Aller au contenu principal
Site en cours de refonte — quelques pages peuvent bouger ou évoluer.
17 avril 2026

Vercel Workflows : enfin un debug de run qui ne finit pas en collage de logs

Le vrai bug en prod, c’est souvent de retrouver les bons logs quand un workflow retry ou time out. Avec le filtre par Run ID et Step ID, tu peux enfin débugger un run proprement.

10 min de lecture
43 vues
réactions
Partager :
Vercel Workflows : enfin un debug de run qui ne finit pas en collage de logs

Quand un Vercel Workflow se met à partir en vrille, le problème n’est pas toujours le code. C’est le temps perdu à recoller des logs qui viennent de plusieurs requêtes, plusieurs steps, plusieurs retries, parfois même plusieurs déploiements. Tu connais le film : tu scrolles, tu filtres au pif, tu copies-colles dans un doc, et tu finis par “croire” que tu as reconstitué l’histoire.

Vercel a ajouté un détail qui a l’air petit, mais qui change vraiment la vie en incident : dans le dashboard Logs, tu peux filtrer par Workflow Run ID et par Workflow Step ID. Dit autrement : tu n’es plus obligé de faire l’archéologue. Tu prends un run, tu le suis, et tu arrives au step qui a cassé. Et si tu logs correctement, tu passes d’un debug flou à un triage quasi mécanique.

Le problème en prod : un workflow qui échoue, et des logs impossibles à corréler

Un workflow, ce n’est pas “une requête”. C’est une exécution qui enchaîne des steps, parfois async, parfois sur des timings bizarres, souvent avec des retries. Et les logs, eux, ont tendance à se retrouver mélangés dans une grande soupe : d’autres requêtes au même moment, d’autres runs, et parfois du bruit applicatif qui n’a rien à voir.

Le pire cas, c’est quand tu as un step qui appelle une API externe. Ça time out une fois sur dix, Vercel retry, ton provider rate-limit, et tu te retrouves avec deux tentatives qui se superposent. Si tu n’as pas un identifiant de corrélation fiable, tu peux très vite “réparer” le mauvais truc. Ou accuser le mauvais service. Ou patcher un symptôme.

Le nouveau filtre Run ID / Step ID : ce que ça débloque concrètement

Ce que Vercel a ajouté est simple : depuis l’UI Workflows, tu passes par « View Logs », puis dans la vue Logs tu peux filtrer par Workflow Run ID et Workflow Step ID. Le bénéfice est immédiat : tu reconstruis la chronologie d’un run sans te battre avec le contexte global.

Sur le terrain, ça sert à trois trucs très concrets. D’abord, isoler une exécution précise quand tu as plusieurs runs similaires (exemple : un job planifié qui se lance toutes les 5 minutes). Ensuite, différencier un échec “première tentative” d’un échec “après retry” sans faire des hypothèses. Enfin, revenir au step fautif sans te laisser hypnotiser par des erreurs secondaires (celles qui arrivent après le vrai crash).

Mais attention : ce filtre ne fait pas de magie si tes logs sont illisibles ou inconsistants. Il te donne un couloir propre. À toi de ne pas le remplir de fumée.

Structurer tes logs pour que le filtrage serve vraiment (et pas juste à scroller plus vite)

Quand tu as un filtre par Run ID et Step ID, tu as déjà une colonne vertébrale. Ce que tu veux ajouter, c’est de la chair utile. Mon biais est assumé : je préfère moins de logs, mais des logs structurés, répétables, et orientés “preuve”.

Dans un workflow, je logge presque toujours en JSON, avec un message humain court, et quelques champs stables : un identifiant métier (commande, facture, import, webhook), un identifiant de tenant si tu es multi-tenant (mais pas un nom de client en clair), et une notion de “phase” (start / success / fail) pour faire une timeline sans réfléchir.

Tu peux aussi te rendre service en normalisant un champ du style op ou action. Le but est bête : quand tu es on-call et fatigué, tu veux pouvoir lire dix lignes et savoir ce qui se passe. Pas te replonger dans le code pour comprendre ce que “entered handler #3” signifie.

// Exemple volontairement simple : log structuré et stable
function log(event: Record<string, unknown>) {
  console.log(JSON.stringify({
    ts: new Date().toISOString(),
    level: event.level ?? "info",
    msg: event.msg,
    op: event.op,
    orderId: event.orderId,
    tenantId: event.tenantId,
    attempt: event.attempt,
    // Jamais de secrets ici.
  }));
}

log({ op: "invoice.generate", msg: "start", orderId: "ord_123", tenantId: "t_42", attempt: 1 });

Un point important : n’essaie pas de “reproduire” le Run ID dans tes logs. Tu l’as déjà via Vercel. Ce que tu veux, c’est le lien vers le monde réel. Le Run ID te dit “quel run”. Ton orderId ou webhookId te dit “pour quel objet métier”. Les deux ensemble, c’est ce qui te permet de répondre à la question qui fait mal : “qu’est-ce qui a été fait, et est-ce que ça a été fait deux fois ?”

Mon protocole de triage : run → step → preuve → fix (sans débat)

Quand ça pète, j’essaie de ne pas partir en exploration. Je prends un incident, je le transforme en run concret, puis je descends. Le filtre par Workflow Run ID te force à être discipliné, et c’est très bien.

