Reintentos de funciones duraderas de Lambda - AWS Lambda

Reintentos de funciones duraderas de Lambda

Las funciones duraderas proporcionan capacidades de reintento automático que hacen que sus aplicaciones sean resistentes a los errores transitorios. El SDK gestiona los reintentos en dos niveles: los reintentos escalonados en caso de errores de lógica empresarial y los reintentos de backend en caso de errores de infraestructura.

Reintentos escalonados

Cuando se produce una excepción no detectada en un paso, el SDK reintenta el paso automáticamente en función de la estrategia de reintento configurada. Los reintentos escalonados son operaciones de punto de control que permiten que el SDK suspenda la ejecución y la reanude más adelante sin perder el progreso.

Comportamiento de reintentos escalonados

En la siguiente tabla, se describe cómo el SDK gestiona las excepciones dentro de los pasos:

Escenario ¿Qué sucede? Medición del impacto
Excepción en el paso con intentos pendientes de reintento El SDK crea un punto de control para el reintento y suspende la función. En la siguiente invocación, el paso hace un reintento con el retraso del retroceso configurado. 1 operación + tamaño de carga útil del error
Excepción en el paso y no quedan reintentos El paso falla e inicia una excepción. Si el código del controlador no detecta esta excepción, se produce un error en toda la ejecución. 1 operación + tamaño de carga útil del error

Cuando es necesario reintentar un paso, el SDK comprueba el estado del reintento y sale de la invocación a Lambda si no hay ningún otro trabajo en ejecución. Esto permite que el SDK implemente los retrasos de retroceso sin consumir recursos de cómputo. La función se reanuda automáticamente tras el período de retroceso.

Configuración de estrategias de reintentos escalonados

Configure estrategias de reintentos para controlar la forma en que los pasos gestionan los errores. Puede especificar el número máximo de intentos, los intervalos de retroceso y las condiciones de reintento.

Retroceso exponencial con un número máximo de intentos:

