Cloudflare Workflows: cuándo conviene migrar cada canal
Cómo migrar rutinas de publicación activadas por agentes a Cloudflare Workflows por canal: costos, límites de V2 e idempotencia que debe preservarse.

Todos los días se activan seis rutinas de publicación del lado de Anthropic y cada una envía un POST a un único PublishWorkflow estático, identificado como publish-{brief_id}. El 1 de mayo, Cloudflare lanzó @cloudflare/dynamic-workflows para Cloudflare Workflows; pocos días después llegó Workflows V2, con un plano de control reconstruido para soportar la carga generada por agentes. Lo interesante no es el lanzamiento en sí, sino que la decisión de concentrarlo todo en un workflow estático —que tomé para garantizar la idempotencia— ahora es una decisión que debo justificar, no una limitación heredada.
Lo que realmente me sorprendió
Esperaba un anuncio del tipo «Workflows ahora escala más». Límites más altos, mayor capacidad en cola, el incremento anual de siempre. Esa terminó siendo la parte menos relevante del anuncio.
La novedad importante es que ahora el código del workflow puede variar para cada tenant en tiempo de ejecución. @cloudflare/dynamic-workflows se lanzó el 1 de mayo con licencia MIT y sobre Dynamic Workers. Permite registrar un único WorkflowEntrypoint cuyo cuerpo se resuelve desde un Dynamic Worker cuando se crea la instancia. Así, el propio grafo de pasos puede adaptarse al tenant en lugar de quedar fijado en el despliegue. Cloudflare lo resume como «ejecución duradera que acompaña al tenant», una descripción muy precisa para quien haya intentado añadir lógica específica por cliente a un solo workflow mediante feature flags.
Mis seis rutinas de publicación —news, dev, build, design, marketing, founders, business— funcionan, en la práctica, como seis tenants que comparten un PublishWorkflow. No son clientes, sino rutinas de IA del lado de Anthropic, cada una dedicada a un canal de contenido distinto. Aun así, el modelo multi-tenant encaja a la perfección: la misma estructura de orquestación, pequeñas variaciones por canal y todo despachado dentro de la misma cuenta de Cloudflare.
Pocos días después llegó Workflows V2, y el enfoque de ese anuncio importa más que las cifras. V2 se rediseñó expresamente bajo la premisa de que las instancias de workflow las crean agentes a velocidad de máquina, no personas que hacen clic en botones. Es exactamente mi patrón de activación. Cuando una rutina editorial decide publicar un artículo, un evento no humano crea una instancia de ejecución duradera; el plano de control de V1 estaba concebido para otro tipo de carga.
Dynamic Workflows: ejecución duradera que acompaña al tenant
Anuncio de Cloudflare sobre @cloudflare/dynamic-workflows, con licencia MIT y construido sobre Dynamic Workers.
Qué implica para un fundador sin perfil técnico
«Ejecución duradera» parece una expresión diseñada para ahuyentar a cualquiera. En términos sencillos, es un trabajo de varios pasos que sobrevive a una caída y continúa desde el último paso completado, en lugar de empezar desde cero. Si el paso 5 de 8 falla porque una API no estaba disponible, el sistema reintenta el paso 5: no vuelve a ejecutar los pasos 1 a 4 ni vuelve a cobrarlos.
Esto es lo que debe importarle a un fundador. El límite de reintento por paso también es el límite de costo por paso. Si el pipeline llama a un modelo de IA de pago en el paso 3 y a otro en el paso 6, pero se cae en el paso 7, conviene reintentar el paso 7, no todo el trabajo. En un pipeline de pago, una nueva ejecución no idempotente no genera solo una fila duplicada en la base de datos: genera una factura duplicada.
La decisión entre construir o posponer cabe en una frase para cualquier contratista: separe los workflows por línea de producto solo cuando la lógica de esas líneas sea realmente distinta, no porque la plataforma ahora lo permita. Cloudflare acaba de presentar una abstracción potente, y es fácil caer en la tentación de rediseñarlo todo a su alrededor. El costo de mantener N definiciones de workflow se multiplica por N, mientras que el beneficio solo aparece si los canales de verdad realizan tareas diferentes. Si alguien propone «dividir cada línea de producto en su propio workflow ahora que podemos hacerlo», la pregunta correcta es qué cambió en el trabajo, no qué cambió en la plataforma.
Así es la arquitectura que uso
Cada rutina de publicación del lado de Anthropic termina su investigación, prepara un brief y envía un POST a /api/admin/publish en el sitio. Ese endpoint valida el payload, genera un ID de instancia y llama a instances.create sobre un único WorkflowEntrypoint llamado PublishWorkflow.
El workflow consta de ocho etapas idempotentes con step.do:
- validate (esquema del brief, unicidad del slug)
- ground (obtención de citas, resolución de enlaces)
- generate (llamada a Claude para generar el contenido)
- clean (validación de directivas Markdown)
- persist (inserción en Postgres, versionado)
- index (embeddings, actualización del buscador)
- cover (generación de imagen + carga en R2)
- publish (cambio de estado, aviso al 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));
}
}El límite de despacho se ve así:
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 lanza una excepción si el ID está duplicado. Esa única línea sostiene buena parte del sistema: es lo único que impide que una rutina de Anthropic reactivada publique dos veces el mismo artículo y me cobre por duplicado las llamadas de IA que hay dentro.
¿Por qué una sola definición para seis canales? Porque las ocho etapas son idénticas en los seis. Lo único que cambia es el paquete editorial: las especificaciones de voz y audiencia, la lista de antipatrones y las indicaciones del brief. Todo eso viaja como datos en tiempo de ejecución dentro del mensaje de despacho, no como código. El nombre del canal determina qué paquete llega al paso 3 (generate); los demás pasos son independientes del canal.
El punto de presión —y la única razón honesta para plantearse siquiera Dynamic Workflows— es que uno de los canales empieza a necesitar un grafo de pasos distinto, no solo otro paquete. El canal con mayor carga de investigación necesita una ronda adicional de grounding antes de generar el contenido y, posiblemente, una etapa de verificación posterior. Es una diferencia estructural, no de datos. Hoy se resuelve con una rama condicional dentro de ground. Funciona, pero es justo el tipo de solución que se deteriora si otros tres canales empiezan a sumar sus propias excepciones.
Cómo planteo la migración a Cloudflare Workflows
Eso es lo que aporta createDynamicWorkflowEntrypoint. El código de workflow de cada canal se carga en tiempo de ejecución desde un Dynamic Worker, por lo que mantener disponibles los canales que no se activaron hoy cuesta casi nada. Se elimina el costo de tener «todos los canales desplegados permanentemente en un solo bundle», y cada canal puede evolucionar sin volver a desplegar la estructura compartida.

