Suscríbete para recibir notificaciones de nuevas publicaciones:

Cloudflare Workflows ahora está disponible: ejecución duradera lista para producción

2025-04-07

5 min de lectura
Esta publicación también está disponible en English, 繁體中文, Français, Deutsch, 日本語, 한국어, Nederlands y 简体中文.

Las versiones beta son útiles para retroalimentación e iteraciones, pero no todos están dispuestos a ser conejillos de indias ni a tolerar los inconvenientes ocasionales que vienen con el software en fase beta. A veces necesitas esa etiqueta grande y llamativa que dice "disponible a nivel general" (o la publicación de un blog), y ahora le toca a Workflows.

Workflows, nuestro motor de gestión y coordinación de procesos persistentes sin servidor que te permite crear aplicaciones de ejecución prolongada y en varios pasos (algunos las llaman "funciones de pasos") en Workers, ya está disponible.

En resumen, eso significa que está listo para la producción, pero eso no significa que Workflows vaya a dejar de evolucionar. Seguimos escalando Workflows (se incluyen más instancias simultáneas), incorporamos nuevas funciones (como la nueva API waitForEvent) y facilitamos la creación de agentes de IA con nuestro Agents SDK y Workflows.

Si prefieres el código a la prosa, puedes instalar rápidamente el proyecto de inicio de Workflows y empezar a explorar el código y la API con un solo comando:

npm create cloudflare@latest workflows-starter -- 
--template="cloudflare/workflows-starter"

¿Cómo funciona Workflows? ¿Qué puedo crear con este? ¿Cómo creo agentes de IA con Workflows y Agents SDK? Sigue leyendo.

Desarrollar con Workflows

Workflows es un motor de ejecución duradero integrado en Cloudflare Workers que te permite desarrollar aplicaciones resistentes y en varios pasos.

En esencia, Workflows implementa una arquitectura en pasos donde cada paso de tu aplicación se puede volver a intentar de forma independiente, y el estado persiste automáticamente entre los pasos. Esto significa que incluso si un paso falla debido a un error transitorio o a un problema de red, Workflows puede volver a intentar solo ese paso sin necesidad de reiniciar toda la aplicación desde el principio.

Cuando defines un Workflow divides tu aplicación en pasos lógicos.

  • Cada paso puede ejecutar código (step.do), dejar tu Workflow en suspenso (step.sleep o step.sleepUntil), o esperar un evento (step.waitForEvent).

  • A medida que se ejecuta, tu Workflow conserva automáticamente el estado devuelto de cada paso, lo que garantiza que tu aplicación pueda continuar exactamente donde se dejó, incluso después de fallas o períodos de hibernación. 

  • Este modelo de ejecución duradera es especialmente eficaz para las aplicaciones que se coordinan entre varios sistemas, procesan datos en secuencia o necesitan gestionar tareas de larga duración que pueden durar minutos, horas o incluso días.

Workflows es especialmente útil para gestionar procesos empresariales complejos con los que luchan las funciones sin estado tradicionales.

Por ejemplo, un flujo de trabajo de procesamiento de pedidos de comercio electrónico podría comprobar el inventario, cargar un método de pago, enviar una confirmación por correo electrónico y actualizar una base de datos, todo ello en pasos independientes. Si el paso de procesamiento de pagos falla debido a una interrupción temporal, Workflows volverá a intentar automáticamente ese paso cuando el servicio de pago vuelva a estar disponible, sin duplicar la comprobación de inventario ni reiniciar todo el proceso. 

A continuación, puedes ver cómo funciona: cada llamada a un servicio puede modelarse como un paso, reintentarse de forma independiente y, si es necesario, recuperarse a partir de ese paso:

import { WorkflowEntrypoint, WorkflowStep, WorkflowEvent } from 'cloudflare:workers';

// The params we expect when triggering this Workflow
type OrderParams = {
	orderId: string;
	customerId: string;
	items: Array<{ productId: string; quantity: number }>;
	paymentMethod: {
		type: string;
		id: string;
	};
};