TypeScript
const result = await context.step('call-api', async () => { const response = await fetch('https://api.example.com/data'); if (!response.ok) throw new Error(`API error: ${response.status}`); return await response.json(); }, { retryStrategy: (error, attemptCount) => { if (attemptCount >= 5) { return { shouldRetry: false }; } // Exponential backoff: 2s, 4s, 8s, 16s, 32s (capped at 300s) const delay = Math.min(2 * Math.pow(2, attemptCount - 1), 300); return { shouldRetry: true, delay: { seconds: delay } }; } });
Python
def retry_strategy(error, attempt_count): if attempt_count >= 5: return {'should_retry': False} # Exponential backoff: 2s, 4s, 8s, 16s, 32s (capped at 300s) delay = min(2 * (2 ** (attempt_count - 1)), 300) return {'should_retry': True, 'delay': delay} result = context.step( lambda _: call_external_api(), name='call-api', config=StepConfig(retry_strategy=retry_strategy) )

Retroceso de intervalo fijo:

TypeScript
const orders = await context.step('query-orders', async () => { return await queryDatabase(event.userId); }, { retryStrategy: (error, attemptCount) => { if (attemptCount >= 3) { return { shouldRetry: false }; } return { shouldRetry: true, delay: { seconds: 5 } }; } });
Python
def retry_strategy(error, attempt_count): if attempt_count >= 3: return {'should_retry': False} return {'should_retry': True, 'delay': 5} orders = context.step( lambda _: query_database(event['userId']), name='query-orders', config=StepConfig(retry_strategy=retry_strategy) )

Reintento condicional (reintenta solo errores específicos):

TypeScript
const result = await context.step('call-rate-limited-api', async () => { const response = await fetch('https://api.example.com/data'); if (response.status === 429) throw new Error('RATE_LIMIT'); if (response.status === 504) throw new Error('TIMEOUT'); if (!response.ok) throw new Error(`API_ERROR_${response.status}`); return await response.json(); }, { retryStrategy: (error, attemptCount) => { // Only retry rate limits and timeouts const isRetryable = error.message === 'RATE_LIMIT' || error.message === 'TIMEOUT'; if (!isRetryable || attemptCount >= 3) { return { shouldRetry: false }; } // Exponential backoff: 1s, 2s, 4s (capped at 30s) const delay = Math.min(Math.pow(2, attemptCount - 1), 30); return { shouldRetry: true, delay: { seconds: delay } }; } });
Python
def retry_strategy(error, attempt_count): # Only retry rate limits and timeouts is_retryable = str(error) in ['RATE_LIMIT', 'TIMEOUT'] if not is_retryable or attempt_count >= 3: return {'should_retry': False} # Exponential backoff: 1s, 2s, 4s (capped at 30s) delay = min(2 ** (attempt_count - 1), 30) return {'should_retry': True, 'delay': delay} result = context.step( lambda _: call_rate_limited_api(), name='call-rate-limited-api', config=StepConfig(retry_strategy=retry_strategy) )

Deshabilite los reintentos:

TypeScript
const isDuplicate = await context.step('check-duplicate', async () => { return await checkIfOrderExists(event.orderId); }, { retryStrategy: () => ({ shouldRetry: false }) });
Python
is_duplicate = context.step( lambda _: check_if_order_exists(event['orderId']), name='check-duplicate', config=StepConfig( retry_strategy=lambda error, attempt: {'should_retry': False} ) )

Cuando la estrategia de reintentos devuelve shouldRetry: false, el paso falla inmediatamente sin reintentos. Puede usar esto para operaciones que no deben reintentarse, como las comprobaciones de idempotencia o las operaciones con efectos secundarios que no pueden repetirse de forma segura.

Excepciones fuera de los pasos

Cuando se produce una excepción no detectada en el código del controlador, pero fuera de cualquier paso, el SDK marca la ejecución como fallida. Esto garantiza que los errores en la lógica de la aplicación se capturen y notifiquen correctamente.

Escenario ¿Qué sucede? Medición del impacto
Excepción en el código del controlador fuera de cualquier paso El SDK marca la ejecución como FALLIDA y devuelve el error. La excepción no se reintenta automáticamente. Tamaño de carga útil del error

Para habilitar el reintento automático en el código propenso a errores, encapsúlelo en un paso con una estrategia de reintento. Los pasos permiten reintentos automáticos con un tiempo de retroceso configurable, mientras que el código fuera de los pasos produce un error inmediato.

Reintentos en backend

Los reintentos del backend se producen cuando Lambda encuentra errores en la infraestructura, errores de tiempo de ejecución o cuando el SDK no puede comunicarse con el servicio de ejecución duradera. Lambda reintenta automáticamente estos errores para garantizar que las funciones duraderas puedan recuperarse de problemas transitorios de infraestructura.

Escenarios de reintentos en backend

Lambda reintenta la función automáticamente cuando se encuentra en los siguientes escenarios:

  • Errores de servicio interno: cuando Lambda o el servicio de ejecución duradera devuelven un error 5xx, que indica un problema de servicio temporal.

  • Limitación: cuando su función es restringida debido a límites de concurrencia o Service Quotas.

  • Tiempos de espera: cuando el SDK no puede acceder al servicio de ejecución duradera dentro del período de espera.

  • Errores de inicialización del entorno de pruebas: cuando Lambda no puede inicializar el entorno de ejecución.

  • Errores de tiempo de ejecución: cuando el tiempo de ejecución de Lambda encuentra errores fuera del código de la función, como errores de memoria insuficiente o bloqueos del proceso.

  • Errores de token de punto de control inválido: cuando el token del punto de control ya no es válido, normalmente debido a cambios de estado del lado del servicio.

En la siguiente tabla, se describe cómo el SDK gestiona estos escenarios.

Escenario ¿Qué sucede? Medición del impacto
Error de tiempo de ejecución ajeno al controlador duradero (OOM, tiempo de espera, bloqueo) Lambda reintenta la invocación automáticamente. El SDK reproduce desde el último punto de control y omite los pasos completados. Tamaño de carga útil del error + 1 operación por reintento
Error de servicio (5xx) o tiempo de espera cuando se llama a las API de CheckpointDurableExecution y GetDurableExecutionState. Lambda reintenta la invocación automáticamente. El SDK reproduce desde el último punto de control. Tamaño de carga útil del error + 1 operación por reintento
Limitación (429) o token de punto de control inválido cuando se llama a las API de CheckpointDurableExecution y GetDurableExecutionState. Lambda reintenta la invocación automáticamente con un retroceso exponencial. El SDK reproduce desde el último punto de control. Tamaño de carga útil del error + 1 operación por reintento
Error del cliente (4xx, excepto 429 y token inválido) cuando se llama a las API de CheckpointDurableExecution y GetDurableExecutionState. El SDK marca la ejecución como FALLIDA. No se produce ningún reintento automático porque el error indica un problema permanente. Tamaño de carga útil del error

Los reintentos de backend utilizan un retroceso exponencial y continúan hasta que la función se ejecute correctamente o se agote el tiempo de espera de la ejecución. Durante la reproducción, el SDK omite los puntos de control completados y continúa con la ejecución desde la última operación satisfactoria, lo que garantiza que la función no vuelva a ejecutar el trabajo completado.

Prácticas recomendadas para los reintentos

Siga estas prácticas recomendadas cuando configure estrategias de reintentos:

  • Configure estrategias de reintentos explícitas: no confíe en el comportamiento de reintento predeterminado en producción. Configure estrategias de reintento explícitas con el máximo de intentos y los intervalos de retroceso adecuados para su caso de uso.

  • Utilice reintentos condicionales: implemente la lógica de shouldRetry para reintentar solo los errores transitorios (límites de tasa, tiempos de espera) y responder rápido a los errores permanentes (errores de validación, no encontrados).

  • Establezca el máximo de intentos adecuado: equilibre la resiliencia y el tiempo de ejecución. Demasiados reintentos pueden retrasar la detección de errores, mientras que muy pocos pueden provocar errores innecesarios.

  • Utilice un retroceso exponencial el retroceso exponencial reduce la carga de los servicios posteriores y aumenta la probabilidad de recuperación en caso de errores transitorios.

  • Encapsule el código propenso a errores en pasos: no es posible hacer un reintento automático con el código fuera de los pasos. Combine las llamadas a las API externas, las consultas a la base de datos y otras operaciones propensas a errores en pasos con estrategias de reintento.

  • Supervise las métricas de reintentos: realice un seguimiento de las operaciones de reintentos escalonados y de los errores de ejecución en Amazon CloudWatch para identificar patrones y optimizar las estrategias de reintentos.