Lección 3 de 311 min
Orquestación de workflows: AWS Step Functions
Máquinas de estados para coordinar pasos, reintentos y ramas sin escribir el pegamento a mano.
Procesar un pedido son varios pasos: comprobar el stock, cobrar, preparar el envío y avisar al cliente. Cada uno lo hace un servicio distinto y cualquiera puede fallar. Si el cobro va bien pero no queda stock, hay que devolver el dinero; si la pasarela de pago tarda, hay que reintentar, pero no para siempre.
Ese «pegamento» entre pasos (qué va después de qué, qué se reintenta, qué se deshace) puede acabar repartido por todo tu código. En esta lección verás las dos grandes formas de coordinar procesos de varios pasos y cómo AWS Step Functions te deja describir el flujo completo como una máquina de estados, con reintentos y manejo de errores incluidos.
Orquestación y coreografía
Piensa en una orquesta con director frente a un grupo de baile que se sabe la coreografía: en el primer caso alguien da cada entrada; en el segundo, cada bailarín reacciona a lo que hacen los demás.
Orquestación
Un coordinador central dice a cada servicio qué hacer y cuándo.
En la orquestación hay un orquestador que conoce el proceso completo. Llama al servicio de pagos, espera su respuesta, decide el siguiente paso y, si algo falla, ejecuta las compensaciones (por ejemplo, el reembolso). Los servicios no se conocen entre sí: solo responden al orquestador.
La gran ventaja es la visibilidad: en un único sitio puedes ver en qué paso está cada pedido, por qué falló y qué se reintentó. Cambiar el orden de los pasos es cambiar una definición, no tocar varios servicios.
Úsalo cuando
Para procesos con un orden claro, ramas, plazos y compensaciones, donde necesitas saber en todo momento en qué punto está cada caso.
Ten en cuenta
El orquestador concentra la lógica del proceso: si crece sin control, se convierte en un monolito de reglas de negocio. Y es una pieza crítica, así que conviene que sea un servicio gestionado y fiable.
Orquestador → Almacén: «¿hay stock del pedido 42?»
← Almacén: «sí»
→ Pagos: «cobra 50 €»
← Pagos: «error temporal» … reintento … «cobrado»
→ Envíos: «prepara el paquete»
← Envíos: «listo» → pedido completadoCoreografía
Sin coordinador: cada servicio reacciona a eventos y publica los suyos.
En la coreografía nadie dirige. El servicio de pedidos publica «pedido creado»; el de pagos lo escucha, cobra y publica «pago cobrado»; el almacén escucha ese evento y prepara el envío. Es la mensajería pub/sub que viste en la lección anterior aplicada a un proceso de negocio.
Los servicios quedan muy desacoplados: añadir uno nuevo que reaccione a «pago cobrado» no obliga a tocar a nadie. El precio es que el proceso completo no está escrito en ningún sitio: hay que reconstruirlo siguiendo eventos, algo que verás con las trazas distribuidas en el módulo de observabilidad.
Úsalo cuando
Cuando cada equipo es dueño de su servicio, los pasos son pocos e independientes, y te importa más poder añadir reacciones nuevas que controlar el flujo de punta a punta.
Ten en cuenta
Con muchos pasos y compensaciones, la coreografía se vuelve difícil de seguir: ¿quién reembolsa si el almacén falla? Las dos formas sirven para montar una saga, el patrón de pasos con compensación que verás en el módulo de arquitectura.
Pedidos publica «PedidoCreado» → lo escucha Pagos
Pagos publica «PagoCobrado» → lo escuchan Almacén y Correo
Almacén publica «SinStock» → lo escucha Pagos, que reembolsaAWS Step Functions
AWS Step Functions
Un orquestador gestionado: describes el flujo como una máquina de estados en JSON.
- Lenguaje:
- Amazon States Language
- Formato:
- JSON
Step Functions es el servicio de orquestación de AWS. Defines una máquina de estados en Amazon States Language (ASL), un formato JSON en el que cada paso es un estado con un tipo, y AWS se encarga de ejecutarla, guardar el progreso, reintentar y registrar el historial. La consola la dibuja como un diagrama y Workflow Studio te deja editarla visualmente.
Cada ejecución recibe un JSON de entrada que pasa de estado en estado. Los estados Task pueden invocar funciones Lambda o llamar directamente a muchos servicios de AWS (DynamoDB, SQS, SNS…) sin escribir código intermedio. Para elegir y transformar datos se usan expresiones JSONPath como $.pedidoId; en las versiones recientes también puedes usar JSONata y variables.
Úsalo cuando
Para procesos de varios pasos en AWS que necesitan reintentos, ramas, esperas o compensaciones: pedidos, altas de clientes, pipelines de datos, procesos con aprobación humana.
Ten en cuenta
La definición es JSON y crece rápido: guárdala en el repositorio y despliégala con infraestructura como código. Y no metas datos grandes en el estado: hay un límite de tamaño, así que pasa referencias (un id, una ruta de S3) en lugar del contenido.
{
"Comment": "Procesar un pedido",
"StartAt": "ComprobarStock",
"States": {
"ComprobarStock": {
"Type": "Task",
"Resource": "arn:aws:lambda:…:function:comprobar-stock",
"Next": "HayStock"
},
"HayStock": {
"Type": "Choice",
"Choices": [{ "Variable": "$.hayStock", "BooleanEquals": true, "Next": "CobrarPago" }],
"Default": "SinStock"
},
"CobrarPago": {
"Type": "Task",
"Resource": "arn:aws:lambda:…:function:cobrar-pago",
"Retry": [{ "ErrorEquals": ["PasarelaOcupada"], "MaxAttempts": 3, "BackoffRate": 2 }],
"Catch": [{ "ErrorEquals": ["States.ALL"], "Next": "PagoRechazado" }],
"Next": "PrepararEnvio"
},
"PrepararEnvio": { "Type": "Task", "Resource": "arn:aws:lambda:…:function:preparar-envio", "End": true },
"SinStock": { "Type": "Fail", "Error": "SinStock", "Cause": "No quedan unidades" },
"PagoRechazado": { "Type": "Fail", "Error": "PagoRechazado" }
}
}Los tipos de estado
Cada estado de la máquina tiene un Type. Con estos pocos tipos se describe casi cualquier proceso; en el ejemplo anterior ya aparecen Task, Choice y Fail.
Task
El estado que hace el trabajo: invoca una Lambda o llama a un servicio de AWS.
Un Task ejecuta una unidad de trabajo indicada en Resource: una función Lambda, una llamada directa a un servicio de AWS o incluso una API HTTP externa. Su resultado se combina con la entrada y pasa al estado siguiente.
Además de la llamada simple, admite patrones para esperar trabajos largos: con .sync espera a que termine, por ejemplo, un trabajo de AWS Batch, y con .waitForTaskToken se queda en pausa hasta que alguien devuelva un token, útil para una aprobación humana.
Úsalo cuando
En cada paso que tenga que hacer algo: cobrar, guardar, enviar, transformar.
Ten en cuenta
Pon TimeoutSeconds en los Task que llaman a sistemas externos. Sin él, una llamada que nunca responde puede dejar la ejecución esperando mucho más de lo que imaginas.
"GuardarPedido": {
"Type": "Task",
"Resource": "arn:aws:states:::dynamodb:putItem",
"Parameters": {
"TableName": "pedidos",
"Item": { "id": { "S.$": "$.pedidoId" }, "estado": { "S": "pagado" } }
},
"TimeoutSeconds": 10,
"Next": "AvisarCliente"
}Choice
Una bifurcación: elige el siguiente estado según los datos.
Un Choice evalúa sus reglas en orden y sigue la primera que se cumple; si ninguna se cumple, va a Default. Las reglas comparan valores de la entrada: números, textos, booleanos o fechas, y se pueden combinar con And, Or y Not.
Úsalo cuando
Cuando el camino depende de los datos: pedidos grandes que requieren revisión, clientes de otro país, un pago aceptado o rechazado.
Ten en cuenta
Define siempre un Default. Si ninguna regla coincide y no lo hay, la ejecución falla con un error difícil de entender.
"RevisarPedido": {
"Type": "Choice",
"Choices": [
{ "Variable": "$.importe", "NumericGreaterThan": 1000, "Next": "RevisionManual" },
{ "Variable": "$.pais", "StringEquals": "MX", "Next": "EnvioNacional" }
],
"Default": "EnvioInternacional"
}Parallel
Ejecuta varias ramas a la vez y continúa cuando terminan todas.
Un Parallel contiene varias ramas, cada una con su propia mini máquina de estados. Todas reciben la misma entrada y se ejecutan simultáneamente; la salida es una lista con el resultado de cada rama, en el mismo orden.
Si una rama falla y nadie captura el error, el Parallel entero falla y se detienen las demás.
Úsalo cuando
Para pasos independientes entre sí que no conviene hacer uno detrás de otro: emitir la factura y avisar al almacén a la vez.
Ten en cuenta
Las ramas son fijas y las escribes tú. Si el número de tareas depende de los datos (una por cada línea del pedido), lo que necesitas es Map.
"FacturarYAvisar": {
"Type": "Parallel",
"Branches": [
{ "StartAt": "Facturar", "States": { "Facturar": { "Type": "Task", "Resource": "arn:aws:lambda:…:function:facturar", "End": true } } },
{ "StartAt": "Avisar", "States": { "Avisar": { "Type": "Task", "Resource": "arn:aws:lambda:…:function:avisar-almacen", "End": true } } }
],
"Next": "Completado"
}Map
Repite los mismos pasos para cada elemento de una lista.
Un Map recorre una lista de la entrada y ejecuta para cada elemento los estados de su ItemProcessor, con MaxConcurrency para limitar cuántos van a la vez. Es el forEach de Step Functions.
En modo inline, las iteraciones viven dentro de la misma ejecución. En modo distributed, cada iteración es una ejecución hija, pensada para procesar grandes volúmenes, como los millones de líneas de un archivo en S3.
Úsalo cuando
Cuando el número de tareas depende de los datos: reservar cada artículo del pedido, procesar cada fila de un CSV, redimensionar cada imagen de un álbum.
Ten en cuenta
Sin MaxConcurrency, un Map con miles de elementos puede lanzar demasiadas llamadas a la vez y saturar el servicio que hay detrás.
"ReservarLineas": {
"Type": "Map",
"ItemsPath": "$.lineas",
"MaxConcurrency": 5,
"ItemProcessor": {
"StartAt": "Reservar",
"States": { "Reservar": { "Type": "Task", "Resource": "arn:aws:lambda:…:function:reservar", "End": true } }
},
"Next": "CobrarPago"
}Wait
Pausa la ejecución un tiempo o hasta una fecha, sin gastar recursos.
Un Wait detiene la ejecución durante unos segundos (Seconds) o hasta un instante concreto (Timestamp), que también puede venir de la entrada con SecondsPath o TimestampPath. Mientras espera no hay ningún proceso tuyo encendido.
Úsalo cuando
Para recordatorios y plazos: escribir al cliente tres días después del alta, pedir una valoración el día después de la entrega.
Ten en cuenta
Las esperas largas solo tienen sentido en los workflows Standard: un Express dura como mucho cinco minutos en total.
"EsperarTresDias": {
"Type": "Wait",
"Seconds": 259200,
"Next": "EnviarRecordatorio"
}Pass, Succeed y Fail
Estados auxiliares: pasar datos, terminar bien o terminar con error.
Pass no hace trabajo: pasa su entrada a la salida y, opcionalmente, añade datos fijos. Sirve para valores por defecto o para dibujar un flujo antes de implementar sus pasos. Succeed termina la ejecución con éxito y Fail la termina con un error y una causa que quedan registrados en el historial.
Úsalo cuando
Pass para preparar datos o maquetar; Succeed y Fail para dejar claro cómo acaba cada camino del flujo.
Ten en cuenta
Un Fail termina la ejecución entera, también desde dentro de una rama de Parallel si nadie captura el error. Si quieres que el flujo siga tras un error, captúralo con Catch en lugar de ir a un Fail.
"ValoresPorDefecto": { "Type": "Pass", "Result": { "moneda": "MXN" }, "ResultPath": "$.config", "Next": "Cobrar" },
"Completado": { "Type": "Succeed" },
"PagoRechazado": { "Type": "Fail", "Error": "PagoRechazado", "Cause": "La pasarela rechazó la tarjeta" }Tipos de workflow y manejo de errores
Workflows Standard
Para procesos largos y críticos: hasta un año, con historial de cada paso.
Un workflow Standard puede durar hasta un año y ejecuta cada paso exactamente una vez, salvo que tú configures reintentos. Guarda el historial completo de cada ejecución, que puedes revisar en la consola paso a paso. Se cobra por cada transición entre estados.
Es el tipo que admite todos los patrones de integración, incluidas las esperas a un trabajo largo (.sync) y a un token de callback (.waitForTaskToken).
Úsalo cuando
Para procesos de negocio que no pueden repetir pasos, que esperan a personas o que duran horas o días: pedidos, altas, aprobaciones.
Ten en cuenta
Con volúmenes enormes de ejecuciones muy cortas, cobrar por transición sale caro. Ahí encaja mejor Express.
Workflows Express
Para volúmenes altos de ejecuciones cortas: hasta cinco minutos.
Un workflow Express dura como máximo cinco minutos y está pensado para muchísimas ejecuciones por segundo. Su garantía es más débil: al menos una vez si lo lanzas de forma asíncrona y como mucho una vez si es síncrono. Se cobra por número de ejecuciones, duración y memoria, y el historial se envía a CloudWatch Logs si lo activas.
Úsalo cuando
Para procesar eventos de alto volumen, transformar datos que llegan por streaming o como backend de una API que responde en el momento.
Ten en cuenta
Como un paso puede repetirse, los Task deben ser idempotentes, igual que los consumidores de una cola. Y no admite .sync ni .waitForTaskToken.
Reintentos con Retry
Reintenta un estado que falla, esperando cada vez más entre intentos.
El campo Retry de un Task, Parallel o Map es una lista de reglas. Cada una indica qué errores cubre (ErrorEquals), cuánto esperar antes del primer reintento (IntervalSeconds, 1 por defecto), cuántas veces intentarlo (MaxAttempts, 3 por defecto) y el BackoffRate, el factor por el que se multiplica la espera tras cada intento (2 por defecto).
Con IntervalSeconds: 2 y BackoffRate: 2, las esperas son 2, 4 y 8 segundos: es el backoff exponencial, que da tiempo a recuperarse al servicio caído. Las versiones recientes también admiten MaxDelaySeconds para poner un tope y JitterStrategy para añadir variación aleatoria.
Úsalo cuando
Para errores pasajeros: tiempos de espera agotados, límites de peticiones, un servicio que se está reiniciando.
Ten en cuenta
No reintentes errores que no se van a arreglar solos, como una tarjeta rechazada: solo retrasas el fallo. Y recuerda que cada reintento repite el paso, así que debe ser idempotente.
"Retry": [
{
"ErrorEquals": ["PasarelaOcupada", "States.Timeout"],
"IntervalSeconds": 2,
"MaxAttempts": 3,
"BackoffRate": 2,
"JitterStrategy": "FULL"
}
]Captura de errores con Catch
Cuando ya no hay más reintentos, desvía el flujo a un estado de recuperación.
El campo Catch indica a qué estado saltar cuando un error no se ha resuelto con reintentos. Se evalúa después de agotar el Retry. Con ResultPath decides dónde guardar la información del error sin perder la entrada original, para que el estado de recuperación sepa qué pedido estaba en juego.
Así se implementan las compensaciones: si falla el envío después de cobrar, el Catch lleva a un estado que reembolsa y otro que avisa al cliente.
Úsalo cuando
Para errores definitivos que requieren otro camino: deshacer pasos anteriores, notificar a una persona o marcar el pedido como fallido.
Ten en cuenta
States.ALL captura cualquier error, así que debe ir sola en la última regla, después de los casos específicos. Y no la uses para esconder fallos: registra siempre qué error llegó.
"Catch": [
{ "ErrorEquals": ["DireccionInvalida"], "ResultPath": "$.error", "Next": "PedirDireccion" },
{ "ErrorEquals": ["States.ALL"], "ResultPath": "$.error", "Next": "Reembolsar" }
]Nota
El orden importa: primero se agotan los Retry y solo después actúa el Catch. Un error pasajero se resuelve reintentando; uno definitivo acaba en la recuperación.
Interactivo
Standard frente a Express
Activa o desactiva opciones para compararlas cara a cara.
| Característica | Standard | Express |
|---|---|---|
| Duración máxima | Un año | Cinco minutos |
| Garantía de ejecución | Exactamente una vez por paso | Al menos una vez (asíncrono) o como mucho una vez (síncrono) |
| Cómo se cobra | Por transición de estado | Por ejecución, duración y memoria |
| Historial | Completo en la consola | En CloudWatch Logs, si lo activas |
| Uso típico | Procesos de negocio largos, aprobaciones | Eventos de alto volumen, backends de API |
Ponlo en práctica
Saber qué es cada cosa es la mitad del trabajo. La otra mitad es reconocer cuándo usarla.
Interactivo
¿Qué usarías?
Lee cada situación y elige la opción que mejor la resuelve. Fallar aquí no cuenta: es para practicar.
El equipo de soporte necesita saber, para cualquier pedido, en qué paso está, qué falló y qué se reintentó, sin revisar los logs de cinco servicios.
Para recordar
- La orquestación concentra el flujo en un coordinador visible; la coreografía lo reparte en eventos y desacopla más.
- Step Functions describe un proceso como una máquina de estados en Amazon States Language, un formato JSON.
Taskhace el trabajo,Choicebifurca,Parallelejecuta ramas fijas a la vez,Maprepite por cada elemento yWaitespera sin gastar recursos.- Standard es para procesos largos que no repiten pasos; Express, para volúmenes altos de ejecuciones de pocos minutos.
Retrycon backoff absorbe los errores pasajeros yCatchlleva los definitivos a un camino de compensación.
Comprueba lo aprendido
Cuestionario
Responde las 5 preguntas para completar la lección.
1.Un
RetrytieneIntervalSeconds: 2,MaxAttempts: 3yBackoffRate: 2. ¿Cuánto espera antes de cada reintento?2.Un proceso de alta espera a que un responsable lo apruebe, lo que puede tardar dos días. ¿Qué tipo de workflow eliges?
3.¿Cuál es el principal inconveniente de la coreografía frente a la orquestación?
4.Dentro de un
Parallel, una de las dos ramas falla y ningúnCatchcaptura el error. ¿Qué pasa?5.¿Para qué sirve
ResultPathen una regla deCatch?