Reintentar un paso fallido y gestionar errores permanentes

AWSBeginner
Practicar Ahora

Introducción

Un fallo temporal de una dependencia puede recuperarse, mientras un pedido no válido debe permanecer fallido. Configurarás reintentos selectivos y una ruta de fallo permanente, y después observarás los intentos reales y los resultados almacenados.

Completa primero Crear un flujo de pedidos de varios pasos. Esta VM nueva proporciona su propio procesador y tablas vacías; no se reutilizan máquinas, roles ni ejecuciones anteriores.

Relación con las certificaciones

Este laboratorio ofrece práctica para los siguientes temas de examen.

Autorizar al flujo para invocar su procesador

En este paso, inspecciona el procesador de negocio proporcionado y crea un rol de ejecución separado para Step Functions.

Usa AWS View junto a Terminal para comparar las consultas CLI con los recursos y resultados reales de este laboratorio. Conserva los datos de referencia proporcionados.

Esta VM nueva proporciona una función de procesamiento y tablas independientes de pedidos, diagnóstico y referencia. Todavía no hay ninguna máquina de estados ni rol de flujo. El procesador acepta un pedido, escribe su cantidad y total y puede leer su resumen después. Para pruebas de fallos sintéticos, el modo flaky lanza TransientOrderError en el primer intento antes de cualquier escritura de negocio; el modo permanent lanza InvalidOrder antes de escribir. Los intentos de diagnóstico están separados de los pedidos de negocio. Su rol de ejecución Lambda ya autoriza esas operaciones de tabla independientes.

Empieza en el directorio del proyecto. Las asignaciones de shell guardan identificadores devueltos; --query selecciona un campo de respuesta y --output text produce una cadena reutilizable.

cd /home/labex/project
WORKER_NAME=labex-ev04-worker
WORKER_ARN=$(aws lambda get-function-configuration \
  --function-name labex-ev04-worker \
  --query FunctionArn \
  --output text)
aws lambda get-function-configuration \
  --function-name labex-ev04-worker \
  --query '{Name:FunctionName,Role:Role,Runtime:Runtime,Timeout:Timeout}'
aws stepfunctions list-state-machines

El procesador usa Python3.12 y su propio rol Lambda; la lista de máquinas está vacía. Step Functions necesita su propio rol de ejecución. Una política de confianza permite al servicio Step Functions asumir ese rol; una política de permisos permite a la sesión resultante invocar exactamente este procesador. Un documento de entrada entre comillas escribe JSON literal y file:// lo lee en la solicitud.

cat > workflow-trust.json <<'JSON'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "states.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
JSON
ROLE_ARN=$(aws iam create-role \
  --role-name labex-ev04-workflow-role \
  --assume-role-policy-document file://workflow-trust.json \
  --query Role.Arn \
  --output text)

Escribe un documento ordinario de permisos. El shell inserta $WORKER_ARN, limitando este permiso al procesador proporcionado.

cat > workflow-invoke.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "lambda:InvokeFunction",
      "Resource": "$WORKER_ARN"
    }
  ]
}
EOF
aws iam put-role-policy \
  --role-name labex-ev04-workflow-role \
  --policy-name InvokeWorker \
  --policy-document file://workflow-invoke.json
aws iam get-role-policy --role-name labex-ev04-workflow-role --policy-name InvokeWorker

La política tiene un ARN exacto de función. Step Functions no recibe los permisos DynamoDB del procesador: este realiza esas llamadas usando su rol Lambda separado. Ejecuta la comprobación de autorización.

Configurar reintentos limitados y una ruta de fallo permanente

En este paso, construye un flujo real de dos tareas con un comportamiento de recuperación selectivo.

reintento temporal y fallo permanente

El error temporal de este procesador puede recuperarse al reintentarlo. Su error permanente sigue Catch hasta un resultado explícito de fallo.

Retry de ASL enumera qué errores de tarea pueden reintentarse. ErrorEquals debe coincidir con el tipo de error de la función. IntervalSeconds:1 empieza con una demora de un segundo; BackoffRate:2 multiplica la siguiente demora. MaxAttempts:2 permite hasta dos reintentos después del intento inicial. Este reintento solo trata TransientOrderError, no todos los fallos posibles.

Catch selecciona otro estado para un error del que la tarea no se ha recuperado. ResultPath registra el error en failure; Next llega a un estado Fail explícito. Gestionar un error no significa que el trabajo de negocio haya tenido éxito. Un InvalidOrder permanente termina FAILED con OrderRejected en lugar de simular que se ha completado un pedido.

Un documento de entrada entre comillas escribe JSON literal. El Choice existente rechaza cantidades no positivas; las dos tareas Task almacenan el pedido y después leen el resumen. Payload.$ pasa la entrada actual, ResultSelector conserva la carga útil real de la función, ResultPath la conserva en saved y OutputPath devuelve el resumen real.