Je commence par isoler un run qui correspond au cas utilisateur (ou au timestamp de l’alerte). Je lis la timeline de logs de haut en bas, en cherchant un pattern “start → action → fail”. Quand j’ai l’erreur, je m’interdis de la corriger tout de suite. Je cherche d’abord la preuve : qu’est-ce qui a été tenté, avec quels paramètres, sur quelle ressource externe, et à quel moment ça a divergé.

Ensuite seulement, je passe au filtre par Workflow Step ID. Pourquoi ? Parce qu’en incident, tu as souvent une cascade : un step échoue, et les steps suivants échouent “parce que l’état est mort” (ou parce que la donnée attendue n’existe pas). Si tu fixes un symptôme du step 4 alors que le step 2 était la cause, tu vas perdre une heure et tu vas te sentir idiot après.

Quand tu as la preuve, le fix devient plus simple à choisir. Soit c’est un bug métier. Soit c’est une question de timeouts et de résilience. Soit c’est un problème d’idempotence (mon grand classique sur les workflows qui retry). Et là, tu reviens aux fondamentaux : qu’est-ce qui doit être rejouable sans casse, et qu’est-ce qui doit être “exactly-once” via un verrou applicatif ou une déduplication.

Les pièges classiques en Workflows (ceux qui te font perdre des heures)

Le premier piège, c’est le retry non-idempotent. Tu crées une facture, ça time out après création côté provider, ton code considère que c’est un échec, tu retry… et tu crées une deuxième facture. Avec un filtre par run, tu vas au moins voir les deux tentatives propres. Mais si tu n’as pas de logs qui portent l’ID externe (ou une clé d’idempotence), tu vas rester dans le flou.

Le deuxième piège, c’est la double exécution qui ne ressemble pas à une double exécution. Exemple typique : un événement est traité deux fois (webhook rejoué, message re-deliver), ou un cron se chevauche. Sans corrélation métier dans les logs, tu vas croire à un bug “random”. Avec Run ID + un identifiant métier, tu peux prouver en 30 secondes que ce sont deux runs distincts qui ont touché le même objet.

Le troisième, c’est le logging “verbeux mais inutile”. Beaucoup de gens loggent tout ce qu’ils peuvent, puis ne trouvent plus rien. En workflow, je préfère des logs par étapes métier, pas des logs “par ligne de code”. Si tu logs chaque micro-action, tu vas masquer le signal. Et tu vas payer la facture d’observabilité, aussi.

Le quatrième, et c’est non négociable : les secrets qui fuient. Un workflow manipule souvent des tokens, des payloads, des headers, parfois des PII. Si tu balances des objets entiers en logs “pour debug”, tu vas te fabriquer un incident de sécurité pendant que tu gères un incident de prod. Redaction stricte, et si tu as besoin de prouver un payload, tu logges une version hashée, tronquée, ou un identifiant de message, pas le contenu brut.

Ce que je logge vraiment (et ce que je refuse de logger)

Je logge ce qui permet de reconstituer une exécution et de répondre aux questions “est-ce que ça a été fait ?”, “combien de fois ?”, “où ça a divergé ?”. Concrètement, ça ressemble à des événements start et success autour des actions externes (paiement, email, facture, upload), avec une durée et un identifiant externe quand il existe. Je logge aussi les timeouts et les retries de façon explicite, parce que sinon tu finis par les deviner.

À l’inverse, je ne logge pas les payloads complets, je ne logge pas les tokens, je ne logge pas des objets utilisateurs entiers, et je me méfie des erreurs “verbatim” qui embarquent des données sensibles dans leur message. Le bon compromis, c’est souvent : loggue un ID, un type d’erreur, un code provider, et un hash du contenu si tu dois prouver qu’il y a eu une différence entre deux tentatives.

Support et post-mortem : garder une trace exploitable sans transformer les logs en décharge

Le filtre Run ID / Step ID est aussi un outil de support déguisé. Quand un client te dit “ça a échoué”, tu peux arrêter de jouer au ping-pong. Tu cherches le run, tu identifies le step, tu récupères l’erreur, et tu peux répondre avec quelque chose de factuel. Le gain n’est pas juste technique, il est organisationnel : moins de “je pense que”, plus de “voilà ce qui s’est passé”.

Et si tu fais des post-mortems, c’est le même délire : tu peux pointer un run précis comme artefact, au lieu de coller 40 screenshots de dashboards. Ça n’empêche pas d’avoir des métriques ou du tracing ailleurs. Mais pour le quotidien, ce genre de lien direct vers l’exécution, c’est de la DX qui évite des disputes.

Conclusion : le bon debug, ce n’est pas plus d’outils, c’est moins de friction

Filtrer les logs par Workflow Run ID et Workflow Step ID, ce n’est pas “révolutionnaire”. C’est juste le genre de détail qui te rend du temps quand tu en as le moins. Et si tu en profites pour structurer tes logs avec un minimum de discipline, tu vas aussi améliorer tes retries, ton idempotence, et la qualité de ton support.

La suite logique, si tu veux pousser le curseur, c’est d’arrêter de penser “logs” et de penser “preuve exploitable”. Logs structurés, IDs métier, redaction stricte, et une routine de triage qui commence toujours par un run concret. Le reste, c’est du bruit.

Sources

Cet article vous a plu ?

Commentaires

Laisser un commentaire

Entre 10 et 2000 caractères

Les commentaires sont modérés avant publication.

Aucun commentaire pour le moment.

Soyez le premier à donner votre avis !