El costo real está en lo que el anuncio apenas menciona. Se cambia un WorkflowEntrypoint con comprobación de tipos —donde el compilador avisa si el contrato de entrada de un paso se desvía— por N definiciones cargadas en tiempo de ejecución, sin esa protección. Las diferencias de contrato entre canales pasan de ser errores de compilación a fallos en tiempo de ejecución. Si hay seis canales y el paso persist espera una estructura de fila algo distinta en dos de ellos porque alguien refactorizó la mitad de los canales y olvidó el resto, el problema aparece cuando un artículo real intenta publicarse, no cuando se ejecuta CI.
La migración no tiene por qué ser total, y tratarla así es la vía directa a sobrediseñar el sistema. Este es mi plan:
- Mantener la estructura compartida de 8 etapas como un
WorkflowEntrypointestático. Es la ruta crítica y cinco de los seis canales la usan sin cambios. - Construir el canal intensivo en investigación como un Dynamic Workflow con su propio grafo de pasos (una ronda extra de grounding y una etapa de verificación de datos).
- Despachar según el canal en el límite
/publish: un switch de una sola línea sobrebrief.lanedecide en qué binding llamar acreate.
Cuándo eliminar el código de Cloudflare Workflow: agentes gestionados, resultados y webhooks
La decisión inversa: cuándo Anthropic Managed Agents vuelve redundante el Workflow de CF.
La regla de decisión, con una cifra concreta: migre un canal a su propio Dynamic Workflow solo cuando su grafo difiera de la estructura común en más de una etapa. Por debajo de ese umbral, mantener una rama condicional dentro del paso existente cuesta menos que una segunda definición de workflow. Por encima, la rama empieza a ocultar lo que realmente hace el canal y una definición separada compensa el esfuerzo.
Un canal está por encima del umbral. Cinco están por debajo. Ese es todo el plan de migración en dos frases. Si un contratista me presentara este mismo brief y propusiera dividir los seis canales en Dynamic Workflows desde el primer día, no lo aprobaría. El costo de desarrollo es real y el beneficio se concentra exactamente en un canal.
Qué cambia Workflows V2 con activaciones a velocidad de máquina
Las cifras destacadas de V2 son 50,000 instancias concurrentes y 2,000,000 de instancias en cola por workflow, frente a 1,000,000 en V1. No son cifras decorativas, pero tampoco se acercan a mi escala. Con seis rutinas activándose una o dos veces al día, estoy aproximadamente nueve órdenes de magnitud por debajo del nuevo límite.
Cloudflare Workflows V2: reproducción determinista, 50k instancias concurrentes
Cobertura de InfoQ sobre la nueva arquitectura del plano de control de V2 y sus nuevos límites de concurrencia.
Para mi stack, lo importante no son las cifras, sino que el plano de control de V2 fue reconstruido tomando como caso principal la creación de instancias activada por agentes. V1 estaba optimizado para un patrón humano: una persona hace clic en un botón, se inicia una instancia y el sistema absorbe una carga con picos, pero acotada. V2 asume que quien activa el proceso no es una persona, sino otro proceso, y que la tasa depende del rendimiento de los agentes aguas arriba, no de clics en una interfaz.
Vale la pena explicar la reproducción determinista de V2 en términos sencillos. Cada paso está aislado, puede reproducirse, es idempotente y, ante un reintento, el workflow continúa desde el último paso completado. Esa es exactamente la propiedad que mi ID de instancia publish-{brief_id} protegía manualmente en el límite de despacho. V1 ya ofrecía la garantía de reintento por paso; V2 refuerza la semántica de reproducción, de modo que la propiedad estructural que estaba protegiendo también queda asegurada por la plataforma subyacente.
La medida práctica para esta semana es no tocar la ruta crítica. El modelo de V2 se adopta de forma voluntaria mediante un nuevo despliegue, y lo peor que se puede hacer con un pipeline idempotente que funciona es apresurarse a moverlo a un plano de control nuevo para perseguir una semántica que ya tenía. Pasaré a V2 el canal intensivo en investigación cuando lo construya como Dynamic Workflow, porque estrenar código en el modelo nuevo cuesta poco. Los cinco canales estáticos seguirán donde están hasta que exista una razón para modificarlos que no sea «la plataforma lanzó una nueva versión».
La única propiedad a la que no voy a renunciar
Usar publish-{brief_id} como ID de instancia es esencial. Si se elimina, una rutina de Anthropic puede reintentar desde su lado, volver a activar el pipeline, publicar dos veces el mismo artículo y cobrar por duplicado cada llamada a una API de pago dentro del workflow.
Controles para agentes de IA en producción: cómo limitar el radio de impacto
Los pasos idempotentes son una capa para limitar el impacto. El punto de control del gasto es la otra.
Dynamic Workflows no pone en riesgo esta propiedad de forma directa. El contrato del ID en instances.create no cambia. Lo que sí podría romperlo es una refactorización descuidada por canal, en la que cada canal vuelva a derivar el ID localmente. Por ejemplo, uno podría decidir que incluir una marca de tiempo en el ID es «más seguro», pero eso rompería la deduplicación de manera silenciosa, porque cada reintento generaría un ID único.
La regla que sobrevive a todas las versiones, y que dejaría escrita en la pared antes de permitir que alguien más tocara este código, es esta:
Este tipo de propiedad no aparece en anuncios ni guías de migración, porque solo existe cuando ya se sufrió el fallo que evita. El otro lado del control de costos —garantizar que una ejecución no pueda disparar la factura aunque falle la deduplicación— corresponde a otra capa y se aplica a las llamadas al modelo, no a la instancia. Ambas existen por la misma razón: en un pipeline donde cada paso cuesta dinero, la corrección estructural es el seguro más barato que se puede comprar.
Qué haría distinto si empezara desde cero en mayo de 2026
Si hoy construyera este stack desde cero, en lugar de heredar decisiones de hace un año, cambiaría tres cosas.
Primero, partiría de una estructura estática compartida y añadiría un Dynamic Workflow para cualquier canal que de verdad se aparte del resto, en vez de crear seis definiciones. Cuando llega una abstracción nueva, es tentador aplicarla en todas partes, pero el costo de mantener N workflows aparece antes que la ventaja de escala. Seis definiciones implican seis lugares donde corregir un error, seis lugares donde actualizar una dependencia y seis oportunidades para que se desvíe el contrato de un paso. Una estructura común y una excepción son la separación mínima viable.
Segundo, colocaría la clave de idempotencia en el límite HTTP desde el primer día. Añadir publish-{brief_id} después de un incidente de publicación duplicada es el camino caro: hay que conciliar las filas duplicadas, reembolsar los costos afectados e instrumentar la capa de despacho mientras el sistema ya está en producción. Incorporar el patrón try { create({id}) } catch (dup) {} antes de publicar el primer pipeline toma diez minutos y evita una categoría completa de fallos.
Tercero, trataría el determinismo de Workflows V2 como el punto de partida del diseño, no como una función que se puede adoptar después. Cada paso debe diseñarse para ser seguro ante una reproducción, aunque nunca se alcance el límite de 50k instancias concurrentes. La seguridad ante reproducción no es una propiedad de escala, sino de corrección. Un paso que no la admite falla ante un reintento, y los reintentos ocurren a cualquier escala.
Esa última es una decisión técnica que refleja experiencia. La trampa consiste en tratar las nuevas capacidades de la plataforma como funciones que hay que adoptar. La disciplina consiste en convertirlas en restricciones de diseño, se aproveche o no toda la capacidad disponible.
¿Necesito Dynamic Workflows si todos mis tenants ejecutan la misma lógica?
No. Si el grafo de pasos es idéntico y solo cambian los datos, incluya esos datos en el payload de despacho y mantenga un único workflow estático. Dynamic Workflows justifica su costo cuando el propio código cambia para cada tenant: cuando difiere el grafo de pasos, no solo sus parámetros.
¿Workflows V2 rompe los workflows existentes de V1?
V2 es un plano de control rediseñado para la ejecución determinista activada por agentes. Trate la migración como opcional, valide la idempotencia antes de mover una ruta crítica y no migre código que funciona solo porque existe una versión nueva.
¿Cuál es ahora el límite real de concurrencia?
50,000 instancias concurrentes y 2,000,000 de instancias en cola por workflow, frente a 1,000,000 en cola. Para la mayoría de los operadores, queda muy por encima de su escala; la propiedad más importante de V2 es la reproducción determinista, no el nuevo límite.
¿@cloudflare/dynamic-workflows está listo para producción o sigue en preview?
Se lanzó el 1 de mayo de 2026 como una biblioteca con licencia MIT construida sobre Dynamic Workers. Evalúe la madurez de la biblioteca y su contrato de idempotencia como riesgos determinantes, no la licencia. Si la capa de despacho es sólida, la biblioteca estará lista antes que el plan de migración.
¿Cuándo debería un fundador pagar a un ingeniero por esta migración?
Cuando la lógica de automatización de una línea de producto se aparte realmente de las demás: un grafo de pasos diferente, no parámetros distintos. Dividir solo por escala es prematuro; hacerlo porque la lógica diverge es el verdadero detonante. Si su equipo necesita ayuda para calcular este tipo de migración, ese es precisamente el tipo de revisión arquitectónica que hago a través de DVNC.dev.
4 sept 2026