cat > workflow-template.json <<'JSON'
{
  "StartAt": "CheckQuantity",
  "States": {
    "CheckQuantity": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.quantity",
          "NumericGreaterThan": 0,
          "Next": "StoreOrder"
        }
      ],
      "Default": "Rejected"
    },
    "StoreOrder": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "WORKER_NAME",
        "Payload.$": "$"
      },
      "ResultSelector": {
        "result.$": "$.Payload"
      },
      "ResultPath": "$.saved",
      "Retry": [
        {
          "ErrorEquals": [
            "TransientOrderError"
          ],
          "IntervalSeconds": 1,
          "BackoffRate": 2,
          "MaxAttempts": 2
        }
      ],
      "Catch": [
        {
          "ErrorEquals": [
            "InvalidOrder"
          ],
          "Next": "Rejected",
          "ResultPath": "$.failure"
        }
      ],
      "Next": "ReadSummary"
    },
    "ReadSummary": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "WORKER_NAME",
        "Payload": {
          "stage": "summary",
          "id.$": "$.saved.result.id"
        }
      },
      "OutputPath": "$.Payload",
      "End": true
    },
    "Rejected": {
      "Type": "Fail",
      "Error": "OrderRejected",
      "Cause": "Order could not be completed"
    }
  }
}
JSON
jq --arg worker "$WORKER_NAME" '.States.StoreOrder.Parameters.FunctionName=$worker | .States.ReadSummary.Parameters.FunctionName=$worker' workflow-template.json > workflow.json
MACHINE_ARN=$(aws stepfunctions create-state-machine \
  --name labex-ev04-orders \
  --type STANDARD \
  --role-arn "$ROLE_ARN" \
  --definition file://workflow.json \
  --query stateMachineArn \
  --output text)
aws stepfunctions describe-state-machine \
  --state-machine-arn "$MACHINE_ARN" \
  --query '{Name:name,Definition:definition}'

La definición contiene los bloques de reintento y captura selectivos. AWS View muestra la misma configuración; todavía no hay ejecuciones ni pedidos de negocio. Ejecuta la comprobación de definición de recuperación.

Observar resultados reales de Retry, Catch y permisos

En este paso, ejecuta un fallo temporal, un fallo permanente y una invocación denegada.

El primer intento flaky del procesador actualiza un contador de intentos de diagnóstico y lanza un error antes de escribir un pedido. Su siguiente intento puede completarse correctamente. Un bucle de shell con límite lee el estado de ejecución cada dos segundos hasta que deja de estar en ejecución; $(...) captura la salida y break sale del bucle. Si la ejecución sigue RUNNING después del bucle, inspecciónala antes de continuar.

RETRY_ARN=$(aws stepfunctions start-execution \
  --state-machine-arn "$MACHINE_ARN" \
  --name retry-order \
  --input '{"id":"retry-order","quantity":2,"mode":"flaky"}' \
  --query executionArn \
  --output text)
for attempt in $(seq 1 60); do
  STATUS=$(aws stepfunctions describe-execution \
    --execution-arn "$RETRY_ARN" \
    --query status \
    --output text)
  if test "$STATUS" != RUNNING; then break; fi
  sleep 2
done
aws stepfunctions describe-execution \
  --execution-arn "$RETRY_ARN" \
  --query '{Status:status,Output:output}'
aws stepfunctions get-execution-history \
  --execution-arn "$RETRY_ARN" \
  --query 'events[?type==`TaskFailed` || type==`TaskSucceeded`].{Type:type,Error:taskFailedEventDetails.error}'
aws dynamodb get-item \
  --table-name labex-ev04-orders \
  --key '{"id":{"S":"retry-order"}}' \
  --query Item
aws dynamodb get-item \
  --table-name labex-ev04-attempts \
  --key '{"id":{"S":"retry-order"}}' \
  --query Item

El estado final es SUCCEEDED con el resumen completado 2/600. El historial tiene un TaskFailed con TransientOrderError seguido de dos eventos TaskSucceeded: almacenamiento correcto y lectura del resumen. El pedido nativo tiene cantidad 2 y total 600, y los intentos de diagnóstico son 2. Un intento de reintento y una escritura de negocio son recuentos distintos.

Ahora usa el modo de fallo permanente del procesador:

PERMANENT_ARN=$(aws stepfunctions start-execution \
  --state-machine-arn "$MACHINE_ARN" \
  --name permanent-order \
  --input '{"id":"permanent-order","quantity":2,"mode":"permanent"}' \
  --query executionArn \
  --output text)
for attempt in $(seq 1 30); do
  STATUS=$(aws stepfunctions describe-execution \
    --execution-arn "$PERMANENT_ARN" \
    --query status \
    --output text)
  if test "$STATUS" != RUNNING; then break; fi
  sleep 2
done
aws stepfunctions describe-execution \
  --execution-arn "$PERMANENT_ARN" \
  --query '{Status:status,Error:error}'