// Our Workflow definition
export class OrderProcessingWorkflow extends WorkflowEntrypoint<Env, OrderParams> {
	async run(event: WorkflowEvent<OrderParams>, step: WorkflowStep) {
		// Step 1: Check inventory
		const inventoryResult = await step.do('check-inventory', async () => {
			console.log(`Checking inventory for order ${event.payload.orderId}`);

			// Mock: In a real workflow, you'd query your inventory system
			const inventoryCheck = await this.env.INVENTORY_SERVICE.checkAvailability(event.payload.items);

			// Return inventory status as state for the next step
			return {
				inStock: true,
				reservationId: 'inv-123456',
				itemsChecked: event.payload.items.length,
			};
		});

		// Exit workflow if items aren't in stock
		if (!inventoryResult.inStock) {
			return { status: 'failed', reason: 'out-of-stock' };
		}

		// Step 2: Process payment
		// Configure specific retry logic for payment processing
		const paymentResult = await step.do(
			'process-payment',
			{
				retries: {
					limit: 3,
					delay: '30 seconds',
					backoff: 'exponential',
				},
				timeout: '2 minutes',
			},
			async () => {
				console.log(`Processing payment for order ${event.payload.orderId}`);

				// Mock: In a real workflow, you'd call your payment processor
				const paymentResponse = await this.env.PAYMENT_SERVICE.processPayment({
					customerId: event.payload.customerId,
					orderId: event.payload.orderId,
					amount: calculateTotal(event.payload.items),
					paymentMethodId: event.payload.paymentMethod.id,
				});

				// If payment failed, throw an error that will trigger retry logic
				if (paymentResponse.status !== 'success') {
					throw new Error(`Payment failed: ${paymentResponse.message}`);
				}

				// Return payment info as state for the next step
				return {
					transactionId: 'txn-789012',
					amount: 129.99,
					timestamp: new Date().toISOString(),
				};
			},
		);

		// Step 3: Send email confirmation
		await step.do('send-confirmation-email', async () => {
			console.log(`Sending confirmation email for order ${event.payload.orderId}`);
			console.log(`Including payment confirmation ${paymentResult.transactionId}`);
			return await this.env.EMAIL_SERVICE.sendOrderConfirmation({ ... })
		});

		// Step 4: Update database
		const dbResult = await step.do('update-database', async () => {
			console.log(`Updating database for order ${event.payload.orderId}`);
			await this.updateOrderStatus(...)

			return { dbUpdated: true };
		});

		// Return final workflow state
		return {
			orderId: event.payload.orderId,
			processedAt: new Date().toISOString(),
		};
	}
}

Esta combinación de durabilidad, reintentos automáticos y persistencia de estado hace que Workflows sea ideal para crear aplicaciones distribuidas confiables que puedan manejar con facilidad fallas del mundo real.

Intervención humana en el proceso

Workflows es solo código, y eso lo hace sumamente potente: puedes definir pasos de forma dinámica y sobre la marcha, bifurcar condicionalmente y hacer llamadas API a cualquier sistema que necesites. Pero a veces también necesitas Workflow para esperar que algo suceda en el mundo real.

Por ejemplo:

  • Aprobación de un humano para avanzar.

  • Un webhook entrante, como un pago de Stripe o un evento de GitHub.

  • Un cambio de estado, como la carga de un archivo en R2 que activa una notificación de evento y luego envía una referencia al archivo a Workflow, para que pueda procesar el archivo (o ejecutarlo a través de un modelo de IA).

La nueva API de WaitForEvent en Workflows te permite hacer precisamente eso: 

let event = await step.waitForEvent<IncomingStripeWebhook>("receive invoice paid webhook from Stripe", { type: "stripe-webhook", timeout: "1 hour" }) 

Luego, puedes enviar un evento a una instancia específica desde cualquier servicio externo que pueda hacer una solicitud HTTP:

curl -d '{"transaction":"complete","id":"1234-6789"}' \
  -H "Authorization: Bearer ${CF_TOKEN}" \
\ "https://api.cloudflare.com/client/v4/accounts/{account_id}/workflows/{workflow_name}/instances/{instance_id}/events/{event_type}"

… o a través de la API de Workers dentro de un mismo Worker:

interface Env {
  MY_WORKFLOW: Workflow;
}

interface Payload {
  transaction: string;
  id: string;
}

export default {
  async fetch(req: Request, env: Env) {
    const instanceId = new URL(req.url).searchParams.get("instanceId")
    const webhookPayload = await req.json<Payload>()

    let instance = await env.MY_WORKFLOW.get(instanceId);
    // Send our event, with `type` matching the event type defined in
    // our step.waitForEvent call
    await instance.sendEvent({type: "stripe-webhook", payload: webhookPayload})
    
    return Response.json({
      status: await instance.status(),
    });
  },
};

Incluso puedes esperar varios eventos, utilizando el parámetro type, y/o ejecutar varios eventos utilizando Promise.race para continuar, según el evento que se haya recibido primero:

