Cloudflare Workflows V2 : le vrai coût d’une migration par pipeline
Cloudflare Workflows V2 change l’exécution pilotée par les agents. Voici quand isoler un pipeline, quoi conserver et comment protéger l’idempotence.

Chaque jour, six routines de publication côté Anthropic se déclenchent chez moi, et toutes envoient une requête POST vers un unique PublishWorkflow statique, identifié par publish-{brief_id}. Le 1er mai, Cloudflare a lancé @cloudflare/dynamic-workflows, puis quelques jours plus tard Cloudflare Workflows V2, avec un plan de contrôle repensé pour la charge générée par des agents. Le plus intéressant n’est pas le lancement. C’est que mon choix d’un workflow statique unique, fait au nom de l’idempotence, devient désormais une décision à défendre au lieu d’une contrainte héritée.
Ce qui m’a surpris
Je m’attendais à une annonce du type « Workflows passe à l’échelle supérieure ». Des plafonds relevés, une file d’attente plus profonde, la hausse annuelle habituelle. Ce n’était que la petite moitié de l’annonce.
La vraie nouveauté, c’est que le code d’un workflow peut désormais varier selon le tenant au moment de l’exécution. Lancé le 1er mai sous licence MIT et construit sur Dynamic Workers, @cloudflare/dynamic-workflows permet d’enregistrer un seul WorkflowEntrypoint dont le corps est résolu depuis un Dynamic Worker à la création de l’instance. Le graphe d’étapes s’adapte donc au tenant au lieu d’être figé dans le déploiement. Cloudflare parle d’une « exécution durable qui suit le tenant » : une formule d’une grande précision dès lors qu’on a déjà tenté de greffer une logique propre à chaque client sur un workflow unique à coups de feature flags.
Mes six routines de publication — news, dev, build, design, marketing, founders et business — fonctionnent comme six tenants réunis dans un même PublishWorkflow. Ce ne sont pas des clients, mais des routines d’IA côté Anthropic, chacune chargée d’un pipeline éditorial différent. Le modèle multitenant leur correspond pourtant parfaitement : même ossature d’orchestration, quelques variations de forme selon le pipeline, le tout envoyé vers le même compte Cloudflare.
Quelques jours plus tard est arrivé Workflows V2, et la manière dont Cloudflare présente cette version compte davantage que les chiffres. V2 a explicitement été réarchitecturé autour d’une idée : les instances de workflow sont créées par des agents à un rythme machine, et non par des humains qui cliquent sur des boutons. C’est exactement mon mode de déclenchement. Lorsqu’une routine décide de publier un article, cet événement non humain crée une instance d’exécution durable ; le plan de contrôle de V1 avait été conçu pour une autre forme de charge.
Dynamic Workflows : l’exécution durable qui suit le tenant
L’annonce de @cloudflare/dynamic-workflows par Cloudflare, une bibliothèque sous licence MIT construite sur Dynamic Workers.
Ce que cela change pour les fondateurs non techniques
« Exécution durable » est le genre d’expression qui semble conçue pour décourager les non-spécialistes. En clair, il s’agit d’une tâche en plusieurs étapes capable de survivre à un plantage et de reprendre à la dernière étape terminée, au lieu de recommencer de zéro. Si l’étape 5 sur 8 échoue parce qu’une API était indisponible, le système relance l’étape 5 : il ne rejoue pas les étapes 1 à 4 et ne vous les facture pas une seconde fois.
C’est ce qui doit retenir l’attention d’un fondateur. La frontière de reprise par étape est aussi la frontière de coût. Si votre pipeline appelle un modèle d’IA payant à l’étape 3, puis un autre à l’étape 6, et que l’étape 7 plante, vous voulez relancer l’étape 7 — pas toute la tâche. Dans un pipeline payant, une réexécution non idempotente ne produit pas simplement une ligne en double dans une base de données. Elle produit une facture en double.
Voici la règle de décision que vous pouvez transmettre à un prestataire en une phrase : ne séparez les workflows par ligne de produit que lorsque leur logique diverge réellement, pas simplement parce que la plateforme le permet désormais. Cloudflare vient de livrer une abstraction puissante, et ce genre de nouveauté donne vite envie de tout repenser autour d’elle. Or N définitions de workflow représentent N fois plus de maintenance, sans bénéfice réel tant que les pipelines n’effectuent pas des tâches véritablement différentes. À la proposition « nous devrions maintenant créer un workflow par ligne de produit », un fondateur doit demander ce qui a changé dans le travail, pas dans la plateforme.
L’architecture que j’utilise réellement
L’ensemble reste assez compact pour être compris d’un coup d’œil. Chaque routine de publication côté Anthropic termine ses recherches, prépare un brief, puis envoie une requête POST à /api/admin/publish sur le site. Cet endpoint valide le payload, génère un identifiant d’instance et appelle instances.create sur un unique WorkflowEntrypoint nommé PublishWorkflow.
Le workflow se compose de huit étapes step.do idempotentes :
- validate (schéma du brief, unicité du slug)
- ground (récupération des citations, résolution des liens)
- generate (appel à Claude pour produire le corps de l’article)
- clean (validation des directives markdown)
- persist (insertion dans Postgres, gestion des versions)
- index (embeddings, actualisation de la recherche)
- cover (génération de l’image + téléversement vers R2)
- publish (changement de statut, ping du sitemap)
export class PublishWorkflow extends WorkflowEntrypoint<Env, PublishParams> {
async run(event: WorkflowEvent<PublishParams>, step: WorkflowStep) {
const brief = await step.do("validate", () => validateBrief(event.payload));
const grounded = await step.do("ground", () => groundCitations(brief));
const draft = await step.do("generate", () => generateBody(grounded));
const cleaned = await step.do("clean", () => validateDirectives(draft));
const row = await step.do("persist", () => persistArticle(cleaned));
await step.do("index", () => reindex(row.id));
await step.do("cover", () => generateCover(row.id));
await step.do("publish", () => flipStatus(row.id));
}
}La frontière de dispatch ressemble à ceci :
const id = `publish-${brief.brief_id}`;
try {
await env.PUBLISH.create({ id, params: brief });
} catch (e) {
if (isDuplicateIdError(e)) return new Response("already queued", { status: 200 });
throw e;
}instances.create lève une exception si l’identifiant existe déjà. Cette seule ligne assume une responsabilité considérable : elle empêche une routine Anthropic relancée de publier deux fois le même article et de me facturer deux fois les appels d’IA exécutés à l’intérieur.
Pourquoi une seule définition pour six pipelines ? Parce que les huit étapes sont identiques dans les six cas. Seul le bundle éditorial varie : les consignes de ton et de lectorat, la liste des anti-patterns et les indications du brief. Ces éléments circulent sous forme de données d’exécution dans l’enveloppe de dispatch, pas sous forme de code. Le nom du pipeline détermine le bundle transmis à l’étape 3 (generate) ; toutes les autres étapes sont indépendantes du pipeline.
Le point de tension — et la seule raison sincère de se pencher sur Dynamic Workflows — tient à ce qu’un pipeline commence à réclamer un graphe d’étapes différent, pas seulement un autre bundle. Le pipeline le plus axé sur la recherche a besoin d’une passe de documentation supplémentaire avant la génération, et peut-être d’une étape de fact-checking après. Il s’agit d’une différence structurelle, pas d’une différence de données. Pour l’instant, cette variante prend la forme d’une branche conditionnelle dans ground. Cela fonctionne, mais ce type de solution finit par pourrir si trois autres pipelines ajoutent à leur tour leurs propres cas particuliers.
Migrer vers Dynamic Workflows : le coût réel
Voilà ce que permet createDynamicWorkflowEntrypoint. Le code propre à chaque pipeline est chargé à l’exécution depuis un Dynamic Worker ; conserver les pipelines inactifs de la journée ne coûte donc presque rien. On cesse de payer la taxe de maintenance liée au fait d’avoir « tous les pipelines déployés en permanence dans un même bundle », et le code de chacun peut évoluer séparément sans redéployer l’ossature commune.