aws stepfunctions get-execution-history \
  --execution-arn "$PERMANENT_ARN" \
  --query 'events[?type==`TaskFailed` || type==`FailStateEntered`].{Type:type,Error:taskFailedEventDetails.error,State:stateEnteredEventDetails.name}'
aws dynamodb get-item \
  --table-name labex-ev04-orders \
  --key '{"id":{"S":"permanent-order"}}' \
  --query Item

Una llamada real al procesador falla con InvalidOrder; Catch llega a Rejected y la ejecución termina FAILED con OrderRejected. El reintento temporal no coincide con este error permanente. No hay ningún elemento de negocio permanent-order.

Por último, elimina únicamente el permiso de invocación del flujo. Tu operador puede iniciar ejecuciones, pero el rol del flujo no puede invocar el procesador:

aws iam delete-role-policy --role-name labex-ev04-workflow-role --policy-name InvokeWorker
DENIED_ARN=$(aws stepfunctions start-execution \
  --state-machine-arn "$MACHINE_ARN" \
  --name denied-order \
  --input '{"id":"denied-order","quantity":2,"mode":"flaky"}' \
  --query executionArn \
  --output text)
for attempt in $(seq 1 30); do
  STATUS=$(aws stepfunctions describe-execution \
    --execution-arn "$DENIED_ARN" \
    --query status \
    --output text)
  if test "$STATUS" != RUNNING; then break; fi
  sleep 2
done
aws stepfunctions describe-execution \
  --execution-arn "$DENIED_ARN" \
  --query '{Status:status,Error:error}'
aws dynamodb get-item \
  --table-name labex-ev04-orders \
  --key '{"id":{"S":"denied-order"}}' \
  --query Item
aws iam put-role-policy \
  --role-name labex-ev04-workflow-role \
  --policy-name InvokeWorker \
  --policy-document file://workflow-invoke.json

Esta ejecución con acceso denegado falla sin invocar el procesador ni crear datos de diagnóstico o negocio. Reintentar el error de aplicación especificado no repara la falta de autorización. Se restablece el permiso previsto. AWS View muestra el resumen del reintento correcto y dos fallos junto al único pedido.

El siguiente ejemplo muestra el resumen real del reintento, el fallo permanente y la ejecución denegada junto al pedido guardado.

AWS View muestra el éxito real del reintento y el fallo permanente

Ejecuta la comprobación de recuperación real.

Eliminar los recursos del flujo y los resultados sintéticos

En este paso, elimina tu máquina completada, el rol del flujo, el pedido y los registros, conservando los recursos preparados proporcionados.

Las tres ejecuciones han terminado. Eliminar la máquina la retira de la lista de máquinas activas. Elimina la política del rol propio antes de eliminar el rol y después elimina el pedido sintético y el grupo de registros del procesador creados por tu ejecución.

aws stepfunctions delete-state-machine --state-machine-arn "$MACHINE_ARN"
aws iam delete-role-policy --role-name labex-ev04-workflow-role --policy-name InvokeWorker
aws iam delete-role --role-name labex-ev04-workflow-role
aws dynamodb delete-item --table-name labex-ev04-orders --key '{"id":{"S":"retry-order"}}'
aws dynamodb delete-item \
  --table-name labex-ev04-attempts \
  --key '{"id":{"S":"retry-order"}}'
aws logs delete-log-group --log-group-name /aws/lambda/labex-ev04-worker

Lee inventarios correctos para demostrar qué permanece:

aws stepfunctions list-state-machines
aws iam list-roles --query 'Roles[].RoleName'
aws dynamodb scan --table-name labex-ev04-orders --query Items
aws logs describe-log-groups --query logGroups
aws dynamodb scan --table-name labex-ev04-reference --query Items

No hay máquinas activas, pedidos ni grupos de registros. Solo permanece el rol del procesador proporcionado y el elemento de referencia está sin cambios. Conserva el procesador y las tablas proporcionados: la responsabilidad de sus recursos preparados difiere de la de los recursos y el flujo que creaste. Los errores de red o autenticación nunca demuestran la eliminación.

Elimina los archivos ordinarios creados en este laboratorio:

rm -f workflow-trust.json workflow-invoke.json workflow-template.json workflow.json

AWS View muestra máquinas, ejecuciones y pedidos vacíos y la referencia conservada. Ejecuta la comprobación de limpieza antes de finalizar la VM.

Resumen

Configuraste reintentos limitados para un fallo temporal específico y Catch hacia un fallo permanente explícito. El historial nativo y los pedidos reales diferenciaron los intentos de las escrituras de negocio; la denegación de permisos no produjo efectos del procesador ni de negocio. Eliminaste los recursos propios del flujo y sus resultados, conservando los recursos preparados proporcionados.

La siguiente unidad trata un fallo que ocurre después de la escritura de negocio, cuando reintentar podría repetir su efecto.