export class MyWorkflow extends WorkflowEntrypoint<Env, Params> {
	async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
		let state = await step.do("get some data", () => { /* step call here */ })
		// Race the events, resolving the Promise based on which event
// we receive first
		let value = Promise.race([
step.waitForEvent("payment success", { type: "payment-success-webhook", timeout: "4 hours" ),
step.waitForEvent("payment failure", { type: "payment-failure-webhook", timeout: "4 hours" ),
])
// Continue on based on the value and event received
	}
}

Para visualizar waitForEvent con un poco más de detalle, supongamos que tenemos un Workflow activado por un agente de revisión de código que observa un repositorio de GitHub.

Sin la función de esperar en los eventos, nuestro Workflow no puede obtener fácilmente la aprobación humana para escribir sugerencias (o incluso enviar un RP propio). Potencialmente,podría sondear algún estado que se haya actualizado, pero eso significa que tenemos que llamar a step.sleep durante períodos de tiempo arbitrarios, sondear un servicio de almacenamiento en busca de un valor actualizado y repetir si no está allí. Eso es mucho código y hay margen de error:

Sin waitForEvent, es más difícil enviar datos a una instancia de Workflow que se está ejecutando

Si modificáramos ese mismo ejemplo para incorporar la nueva API waitForEvent, podríamos usarla para esperar la aprobación humana antes de hacer un cambio de mutación: 

Agregamos waitForEvent a nuestro Workflow de revisión de código, para que pueda buscar una aprobación explícita.

Incluso podrían imaginarse a un agente de IA enviando y/o actuando en nombre de un humano aquí: waitForEvent simplemente expone una forma para que Workflow obtenga y se detenga en algo para cambiar antes de que continúe (o no).

Lo más importante es que puedes llamar a waitForEvent como cualquier otro paso en Workflows: puedes llamarlo de forma condicional, varias veces y/o en bucle. Workflows son solo Workers: tienes toda la potencia de un lenguaje de programación y no estás restringido por un lenguaje específico de dominio (DSL) o un lenguaje de configuración.

Precio

Buenas noticias: ¡no hemos cambiado mucho desde el anuncio de la versión beta original! Agregamos precios de almacenamiento para el estado almacenado por tus Workflows, y mantenemos nuestros precios en función de CPU y de las solicitudes (invocación) de la siguiente manera:

Unidad

Workers gratuito

Workers de pago

Tiempo de CPU (ms)

10 ms por Workflow

30 millones de milisegundos de CPU incluidos al mes

+USD 0,02 por millón de milisegundos de CPU adicionales

Solicitudes

100 000 invocaciones de Workflows por día (compartidas con Workers)

10 millones incluidos por mes

+USD 0,30 por millón adicional

Almacenamiento (GB)

1 GB

1 GB incluido por mes + USD 0,20/GB-mes

Como el precio del almacenamiento es nuevo, no facturaremos activamente por el almacenamiento hasta el 15 de septiembre de 2025. Notificaremos a los usuarios que superen el límite de 1 GB incluido antes de cobrar por el almacenamiento y, de forma predeterminada, Workflows caducará el estado almacenado después de tres (3) días (plan gratis) o treinta (30) días (plan de pago).

Si te preguntas qué es el "tiempo de CPU": es el tiempo que tu Workflow consume activamente recursos informáticos. No incluye el tiempo de espera en llamadas a la API, a procesar razonamientos de LLM de ni otras operaciones de entrada/salida (como escribir en una base de datos). Esto puede parecer algo insignificante, pero en la práctica, se suma: la mayoría de las aplicaciones tienen milisegundos de un solo dígito de tiempo de CPU y varios segundos de tiempo real transcurrido: ¡una o dos API que tardan 100-250 ms en responder suma!

Factura por la CPU, no por el tiempo que pasa cuando un Workflow está inactivo o en espera.

Los motores de Workflow, en especial, suelen pasar mucho tiempo esperando: leyendo datos del almacenamiento de objetos (como Cloudflare R2), llamando a API de terceros o LLM como o3-mini o Claude 3.7, incluso consultando bases de datos como D1, Postgres o MySQL. Con Workflows, al igual que Workers, no pagas por el tiempo que tu aplicación simplemente espera.

Comienza a crear

Tienes un buen manejo de Workflows, cómo funciona, y quieres empezar a desarrollar. ¿Y ahora qué?

  1. Consulta la documentación de Workflows para saber cómo funciona, comprender la API de Workflows y conocer las prácticas recomendadas

  2. Revisa el código en el proyecto de inicio

  3. Y, por último, implementa el proyecto de inicio en tu propia cuenta de Cloudflare con solo unos clics:

Implementación en Cloudflare

La conectividad cloud de Cloudflare protege redes corporativas completas, ayuda a los clientes a desarrollar de forma eficiente aplicaciones a escala de Internet, acelera cualquier sitio web o aplicación de Internet, previene contra los ataques DDoS, mantiene a raya a los hackers, y te puede ayudar en tu recorrido hacia la seguridad Zero Trust.

Visita 1.1.1.1 desde cualquier dispositivo para empezar a utilizar nuestra aplicación gratuita y beneficiarte de una navegación más rápida y segura.

Para saber más sobre nuestra misión para ayudar a mejorar Internet, empieza aquí. Si estás buscando un nuevo rumbo profesional, consulta nuestras ofertas de empleo.
Semana del desarrolladorCloudflare Workersde los flujos de trabajoPlataforma para desarrolladores

Síguenos en X

Sid Chatterjee|@chatsidhartha
Matt Silverlock|@elithrar
Cloudflare|@cloudflare

Publicaciones relacionadas