Le vrai coût est celui sur lequel l’annonce s’attarde peu. On échange un WorkflowEntrypoint vérifié par les types — où le compilateur signale toute dérive du contrat d’entrée d’une étape — contre N définitions chargées à l’exécution, sans ce filet. La dérive des contrats d’étape entre pipelines devient une erreur d’exécution plutôt qu’une erreur de build. Avec six pipelines, si l’étape persist attend une structure de ligne légèrement différente dans deux d’entre eux parce qu’une refactorisation n’a touché que la moitié du code, vous le découvrez lorsqu’un véritable article tente d’être publié, pas pendant la CI.
La migration n’a rien d’un choix binaire ; prétendre le contraire est le meilleur moyen de surconcevoir le système. Voici mon plan :
- Conserver l’ossature commune en 8 étapes sous forme de
WorkflowEntrypointstatique. C’est le chemin critique. Cinq des six pipelines l’utilisent sans modification. - Construire le pipeline axé sur la recherche comme un Dynamic Workflow doté de son propre graphe d’étapes (passe de documentation supplémentaire, étape de fact-checking).
- Router selon le pipeline à la frontière
/publish: un switch d’une ligne surbrief.lanechoisit le binding sur lequel appelercreate.
Quand supprimer le code Cloudflare Workflow : agents managés, résultats et webhooks
La décision inverse : à quel moment Anthropic Managed Agents rend votre Cloudflare Workflow superflu.
La règle de décision, cette fois assortie d’un chiffre : ne migrez un pipeline vers son propre Dynamic Workflow que si son graphe s’écarte de l’ossature de plus d’une étape. En dessous de ce seuil, une branche conditionnelle dans l’étape existante coûte moins cher à maintenir qu’une seconde définition de workflow. Au-delà, la branche masque progressivement ce que fait réellement le pipeline, et une définition séparée devient rentable.
Un pipeline dépasse le seuil. Les cinq autres restent en dessous. Voilà le plan de migration en deux phrases. Si un prestataire me proposait, à partir du même brief, de scinder les six pipelines en Dynamic Workflows dès le premier jour, je refuserais. Le coût de développement est réel, alors que le bénéfice se concentre sur un seul pipeline.
Ce que Cloudflare Workflows V2 change pour les déclenchements automatisés
Les chiffres mis en avant pour V2 sont les suivants : 50,000 instances simultanées et 2,000,000 instances en file d’attente par workflow, contre 1,000,000 en file d’attente dans V1. Ils ne sont pas là pour faire joli, mais ils se situent aussi très loin de mon usage. Avec six routines déclenchées une ou deux fois par jour, je reste environ neuf ordres de grandeur sous le nouveau plafond.
Cloudflare Workflows V2 : replay déterministe et 50k instances simultanées
L’analyse par InfoQ de la réarchitecture du plan de contrôle de V2 et de ses nouvelles limites de concurrence.
Pour ma stack, l’essentiel n’est pas dans les chiffres. Il tient au fait que le plan de contrôle de V2 a été reconstruit autour de la création d’instances par des agents comme scénario principal. V1 était optimisé pour un déclenchement humain : un utilisateur clique sur un bouton, une instance démarre, puis le système absorbe une charge en rafales mais bornée. V2 suppose au contraire que le déclencheur est un processus, pas une personne, et que le rythme dépend du débit des agents en amont plutôt que des clics dans une interface.
Le replay déterministe est la propriété de V2 qui mérite une explication simple. Chaque étape est isolée, rejouable et idempotente ; en cas de nouvelle tentative, le workflow reprend à la dernière étape réussie. C’est précisément ce que mon identifiant d’instance publish-{brief_id} protégeait manuellement à la frontière de dispatch. V1 m’apportait déjà la garantie de reprise par étape ; V2 renforce la sémantique de replay, si bien que la propriété structurelle que je préservais est aussi appliquée par la plateforme sous-jacente.
Cette semaine, la décision pratique est simple : ne rien changer sur le chemin critique. Le modèle V2 s’adopte lors d’un nouveau déploiement, et rien n’est plus risqué que de précipiter la migration d’un pipeline idempotent qui fonctionne vers un nouveau plan de contrôle pour courir après des garanties qu’il possédait déjà. Je passerai le pipeline axé sur la recherche à V2 lorsque je le construirai sous forme de Dynamic Workflow, car démarrer du nouveau code sur le nouveau modèle coûte peu. Les cinq pipelines statiques resteront en place jusqu’à ce qu’une autre raison que « la plateforme vient de sortir une nouvelle version » justifie d’y toucher.
L’invariant auquel je ne renoncerai pas
L’identifiant d’instance publish-{brief_id} est structurel. Supprimez-le, et le pipeline se relance dès qu’une routine Anthropic réessaie de son côté, publie deux fois le même article et facture en double chaque appel d’API payant contenu dans le workflow.
Garde-fous des agents d’IA en production : limiter le rayon d’impact
Les étapes idempotentes forment une couche de protection. Le verrou de coût en est une autre.
Dynamic Workflows ne menace pas directement cet invariant. Le contrat d’identifiant de instances.create reste inchangé. Le danger viendrait plutôt d’une refactorisation bâclée par pipeline, dans laquelle chaque code local recommencerait à calculer l’identifiant — par exemple un pipeline qui voudrait y ajouter un timestamp « par sécurité ». La déduplication serait alors silencieusement cassée, puisque chaque nouvelle tentative produirait un identifiant unique.
La règle qui doit survivre à chaque changement de version — celle que j’afficherais au mur avant de laisser quiconque toucher à ce code — tient en quelques mots :
Ce genre d’invariant ne figure ni dans une annonce ni dans un guide de migration, car il n’existe qu’après avoir subi l’incident qu’il évite. L’autre volet du verrou de coût — empêcher qu’une seule exécution de workflow entraîne une facture incontrôlable même en cas d’échec de la déduplication — forme une couche distincte, au niveau des appels aux modèles plutôt qu’à celui des instances. Les deux répondent à la même logique : dans un pipeline où chaque étape coûte de l’argent, la correction structurelle reste l’assurance la moins chère qui soit.
Ce que je ferais autrement en repartant de zéro en mai 2026
Si je construisais cette stack aujourd’hui au lieu d’hériter de décisions prises il y a un an, je changerais trois choses.
D’abord, je partirais d’une ossature statique commune et d’un Dynamic Workflow pour chaque pipeline réellement divergent, plutôt que de créer six définitions distinctes. À l’arrivée d’une nouvelle abstraction, la tentation consiste à l’appliquer partout ; mais la taxe de maintenance de N définitions de workflow précède le bénéfice lié au passage à l’échelle. Six définitions, ce sont six endroits où corriger un bug, six endroits où mettre à niveau une dépendance et six endroits où le contrat d’une étape peut dériver. Une ossature et une exception constituent la séparation minimale viable.
Ensuite, je placerais la clé d’idempotence à la frontière HTTP dès le premier jour. Ajouter publish-{brief_id} après un incident de double publication est la voie coûteuse : il faut réconcilier les lignes publiées deux fois, rembourser les coûts concernés et instrumenter la couche de dispatch alors que le système est déjà en production. Installer le pattern try { create({id}) } catch (dup) {} avant même la première mise en production prend dix minutes et élimine toute une catégorie de défaillances.
Enfin, je considérerais le déterminisme de Workflows V2 comme le socle de la conception, pas comme une fonctionnalité à activer plus tard. Chaque étape doit être conçue pour supporter le replay, même si le système n’atteint jamais le plafond de 50k exécutions simultanées. La sûreté du replay n’est pas une propriété de mise à l’échelle, mais une propriété de correction. Une étape qui ne supporte pas le replay casse lors d’une nouvelle tentative, quel que soit le volume.
C’est le choix d’un ingénieur expérimenté sous l’apparence d’une décision technique. Le piège consiste à traiter les nouvelles capacités d’une plateforme comme des fonctionnalités à adopter. La discipline consiste à les considérer comme des contraintes de conception, que l’on exploite ou non toute la marge offerte.
Ai-je besoin de Dynamic Workflows si tous mes tenants exécutent la même logique ?
Non. Si le graphe d’étapes est identique et que seules les données changent, transmettez ces données dans le payload de dispatch et conservez un workflow statique unique. Dynamic Workflows se justifie lorsque le code lui-même diverge selon le tenant — quand le graphe d’étapes change, pas seulement ses paramètres.
Workflows V2 casse-t-il les workflows V1 existants ?
V2 repose sur un plan de contrôle réarchitecturé autour d’une exécution déterministe déclenchée par des agents. Traitez la migration comme une démarche volontaire, validez l’idempotence avant de déplacer un chemin critique et ne migrez pas du code opérationnel au seul motif qu’une nouvelle version existe.
Quel est désormais le plafond réel de concurrence ?
50,000 instances simultanées et 2,000,000 instances en file d’attente par workflow, contre 1,000,000 auparavant. Pour la plupart des opérateurs, ces limites dépassent largement les besoins ; la propriété la plus importante de V2 reste le replay déterministe, pas le nouveau plafond.
@cloudflare/dynamic-workflows est-il prêt pour la production ou encore en preview ?
La bibliothèque est sortie le 1er mai 2026 sous licence MIT et repose sur Dynamic Workers. Évaluez d’abord sa maturité et votre contrat d’idempotence, pas sa licence. Si votre couche de dispatch est solide, la bibliothèque sera prête avant votre plan de migration.
Quand un fondateur doit-il payer un ingénieur pour cette migration ?
Lorsque la logique d’automatisation d’une ligne de produit diverge réellement des autres : un graphe d’étapes différent, pas de simples paramètres différents. Scinder uniquement pour le passage à l’échelle est prématuré ; scinder parce que la logique diverge est le véritable déclencheur. Si votre équipe a besoin d’aide pour arbitrer ce genre de migration, c’est précisément le type de revue d’architecture que je propose via DVNC.dev.
4 sept. 2026







