Next.js SaaS
Exécuter des tâches en arrière-plan et des webhooks fiables dans un SaaS Next.js
Concevez des tâches durables, des webhooks vérifiés, des nouvelles tentatives, l’idempotence, des délais limites, des états d’échec et des tâches en arrière-plan observables autour d’un SaaS Next.js.
Une requête convient mal aux tâches qui prennent des minutes, dépendent d’un prestataire peu fiable ou doivent survivre au redémarrage du processus. L’état durable doit vivre plus longtemps que la requête.
Repérer les tâches à sortir de la requête
Placez les imports, exports, rapports, traitements de médias, e-mails en masse, synchronisations de prestataires et autres tâches lentes derrière un mécanisme de tâche durable. La requête doit valider l’intention, enregistrer la tâche et renvoyer un identifiant permettant à l’interface d’afficher sa progression.
Toutes les tâches asynchrones n’exigent pas un service distinct dès le premier jour. Elles nécessitent un état durable, un responsable, un contrat d’exécution et un moyen de reprise. Une promesse non attendue dans un Route Handler peut disparaître à l’arrêt du processus, sans laisser de trace fiable pour l’utilisateur.
Modéliser le cycle de vie d’une tâche
Enregistrez un identifiant stable, un type, un propriétaire, une référence aux entrées validées, un statut, un nombre de tentatives, la prochaine date d’exécution, une référence au résultat et une erreur nettoyée des données sensibles. Utilisez des états tels que queued, running, succeeded, failed et canceled. Un bail ou un signal de présence empêche deux workers de s’attribuer discrètement la même tentative indéfiniment.
Stockez les données volumineuses et les résultats hors de l’enregistrement de file si nécessaire. La tâche doit référencer des objets durables et relire les autorisations ou la propriété actuelles avant de publier un résultat.
type JobState =
| "queued"
| "running"
| "succeeded"
| "failed"
| "canceled";
type Job = {
id: string;
tenantId: string;
type: string;
state: JobState;
attempts: number;
runAfter: Date;
};Rendre l’exécution idempotente
Un worker peut s’arrêter après la réussite d’une action externe, mais avant l’enregistrement local du succès. Concevez chaque étape pour pouvoir la répéter sans risque. Utilisez des clés métier uniques, des clés d’idempotence du prestataire, des upserts et des points de contrôle enregistrés plutôt que de supposer une livraison exactement une fois.
Distinguez l’identité de la tâche de celle d’une tentative. Les nouvelles tentatives doivent concerner la même tâche métier tout en laissant des traces distinctes. L’interface peut ainsi expliquer ce qui s’est passé sans créer plusieurs exports ou e-mails impossibles à distinguer.
Limiter les nouvelles tentatives et les appels externes
Imposez des délais limites de connexion et de réponse aux prestataires. Retentez les dépassements de délai transitoires, les limitations de débit et les pannes temporaires avec des délais progressifs et aléatoires. Ne retentez pas indéfiniment une entrée invalide, une autorisation révoquée ou un refus permanent du prestataire.
Une fois le budget de tentatives épuisé, placez la tâche dans un état d’échec visible et déclenchez une alerte selon son importance. Gardez assez de contexte pour agir sans journaliser les identifiants ni les données privées.
- —Classez les erreurs avant de réessayer.
- —Limitez le nombre de tentatives et le temps total écoulé.
- —Répartissez les nouvelles tentatives avec une variation aléatoire.
- —Ne proposez une nouvelle tentative manuelle que si l’opération peut être répétée sans risque.
Sécuriser les webhooks entrants
Recevez les événements du prestataire dans un Route Handler, vérifiez la signature sur le corps brut, rejetez les requêtes invalides ou trop anciennes selon son protocole et enregistrez l’identifiant d’événement avant toute opération coûteuse. Renvoyez rapidement un succès une fois le travail enregistré durablement.
Utilisez une contrainte d’unicité pour dédupliquer les livraisons. Associez l’événement du prestataire à un tenant ou compte local avec des métadonnées fiables ou des identifiants de prestataire enregistrés, et non un champ tenant arbitraire des données reçues.
Montrer aux utilisateurs la progression réelle
Une tâche soumise n’est pas terminée. Renvoyez son identifiant et affichez son état en file d’attente ou en cours dans l’application. Actualisez avec la navigation serveur, des interrogations périodiques ou un canal temps réel adapté au produit. Rendez les échecs et annulations visibles au lieu de laisser un indicateur de chargement indéfiniment.
Protégez les téléchargements des résultats avec les mêmes contrôles de propriété que la requête initiale. Faites expirer les fichiers générés si nécessaire et séparez les explications destinées aux utilisateurs des détails d’erreur internes.
Tester l’interruption et la livraison en double
Arrêtez un worker au milieu d’une étape, relancez-le, livrez deux fois le même webhook, retardez un prestataire au-delà du délai limite, épuisez les tentatives et retirez l’accès d’un utilisateur avant la fin. Confirmez que l’opération reste sûre et que son état final est compréhensible.
Testez un déploiement pendant l’exécution des tâches. Les workers doivent terminer, libérer ou retenter sans risque le travail sous bail selon la conception. Les migrations doivent rester compatibles avec les tâches en attente créées par la version précédente.
Exploiter les tâches et workflows avec l’application
Adios peut exécuter des processus applicatifs persistants et des workflows inspectables avec déclencheurs, étapes, attentes, approbations et historique d’exécution. Concentrez le parcours des requêtes Next.js sur la validation et l’enregistrement durable du travail, puis laissez le worker ou le workflow gérer l’exécution qui peut être retentée.
Déployez la configuration et les références aux secrets près du code source, consultez séparément les journaux applicatifs et de workflow, et utilisez des contrôles de santé pour les services recevant du trafic. La version visible par les clients reste stable, tandis que les échecs en arrière-plan conservent leurs diagnostics et leurs moyens de reprise.
env:
DATABASE_URL: secret://DATABASE_URL
EMAIL_API_KEY: secret://EMAIL_API_KEY
runtime:
name: node@24
port: 3000
health_path: /api/health