

# Funciones duraderas de Lambda
<a name="durable-functions"></a>

Las funciones duraderas de Lambda le permiten crear aplicaciones resilientes de varios pasos y flujos de trabajo de IA que pueden ejecutarse durante 1 año como máximo y, al mismo tiempo, mantener un progreso fiable a pesar de las interrupciones. Cuando se ejecuta una función duradera, este ciclo de vida completo se denomina ejecución duradera, que utiliza puntos de control para hacer un seguimiento del progreso y recuperarse automáticamente de los errores mediante la reproducción, es decir, se vuelve a ejecutar desde el principio y se omite el trabajo completado.

Dentro de cada función, utiliza operaciones duraderas como componentes básicos. Los pasos ejecutan la lógica empresarial con los reintentos integrados y el seguimiento del progreso, mientras que las esperas suspenden la ejecución sin incurrir en gastos de cómputo, lo que los hace ideales para procesos de larga duración, como los flujos de trabajo con intervención humana o los sondeos sobre dependencias externas. Ya sea que esté procesando pedidos, coordinando microservicios u orquestando aplicaciones de IA agéntica, las funciones duraderas mantienen el estado automáticamente y se recuperan de los errores mientras escribe código en lenguajes de programación conocidos.

## Ventajas principales
<a name="durable-functions-benefits"></a>

**Escriba código resiliente de forma natural:** con los constructos de programación conocidos, se escribe código que maneja los errores automáticamente. La creación de puntos de control integrados, los reintentos transparentes y la recuperación automática hacen que su lógica empresarial se mantenga limpia y centrada.

**Pague solo por lo que utilice:** durante las operaciones de espera, su función se suspende sin incurrir en gastos de cómputo. En el caso de los flujos de trabajo de larga duración que esperan horas o días, solo paga por el tiempo de procesamiento real, no por las esperas inactivas.

**Simplicidad operativa:** con el modelo sin servidor de Lambda, se obtiene un escalado automático, incluido el escalado a cero, sin administrar la infraestructura. Las funciones duraderas gestionan automáticamente la gestión del estado, la lógica de reintentos y la recuperación de errores, lo que reduce la sobrecarga operativa.

## Cuándo utilizar funciones de larga duración
<a name="durable-functions-use-cases"></a>

**Coordinación de corta duración:** coordine los pagos, el inventario y los envíos entre varios servicios con una reversión automática en caso de errores. Procese los pedidos mediante la validación, la autorización de pago, la asignación del inventario y la gestión logística con una finalización garantizada.

**Procese los pagos con confianza:** cree flujos de pago resilientes que mantengan el estado de las transacciones en caso de errores y gestionen los reintentos de forma automática. Coordine la autorización en varios pasos, las comprobaciones de fraude y la liquidación entre los proveedores de pagos con total auditabilidad en todos los pasos.

**Cree flujos de trabajo de IA fiables:** cree flujos de trabajo de IA de varios pasos que modelen llamadas en cadena, incorporen comentarios humanos y gestionen las tareas de larga duración de forma determinista durante los errores. Reanude automáticamente tras la suspensión y pague solo por el tiempo de ejecución activo.

**Orqueste el cumplimiento de pedidos complejos:** coordine el procesamiento de pedidos en los sistemas de inventario, pago, envío y notificación con resiliencia integrada. Gestione automáticamente los errores parciales, conserve el estado de los pedidos a pesar de las interrupciones y espere de forma eficiente a que se produzcan eventos externos sin consumir recursos de cómputo.

**Automatice los flujos de trabajo empresariales de varios pasos:** cree flujos de trabajo fiables para la incorporación de empleados, la aprobación de préstamos y los procesos de cumplimiento que abarquen días o semanas. Mantenga el estado del flujo de trabajo en lo que respecta a las aprobaciones humanas, las integraciones de sistemas y las tareas programadas, a la vez que proporciona una visibilidad total del estado y el historial de los procesos.

### Cómo se comparan las funciones duraderas con Step Functions
<a name="durable-functions-vs-step-functions"></a>

Tanto las funciones duraderas como Step Functions permiten orquestar flujos de trabajo con una administración automática de estados. Las principales diferencias radican en dónde se ejecutan y en cómo se definen los flujos de trabajo:
+ **Funciones duraderas:** se ejecutan dentro de Lambda, utilizan lenguajes de programación estándar y se administran dentro de un entorno Lambda
+ **Step Functions:** servicio independiente, diseñador visual o DSL basado en gráficos, totalmente administrado y no requiere mantenimiento

Las funciones duraderas son ideales para el desarrollo de aplicaciones en Lambda, donde los flujos de trabajo están estrechamente relacionados con la lógica empresarial. Step Functions resulta especialmente adecuado para la orquestación de flujos de trabajo entre los servicios de AWS cuando se necesita diseño visual, integraciones nativas para más de 220 servicios y una infraestructura que no requiere mantenimiento.

Para obtener una comparación detallada, consulte [Funciones duraderas o Step Functions](durable-step-functions.md).

## Funcionamiento
<a name="durable-functions-how-it-works"></a>

 En realidad, las funciones duraderas son las funciones de Lambda normales que utilizan un mecanismo de puntos de control/reproducción para realizar un seguimiento del progreso y respaldar las operaciones de larga duración a través de puntos de suspensión definidos por el usuario, comúnmente denominados ejecución duradera. Cuando la función se reanude tras una pausa o interrupción, el sistema realizará la reproducción. Durante la reproducción, el código se ejecuta desde el principio, pero omite los puntos de control completados y utiliza los resultados almacenados en lugar de volver a ejecutar las operaciones finalizadas. Este mecanismo de reproducción garantiza la coherencia y, al mismo tiempo, permite ejecuciones de larga duración.

Para aprovechar este mecanismo de puntos de control y reproducción en sus aplicaciones, Lambda proporciona un SDK de ejecución duradera. El SDK elimina la complejidad de la gestión de los puntos de control y la reproducción, y expone primitivas sencillas denominadas operaciones duraderas que utiliza en su código. El SDK está disponible para JavaScript, TypeScript, Python y Java (versión preliminar), y se integra perfectamente con su flujo de trabajo de desarrollo de Lambda existente.

Con el SDK, puede encapsular el controlador de eventos de Lambda, que luego proporciona un DurableContext junto con su evento. Este contexto le da acceso a operaciones duraderas, como los pasos y las esperas. La lógica de la función se escribe como un código secuencial normal, pero, en lugar de llamar directamente a los servicios, se encapsulan las llamadas en pasos para la creación automática de puntos de control y reintentos. Cuando necesita pausar la ejecución, añada esperas que suspenden la función sin incurrir en cargos. El SDK gestiona toda la complejidad de la administración del estado y la reproducción en segundo plano, para que el código permanezca limpio y legible.

 ![\[Filter for Amazon Inspector results related to Lambda functions\]](http://docs.aws.amazon.com/es_es/lambda/latest/dg/images/how_durable_works.png) 

## Siguientes pasos
<a name="durable-functions-next-steps"></a>
+ [Comience con funciones duraderas](durable-getting-started.md)
+ [Explore el SDK de ejecución duradera](durable-execution-sdk.md)
+ [Funciones duraderas o Step Functions](durable-step-functions.md)
+ [Supervise y depure funciones duraderas](durable-monitoring.md)
+ [Revise la seguridad y los permisos](durable-security.md)
+ [Seguir las prácticas recomendadas](durable-best-practices.md)

# Conceptos básicos
<a name="durable-basic-concepts"></a>

Lambda proporciona los SDK de ejecución duradera para JavaScript, TypeScript y Python. Estos SDK son la base para crear funciones duraderas y proporcionan los componentes que necesita para comprobar el progreso, gestionar los reintentos y administrar el flujo de ejecución. Para ver ejemplos y documentación completa del SDK, consulte el [SDK para JavaScript/TypeScript](https://github.com/aws/aws-durable-execution-sdk-js) y el [SDK para Python](https://github.com/aws/aws-durable-execution-sdk-python) en GitHub.

## Ejecución duradera
<a name="durable-execution-concept"></a>

Una **ejecución duradera** representa el ciclo de vida completo de una función duradera de Lambda y utiliza un mecanismo de puntos de control y reproducción para realizar un seguimiento del progreso de la lógica empresarial, suspender la ejecución y recuperarse de los errores. Cuando las funciones se reanudan tras una suspensión o interrupción, los puntos de control completados anteriormente se reproducen y la función continúa ejecutándose.

El ciclo de vida puede incluir varias invocaciones de una función de Lambda para completar la ejecución, especialmente después de suspensiones o una recuperación de errores. Este enfoque permite que la función se ejecute durante períodos prolongados (hasta 1 año) y, al mismo tiempo, mantiene un progreso fiable a pesar de las interrupciones.

**Cómo funciona la reproducción**  
Lambda mantiene un registro en ejecución de todas las operaciones duraderas (pasos, esperas y otras operaciones) a medida que se ejecuta la función. Cuando la función necesita hacer una pausa o se produce una interrupción, Lambda guarda este registro de puntos de control y detiene la ejecución. Cuando llega el momento de reanudarla, Lambda vuelve a invocar la función desde el principio y reproduce el registro de puntos de control; así se sustituyen los valores almacenados por las operaciones completadas. Esto significa que el código se vuelve a ejecutar, pero los pasos completados anteriormente no se vuelven a ejecutar. En cambio, se utilizan sus resultados almacenados.

Este mecanismo de reproducción es fundamental para comprender las funciones duraderas. El código debe ser determinista durante la reproducción, lo que significa que produce los mismos resultados con las mismas entradas. Evite realizar operaciones con efectos secundarios (como generar números al azar u obtener la hora actual) fuera de los pasos, ya que pueden producir valores diferentes durante la reproducción y provocar un comportamiento no determinista.

## DurableContext
<a name="durable-context-concept"></a>

**DurableContext** es el objeto de contexto recibido por la función duradera. Proporciona métodos para operaciones duraderas, como pasos y esperas, que crean puntos de control y administran el flujo de ejecución.

La función duradera recibe un `DurableContext` en lugar del predeterminado de Lambda:

------
#### [ TypeScript ]

```
import {
  DurableContext,
  withDurableExecution,
} from "@aws/durable-execution-sdk-js";

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    const result = await context.step(async () => {
      return "step completed";
    });
    return result;
  },
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import (
    DurableContext,
    durable_execution,
    durable_step,
)

@durable_step
def my_step(step_context, data):
    # Your business logic
    return result

@durable_execution
def handler(event, context: DurableContext):
    result = context.step(my_step(event["data"]))
    return result
```

------

El SDK para Python para funciones duraderas utiliza métodos sincrónicos y no admite `await`. El SDK para TypeScript utiliza `async/await`.

## Steps
<a name="steps-concept"></a>

**Steps** utiliza la lógica empresarial con reintentos integrados y creación automática de puntos de control. Cada paso guarda su resultado, lo que garantiza que la función pueda reanudarse desde cualquier paso completado después de las interrupciones.

------
#### [ TypeScript ]

```
// Each step is automatically checkpointed
const order = await context.step(async () => processOrder(event));
const payment = await context.step(async () => processPayment(order));
const result = await context.step(async () => completeOrder(payment));
```

------
#### [ Python ]

```
# Each step is automatically checkpointed
order = context.step(lambda: process_order(event))
payment = context.step(lambda: process_payment(order))
result = context.step(lambda: complete_order(payment))
```

------

## Estados de espera
<a name="wait-states-concept"></a>

Los **estados de espera** son pausas planificadas en las que la función deja de ejecutarse (y deja de cargarse) hasta el momento de continuar. Utilícelos para esperar períodos de tiempo, devoluciones de llamada externas o condiciones específicas.

------
#### [ TypeScript ]

```
// Wait for 1 hour without consuming resources
await context.wait({ seconds:3600 });

// Wait for external callback
const approval = await context.waitForCallback(
  async (callbackId) => sendApprovalRequest(callbackId)
);
```

------
#### [ Python ]

```
# Wait for 1 hour without consuming resources
context.wait(3600)

# Wait for external callback
approval = context.wait_for_callback(
    lambda callback_id: send_approval_request(callback_id)
)
```

------

Cuando la función encuentra una espera o necesita hacer una pausa, Lambda guarda este registro de puntos de control y detiene la ejecución. Cuando llega el momento de reanudarla, Lambda vuelve a invocar la función y reproduce el registro de puntos de control; así se sustituyen los valores almacenados por las operaciones completadas.

Para flujos de trabajo más complejos, las funciones duraderas de Lambda también incluyen operaciones avanzadas, como `parallel()` para la ejecución simultánea, `map()` para el procesamiento de matrices, `runInChildContext()` para las operaciones anidadas y `waitForCondition()` para el sondeo. Consulte los [ejemplos](durable-examples.md) para ver ejemplos detallados y obtener orientación sobre cuándo utilizar cada operación.

## Invocación de otras funciones
<a name="invoke-concept"></a>

**Invocación** permite que una función duradera llame a otras funciones de Lambda y espera sus resultados. La función de llamada se suspende mientras se ejecuta la función invocada, lo que crea un punto de control que conserva el resultado. Esto le permite crear flujos de trabajo modulares en los que las funciones especializadas gestionan tareas específicas.

Use `context.invoke()` para llamar a otras funciones desde su función duradera. La invocación tiene un punto de control, por lo que si la función se interrumpe una vez completada la función invocada, se reanudará con el resultado almacenado sin volver a invocar la función.

------
#### [ TypeScript ]

```
// Invoke another function and wait for result
const customerData = await context.invoke(
  'validate-customer',
  'arn:aws:lambda:us-east-1:123456789012:function:customer-service:1',
  { customerId: event.customerId }
);

// Use the result in subsequent steps
const order = await context.step(async () => {
  return processOrder(customerData);
});
```

------
#### [ Python ]

```
# Invoke another function and wait for result
customer_data = context.invoke(
    'arn:aws:lambda:us-east-1:123456789012:function:customer-service:1',
    {'customerId': event['customerId']},
    name='validate-customer'
)

# Use the result in subsequent steps
order = context.step(
    lambda: process_order(customer_data),
    name='process-order'
)
```

------

La función invocada puede ser una función duradera o estándar de Lambda. Si invoca una función duradera, la función de llamada espera a que finalice la ejecución duradera completa. Este patrón es común en las arquitecturas de microservicios, en las que cada función gestiona un dominio específico, lo que permite crear flujos de trabajo complejos a partir de funciones especializadas y reutilizables.

**nota**  
No se admiten invocaciones entre cuentas. La función invocada debe estar en la misma cuenta de AWS que la función de llamada.

## Configuración de funciones duraderas
<a name="durable-configuration-basic"></a>

Las funciones duraderas tienen ajustes de configuración específicos que controlan el comportamiento de ejecución y la retención de datos. Estos ajustes son independientes de la configuración estándar de la función de Lambda y se aplican a todo el ciclo de vida de la ejecución duradera.

El objeto **DurableConfig** define la configuración de las funciones duraderas:

```
{
  "ExecutionTimeout": Integer,
  "RetentionPeriodInDays": Integer
}
```

### Execution timeout (Tiempo de espera hasta ejecución)
<a name="durable-execution-timeout"></a>

El **tiempo de espera de la ejecución** controla el tiempo que puede durar una ejecución duradera desde el principio hasta su finalización. Esto es diferente del tiempo de espera de la función de Lambda, que controla cuánto tiempo puede ejecutarse la invocación de una sola función.

Una ejecución duradera puede abarcar varias invocaciones de funciones de Lambda a medida que avanza por los puntos de control, las esperas y las reproducciones. El tiempo de espera de ejecución se aplica al tiempo total transcurrido de la ejecución duradera, no a las invocaciones de funciones individuales.

**Descripción de las diferencias**  
El tiempo de espera de la función de Lambda (máximo 15 minutos) limita cada invocación individual de la función. El tiempo de espera de la ejecución duradera (máximo 1 año) limita el tiempo total desde que se inicia la ejecución hasta que se completa, se produce un error o se agota el tiempo de espera. Durante este período, es posible que la función se invoque varias veces mientras procesa los pasos, espera y se recupera de los errores.

Por ejemplo, si establece un tiempo de espera de ejecución duradera de 24 horas y un tiempo de espera de la función de Lambda de 5 minutos:
+ La invocación de cada función debe completarse en 5 minutos.
+ Toda la ejecución duradera puede durar hasta 24 horas.
+ Su función se puede invocar muchas veces durante esas 24 horas.
+ Las operaciones de espera no se tienen en cuenta para el tiempo de espera de la función de Lambda, pero sí para el tiempo de espera de ejecución.

Puede configurar el tiempo de espera de ejecución si crea una función duradera mediante la consola de Lambda, la AWS CLI o el AWS SAM. En la consola de Lambda, seleccione su función y, a continuación, elija Configuración, Ejecución duradera. Establezca el valor del tiempo de espera de ejecución en segundos (predeterminado: 86 400 segundos/24 horas, mínimo: 60 segundos, máximo: 31 536 000 segundos/1 año).

**nota**  
El tiempo de espera de ejecución y el tiempo de espera de la función de Lambda son ajustes diferentes. El tiempo de espera de la función de Lambda controla cuánto tiempo puede ejecutarse cada invocación individual (máximo 15 minutos). El tiempo de espera de la ejecución controla el tiempo total transcurrido durante toda la ejecución duradera (máximo 1 año).

### Periodo de retención
<a name="durable-retention-period"></a>

El **período de retención** controla el tiempo que Lambda conserva el historial de ejecución y los datos de los puntos de control una vez finalizada una ejecución duradera. Estos datos incluyen los resultados de los pasos, el estado de ejecución y el registro completo de los puntos de control.

Una vez que vence el período de retención, Lambda elimina el historial de ejecuciones y los datos de los puntos de control. Ya no se pueden recuperar los detalles de la ejecución ni reproducir la ejecución. El período de retención comienza cuando la ejecución alcanza un estado terminal (EXITOSA, FALLIDA, DETENIDA o TIEMPO DE ESPERA AGOTADO).

Puede configurar el período de retención cuando crea una función duradera mediante la consola de Lambda, la AWS CLI o el AWS SAM. En la consola de Lambda, seleccione su función y, a continuación, elija Configuración, Ejecución duradera. Establezca el valor del período de retención en días (predeterminado: 14 días, mínimo: 1 día, máximo: 90 días).

Elija un período de retención según sus requisitos de conformidad, sus necesidades de depuración y las consideraciones de los costos. Los períodos de retención más prolongados proporcionan más tiempo para la depuración y la auditoría, pero aumentan los costos de almacenamiento.

## Véase también
<a name="durable-basic-concepts-see-also"></a>
+ [Funciones duraderas o Step Functions](durable-step-functions.md): compare las funciones duraderas con Step Functions para comprender cuándo cada enfoque es más eficaz.

# Creación de funciones duraderas de Lambda
<a name="durable-getting-started"></a>

Para iniciarte en las funciones duraderas de Lambda, utiliza la consola de Lambda para crear una función duradera. En unos minutos, puede crear e implementar una función duradera que utilice pasos y esperas para demostrar la ejecución basada en puntos de control.

A medida que realice el tutorial, aprenderá conceptos fundamentales sobre funciones duraderas, por ejemplo, cómo usar el objeto `DurableContext`, crear puntos de control mediante pasos y pausar la ejecución mediante esperas. También obtendrá información sobre cómo funciona la reproducción cuando la función se reanuda tras una espera.

Para simplificar, este tutorial muestra cómo crear su función con el tiempo de ejecución de Python o Node.js. Con estos lenguajes interpretados, puede editar el código de función directamente en el editor de código integrado en la consola.

Actualmente, las funciones duraderas en Java (versión preliminar) solo pueden implementarse mediante imágenes de contenedor. Para obtener más información sobre cómo crear funciones duraderas a partir de imágenes de contenedor, consulte [Tiempos de ejecución compatibles para funciones duraderas](durable-supported-runtimes.md) o [Implementar funciones duraderas de Lambda con infraestructura como código](durable-getting-started-iac.md).

**nota**  
Actualmente, las funciones duraderas admiten tiempos de ejecución administrados de Python y Node.js (JavaScript/TypeScript) e imágenes de contenedor (OCI), como Java. Para obtener una lista completa de las versiones de tiempo de ejecución compatibles y las opciones de imágenes de contenedores, consulte [Tiempos de ejecución compatibles para funciones duraderas](durable-supported-runtimes.md). Para obtener más información acerca del uso de imágenes de contenedor con Lambda, consulte [Creación de imágenes de contenedor](https://docs.aws.amazon.com/lambda/latest/dg/images-create.html) en la Guía para desarrolladores de Lambda.

**sugerencia**  
Para obtener información sobre cómo crear **soluciones sin servidor**, consulte la [Guía para desarrolladores sin servidor](https://docs.aws.amazon.com/serverless/latest/devguide/).

## Requisitos previos
<a name="durable-getting-started-prerequisites"></a>

### Cómo crear una Cuenta de AWS
<a name="sign-up-for-aws"></a>

Si no dispone de una Cuenta de AWS, siga estos pasos para crear una.

**Cómo registrarse en Cuenta de AWS**

1. Abra [https://portal.aws.amazon.com/billing/signup](https://portal.aws.amazon.com/billing/signup).

1. Siga las instrucciones que se le indiquen.

   Parte del procedimiento de registro consiste en recibir una llamada telefónica o mensaje de texto e indicar un código de verificación en el teclado del teléfono.

   Al registrarse en una Cuenta de AWS, se crea un *Usuario raíz de la cuenta de AWS*. El usuario raíz tendrá acceso a todos los Servicios de AWS y recursos de esa cuenta. Como práctica recomendada de seguridad, asigne acceso administrativo a un usuario y utilice únicamente el usuario raíz para realizar [Tareas que requieren acceso de usuario raíz](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html#root-user-tasks).

AWS le enviará un correo electrónico de confirmación cuando complete el proceso de registro. Se puede ver la actividad de la cuenta y administrarla en cualquier momento entrando en [https://aws.amazon.com/](https://aws.amazon.com/) y seleccionando **Mi cuenta**.

### Creación de un usuario con acceso administrativo
<a name="create-an-admin"></a>

Después de registrarse para obtener una Cuenta de AWS, proteja su Usuario raíz de la cuenta de AWS, habilite AWS IAM Identity Center y cree un usuario administrativo para no usar el usuario raíz en las tareas cotidianas.

**Protección de Usuario raíz de la cuenta de AWS**

1.  Inicie sesión en [Consola de administración de AWS](https://console.aws.amazon.com/) como propietario de la cuenta; para ello, elija **Usuario raíz** e introduzca el correo electrónico de su Cuenta de AWS. En la siguiente página, escriba su contraseña.

   Para obtener ayuda para iniciar sesión con el usuario raíz, consulte [Iniciar sesión como usuario raíz](https://docs.aws.amazon.com/signin/latest/userguide/console-sign-in-tutorials.html#introduction-to-root-user-sign-in-tutorial) en la *Guía del usuario de AWS Sign-In*.

1. Active la autenticación multifactor (MFA) para el usuario raíz.

   Para obtener instrucciones, consulte [Habilitación de un dispositivo MFA virtual para su usuario raíz de la Cuenta de AWS (consola)](https://docs.aws.amazon.com/IAM/latest/UserGuide/enable-virt-mfa-for-root.html) en la *Guía del usuario de IAM*.

**Creación de un usuario con acceso administrativo**

1. Activar IAM Identity Center.

   Consulte las instrucciones en [Activar AWS IAM Identity Center](https://docs.aws.amazon.com//singlesignon/latest/userguide/get-set-up-for-idc.html) en la *Guía del usuario de AWS IAM Identity Center*.

1. En IAM Identity Center, conceda acceso administrativo a un usuario.

   Para ver un tutorial sobre cómo usar Directorio de IAM Identity Center como origen de identidad, consulte [Configuración del acceso de los usuarios con el Directorio de IAM Identity Center predeterminado](https://docs.aws.amazon.com//singlesignon/latest/userguide/quick-start-default-idc.html) en la *Guía del usuario de AWS IAM Identity Center*.

**Inicio de sesión como usuario con acceso de administrador**
+ Para iniciar sesión con el usuario de IAM Identity Center, use la URL de inicio de sesión que se envió a la dirección de correo electrónico cuando creó el usuario de IAM Identity Center.

  Para obtener ayuda para iniciar sesión con un usuario de IAM Identity Center, consulte [Inicio de sesión en el portal de acceso de AWS](https://docs.aws.amazon.com/signin/latest/userguide/iam-id-center-sign-in-tutorial.html) en la *Guía del usuario de AWS Sign-In*.

**Concesión de acceso a usuarios adicionales**

1. En IAM Identity Center, cree un conjunto de permisos que siga la práctica recomendada de aplicar permisos de privilegios mínimos.

   Para conocer las instrucciones, consulte [Create a permission set](https://docs.aws.amazon.com//singlesignon/latest/userguide/get-started-create-a-permission-set.html) en la *Guía del usuario de AWS IAM Identity Center*.

1. Asigne usuarios a un grupo y, a continuación, asigne el acceso de inicio de sesión único al grupo.

   Para conocer las instrucciones, consulte [Add groups](https://docs.aws.amazon.com//singlesignon/latest/userguide/addgroups.html) en la *Guía del usuario de AWS IAM Identity Center*.

## Creación de una función duradera de Lambda con la consola
<a name="getting-started-create-durable-function"></a>

En este ejemplo, la función duradera procesa un pedido en varios pasos con creación automática de puntos de control. La función toma un objeto de JSON que contiene un identificador de pedido, lo valida, procesa el pago y lo confirma. Cada paso atraviesa automáticamente por un punto de control, por lo que, si la función se interrumpe, se reanudará desde el último paso completado.

La función también muestra una operación de espera, en la que se pausa la ejecución durante un breve período para simular la espera de una confirmación externa.

**Cómo crear una función duradera con la consola**

1. Abra la página de [Functions](https://console.aws.amazon.com/lambda/home#/functions) (Funciones) en la consola de Lambda.

1. Seleccione **Creación de función**.

1. Seleccione **Crear desde cero**.

1. En el panel de **Información básica**, ingrese `myDurableFunction` para el **Nombre de la función**.

1. En **Tiempo de ejecución**, elija **Node.js 24** o **Python 3.14**.

1. Seleccione **Habilitar la ejecución duradera**.

Lambda crea la función duradera con un [rol de ejecución](lambda-intro-execution-role.md) que incluye permisos para las operaciones de puntos de control (`lambda:CheckpointDurableExecutions` y `lambda:GetDurableExecutionState`).

**nota**  
Los tiempos de ejecución de Lambda incluyen el SDK de ejecución duradera, por lo que puede probar funciones duraderas sin empaquetar dependencias. Sin embargo, le recomendamos incluir el SDK en su paquete de implementación para producción. Esto garantiza la coherencia de las versiones y evita posibles actualizaciones del tiempo de ejecución que podrían afectar su función.

Para añadir el código de la función duradera, utilice el editor de código integrado en la consola.

------
#### [ Node.js ]

**Modificación del código en la consola**

1. Elija la pestaña **Código**.

   En el editor de código integrado de la consola, debería ver el código de función que creó Lambda. Si no ve la pestaña **index.mjs** en el editor de código, seleccione **index.mjs** en el explorador de archivos, como se muestra en el siguiente diagrama.  
![\[\]](http://docs.aws.amazon.com/es_es/lambda/latest/dg/images/durable-nodejs.png)

1. Pegue el siguiente código en la pestaña **index.mjs**, que reemplaza el código que creó Lambda.

   ```
   import {
     DurableContext,
     withDurableExecution,
   } from "@aws/durable-execution-sdk-js";
   
   export const handler = withDurableExecution(
     async (event, context) => {
       const orderId = event.orderId;
       
       // Step 1: Validate order
       const validationResult = await context.step(async (stepContext) => {
         stepContext.logger.info(`Validating order ${orderId}`);
         return { orderId, status: "validated" };
       });
       
       // Step 2: Process payment
       const paymentResult = await context.step(async (stepContext) => {
         stepContext.logger.info(`Processing payment for order ${orderId}`);
         return { orderId, status: "paid", amount: 99.99 };
       });
       
       // Wait for 10 seconds to simulate external confirmation
       await context.wait({ seconds: 10 });
       
       // Step 3: Confirm order
       const confirmationResult = await context.step(async (stepContext) => {
         stepContext.logger.info(`Confirming order ${orderId}`);
         return { orderId, status: "confirmed" };
       });
           
       return {
         orderId: orderId,
         status: "completed",
         steps: [validationResult, paymentResult, confirmationResult]
       };
     }
   );
   ```

1. En la sección **IMPLEMENTAR** elija **Implementar** para actualizar el código de la función:  
![\[\]](http://docs.aws.amazon.com/es_es/lambda/latest/dg/images/getting-started-tutorial/deploy-console.png)

**Descripción del código de función duradera**  
Antes de avanzar al siguiente paso, observemos el código de función y comprendamos algunos conceptos clave de las funciones duraderas.
+ El encapsulador de `withDurableExecution`:

  La función duradera se encapsula con `withDurableExecution`. Este encapsulador permite una ejecución duradera al proporcionar el objeto `DurableContext` y gestionar las operaciones de los puntos de control.
+ El objeto `DurableContext`:

  En lugar del contexto estándar de Lambda, la función recibe un `DurableContext`. Este objeto proporciona métodos para operaciones duraderas, como `step()` y `wait()`, que crearán puntos de control.
+ Pasos y puntos de control:

  Cada llamada a `context.step()` crea un punto de control antes y después de la ejecución. Si la función se interrumpe, se reanudará desde el último punto de control completado. La función no vuelve a ejecutar los pasos completados. En su lugar, utiliza los resultados almacenados.
+ Operaciones de espera:

  La llamada a `context.wait()` detiene la ejecución sin consumir recursos de cómputo. Cuando finaliza la espera, Lambda vuelve a invocar la función y reproduce el registro de puntos de control; de esta manera, sustituye los valores almacenados de los pasos completados.
+ Mecanismo de reproducción:

  Cuando la función se reanuda tras una espera o una interrupción, Lambda ejecuta el código desde el principio. Sin embargo, los pasos completados no se vuelven a ejecutar. Lambda reproduce sus resultados del registro de puntos de control. Por eso su código debe ser determinista.

------
#### [ Python ]

**Modificación del código en la consola**

1. Elija la pestaña **Código**.

   En el editor de código integrado de la consola, debería ver el código de función que creó Lambda. Si no ve la pestaña **lambda\$1function.py** en el editor de código, seleccione **lambda\$1function.py** en el explorador de archivos, como se muestra en el siguiente diagrama.  
![\[\]](http://docs.aws.amazon.com/es_es/lambda/latest/dg/images/durable-python.png)

1. Pegue el siguiente código en la pestaña **lambda\$1function.py**, que reemplaza el código que creó Lambda.

   ```
   from aws_durable_execution_sdk_python import (
       DurableContext,
       durable_execution,
       durable_step,
   )
   from aws_durable_execution_sdk_python.config import Duration
   
   @durable_step
   def validate_order(step_context, order_id):
       step_context.logger.info(f"Validating order {order_id}")
       return {"orderId": order_id, "status": "validated"}
   
   @durable_step
   def process_payment(step_context, order_id):
       step_context.logger.info(f"Processing payment for order {order_id}")
       return {"orderId": order_id, "status": "paid", "amount": 99.99}
   
   @durable_step
   def confirm_order(step_context, order_id):
       step_context.logger.info(f"Confirming order {order_id}")
       return {"orderId": order_id, "status": "confirmed"}
   
   @durable_execution
   def lambda_handler(event, context: DurableContext):
       order_id = event['orderId']
       
       # Step 1: Validate order
       validation_result = context.step(validate_order(order_id))
       
       # Step 2: Process payment
       payment_result = context.step(process_payment(order_id))
       
       # Wait for 10 seconds to simulate external confirmation
       context.wait(Duration.from_seconds(10))
       
       # Step 3: Confirm order
       confirmation_result = context.step(confirm_order(order_id))
           
       return {
           "orderId": order_id,
           "status": "completed",
           "steps": [validation_result, payment_result, confirmation_result]
       }
   ```

1. En la sección **IMPLEMENTAR** elija **Implementar** para actualizar el código de la función:  
![\[\]](http://docs.aws.amazon.com/es_es/lambda/latest/dg/images/getting-started-tutorial/deploy-console.png)

**Descripción del código de función duradera**  
Antes de avanzar al siguiente paso, observemos el código de función y comprendamos algunos conceptos clave de las funciones duraderas.
+ El decorador `@durable_execution`:

  Su función de controlador está decorada con `@durable_execution`. Este decorador permite una ejecución duradera porque proporciona el objeto `DurableContext` y administra las operaciones de los puntos de control.
+ El decorador `@durable_step`:

  Cada función escalonada está decorada con `@durable_step`. Este decorador marca la función como un paso duradero que crea puntos de control.
+ El objeto `DurableContext`:

  En lugar del contexto estándar de Lambda, la función recibe un `DurableContext`. Este objeto proporciona métodos para operaciones duraderas, como `step()` y `wait()`, que crearán puntos de control.
+ Pasos y puntos de control:

  Cada llamada a `context.step()` crea un punto de control antes y después de la ejecución. Si la función se interrumpe, se reanudará desde el último punto de control completado. La función no vuelve a ejecutar los pasos completados. En su lugar, utiliza los resultados almacenados.
+ Operaciones de espera:

  La llamada a `context.wait()` detiene la ejecución sin consumir recursos de cómputo. Cuando finaliza la espera, Lambda vuelve a invocar la función y reproduce el registro de puntos de control; de esta manera, sustituye los valores almacenados de los pasos completados.
+ El SDK para Python es sincrónico:

  Tenga en cuenta que el SDK para Python no utiliza `await`. Todas las operaciones duraderas son llamadas a métodos sincrónicas.

------

## Invocación de la función de Lambda mediante la consola de editor de código
<a name="get-started-invoke-durable-manually"></a>

Cuando no se especifica (o publica) ninguna versión explícita, la consola invoca la función duradera mediante el calificador de versión `$LATEST`. Sin embargo, para la ejecución determinista del código, siempre debe utilizar un ARN calificado que apunte a una versión estable.

**Cómo publicar una versión de la función:**

1. Elija la pestaña **Versiones**.

1. Elija **Publicar nueva versión**.

1. En **Descripción de la versión**, introduzca **Initial version** (opcional).

1. Elija **Publicar**.

1. Lambda crea la versión 1 de la función. Tenga en cuenta que el ARN de la función ahora incluye `:1` al final, lo que indica que se trata de la versión 1.

Ahora cree un evento de prueba a fin de enviarlo a su función. El evento es un documento con formato JSON que contiene un identificador de pedido.

**Para crear el evento de prueba, realice lo siguiente:**

1. En la sección **EVENTOS DE PRUEBA** del editor de código de la consola, elija **Crear evento de prueba**.  
![\[\]](http://docs.aws.amazon.com/es_es/lambda/latest/dg/images/getting-started-tutorial/test-event.png)

1. Para **Event name (Nombre de evento)**, escriba **myTestEvent**.

1. En la sección **Evento JSON**, sustituya el JSON predeterminado por el siguiente:

   ```
   {
     "orderId": "order-12345"
   }
   ```

1. Seleccione **Save**.

**Cómo probar la función duradera y ver la ejecución**

En la sección **EVENTOS DE PRUEBA** del editor de código de la consola, seleccione el ícono de ejecución junto a su evento de prueba:

![\[\]](http://docs.aws.amazon.com/es_es/lambda/latest/dg/images/getting-started-tutorial/run-test-event.png)


Su función duradera comienza a ejecutarse. Dado que incluye una espera de 10 segundos, la invocación inicial se completa rápidamente, y la función se reanuda tras el período de espera. Puede ver el progreso de la ejecución en la pestaña **Ejecuciones duraderas**.

**Cómo ver la ejecución de función duradera**

1. Seleccione la pestaña **Ejecuciones duraderas**.

1. Busque la ejecución en la lista. La ejecución muestra el estado actual (En ejecución, satisfactoria o fallida).

1. Seleccione el identificador de ejecución para ver los detalles, entre otros los siguientes:
   + El cronograma de ejecución que muestra cuándo se completó cada paso.
   + El historial de los puntos de control.
   + Los períodos de espera.
   + Los resultados de la prueba.

También puede ver los registros de la función en Registros de CloudWatch para ver el resultado de la consola de cada paso.

**Visualización de los registros de invocación de la función en Registros de CloudWatch**

1. En la consola de CloudWatch, abra la página [Log groups (grupos de registro)](https://console.aws.amazon.com/cloudwatch/home#logs:).

1. Elija el grupo de registro para la función (`/aws/lambda/myDurableFunction`).

1. Desplácese hacia abajo y seleccione el **flujo de registro** para las invocaciones de la función que desee consultar.  
![\[\]](http://docs.aws.amazon.com/es_es/lambda/latest/dg/images/log-stream.png)

   Debería ver las entradas de registro de cada invocación de la función, incluidas la ejecución inicial y la reproducción tras la espera.

**nota**  
Cuando se utiliza el registrador de `DurableContext` (por ejemplo, `context.logger` o `stepContext.logger`), los registros también aparecen en las vistas de ejecución duradera y paso a paso de la consola de Lambda. Es posible que estos registros tarden un momento en cargarse.

## Limpieza
<a name="gettingstarted-durable-cleanup"></a>

Cuando haya terminado de trabajar con la función duradera de ejemplo, elimínela. También puede eliminar el [rol de ejecución](lambda-intro-execution-role.md) creado por la consola y el grupo de registro que almacena los registros de la función.

**Cómo eliminar la función de Lambda**

1. Abra la [página de Funciones](https://console.aws.amazon.com/lambda/home#/functions) en la consola de Lambda.

1. Seleccione la función que ha creado.

1. Elija **Acciones**, **Eliminar**.

1. Escriba **confirm** en el campo de entrada de texto y elija **Delete**(Eliminar).

**Para eliminar el grupo de registros**

1. En la consola de CloudWatch, abra la página [Log groups (Grupos de registro)](https://console.aws.amazon.com/cloudwatch/home#logs:).

1. Seleccione el grupo de registros de la función (`/aws/lambda/myDurableFunction`).

1. Elija **Acciones**, **Eliminar grupo(s) de registro(s)**.

1. En el cuadro de diálogo **Eliminar grupos de registros**, elija **Eliminar**.

**Cómo eliminar el rol de ejecución**

1. Abra la página de [Roles](https://console.aws.amazon.com/iam/home?#/roles) de la consola de AWS Identity and Access Management (IAM).

1. Seleccione el rol de ejecución de la función, por ejemplo, ., `myDurableFunction-role-31exxmpl`).

1. Elija **Eliminar**.

1. En el cuadro de diálogo **Eliminar rol**, escriba el nombre del rol y, a continuación, elija **Eliminar**.

## Recursos adicionales y próximos pasos
<a name="durable-getting-started-more-resources"></a>

Ahora que ha creado y probado una función duradera simple de Lambda con la consola, siga los pasos a continuación:
+ Obtenga información sobre los casos de uso más comunes de las funciones duraderas, como las transacciones distribuidas, el procesamiento de pedidos y los flujos de trabajo de revisión humana. Consulte [Ejemplos](durable-examples.md).
+ Descubra cómo supervisar las ejecuciones de funciones duraderas con las métricas y el historial de ejecución de CloudWatch. Consulte [Supervisión y depuración](durable-monitoring.md).
+ Obtenga información sobre cómo invocar funciones duraderas de forma sincrónica y asíncrona y cómo administrar las ejecuciones de larga duración. Consulte [Invocación de funciones duraderas](durable-invoking.md).
+ Siga las prácticas recomendadas para escribir código determinista, administrar el tamaño de los puntos de control y optimizar los costos. Consulte [Prácticas recomendadas](durable-best-practices.md).
+ Obtenga información sobre cómo probar las funciones duraderas a nivel local y en la nube. Consulte [Prueba de funciones duraderas](durable-testing.md).
+ Compare las funciones duraderas con Step Functions para comprender cuándo cada enfoque es más eficaz. Consulte [Funciones duraderas o Step Functions](durable-step-functions.md).

# Implementación e invocación de funciones duraderas de Lambda con la AWS CLI
<a name="durable-getting-started-cli"></a>

Utilice la AWS CLI para crear e implementar funciones duraderas de Lambda con comandos imperativos. Este enfoque le brinda un control directo sobre cada paso del proceso de implementación.

## Requisitos previos
<a name="durable-cli-prerequisites"></a>
+ Instale y configure la AWS CLI. Para obtener instrucciones, consulte [Instalación de AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html).
+ Cree un paquete de implementación con el código de la función y el SDK de ejecución duradera.
+ Cree un rol de ejecución de IAM con permisos de puntos de control.

## Creación del rol de ejecución
<a name="durable-cli-create-role"></a>

Cree un rol de IAM con permisos para las operaciones básicas de ejecución de Lambda y puntos de control.

**Para crear el rol de ejecución**

1. Cree un documento de política de confianza que permita que Lambda asuma el rol. Guarde esto como `trust-policy.json`:

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [
       {
         "Effect": "Allow",
         "Principal": {
           "Service": "lambda.amazonaws.com"
         },
         "Action": "sts:AssumeRole"
       }
     ]
   }
   ```

1. Cree el rol:

   ```
   aws iam create-role \
     --role-name durable-function-role \
     --assume-role-policy-document file://trust-policy.json
   ```

1. Adjunte la política de ejecución duradera para las operaciones de puntos de control y la ejecución básica:

   ```
   aws iam attach-role-policy \
     --role-name durable-function-role \
     --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicDurableExecutionRolePolicy
   ```

La política administrada `AWSLambdaBasicDurableExecutionRolePolicy` incluye los permisos necesarios para las operaciones de puntos de control (`lambda:CheckpointDurableExecutions` y `lambda:GetDurableExecutionState`) y la ejecución básica de Lambda.

## Creación de la función duradera
<a name="durable-cli-create-function"></a>

Cree la función duradera con el parámetro `--durable-config`.

**Cómo crear una función duradera**

1. Empaque el código de función con las dependencias en un archivo.zip:

   ```
   zip -r function.zip index.mjs node_modules/
   ```

1. Cree la función con la ejecución duradera habilitada:

   ```
   aws lambda create-function \
     --function-name myDurableFunction \
     --runtime nodejs22.x \
     --role arn:aws:iam::123456789012:role/durable-function-role \
     --handler index.handler \
     --zip-file fileb://function.zip \
     --durable-config '{"ExecutionTimeout": 3600, "RetentionPeriodInDays": 7}'
   ```

**nota**  
Solo puede habilitar la ejecución duradera cuando crea la función. No puede habilitarla en las funciones existentes.

**nota**  
Actualmente, las funciones duraderas en Java (versión preliminar) solo pueden crearse mediante imágenes de contenedor. Para obtener más información sobre cómo crear funciones duraderas a partir de imágenes de contenedor, consulte [Tiempos de ejecución compatibles para funciones duraderas.](durable-supported-runtimes.md)

## Publicación de una versión
<a name="durable-cli-publish-version"></a>

Si bien las funciones duraderas se pueden invocar con el calificador de versión `$LATEST`, siempre debe utilizar un ARN calificado que apunte a una versión estable para garantizar la ejecución determinista del código.

```
aws lambda publish-version \
  --function-name myDurableFunction \
  --description "Initial version"
```

El comando devuelve el ARN de la versión. Anote el número de versión (por ejemplo, `:1`) al final del ARN.

De manera opcional, cree un alias que apunte a la versión:

```
aws lambda create-alias \
  --function-name myDurableFunction \
  --name prod \
  --function-version 1
```

## Invocación de la función duradera
<a name="durable-cli-invoke"></a>

Invoque la función duradera mediante el ARN calificado (versión o alias).

**nota**  
**Invocaciones idempotentes:** para evitar ejecuciones duplicadas al volver a intentar invocaciones fallidas, puede proporcionar un nombre de ejecución que garantice una semántica de ejecución como máximo una vez. Consulte [Idempotencia](durable-execution-idempotency.md) para obtener más información.

**Invocación sincrónica**  
Para las ejecuciones que se completen en 15 minutos, utilice la invocación sincrónica:

```
aws lambda invoke \
  --function-name myDurableFunction:1 \
  --payload '{"orderId": "order-12345"}' \
  --cli-binary-format raw-in-base64-out \
  response.json
```

O use un alias:

```
aws lambda invoke \
  --function-name myDurableFunction:prod \
  --payload '{"orderId": "order-12345"}' \
  --cli-binary-format raw-in-base64-out \
  response.json
```

**Invocación asíncrona**  
Para ejecuciones de larga duración, utilice la invocación asíncrona:

```
aws lambda invoke \
  --function-name myDurableFunction:prod \
  --invocation-type Event \
  --payload '{"orderId": "order-12345"}' \
  --cli-binary-format raw-in-base64-out \
  response.json
```

Con la invocación asíncrona, Lambda regresa inmediatamente. La función continúa ejecutándose en segundo plano.

**nota**  
Puede utilizar `$LATEST` para crear prototipos y realizar pruebas en la consola. Para las cargas de trabajo de producción, utilice una versión publicada o un alias.

## Administración de ejecuciones duraderas
<a name="durable-cli-manage-executions"></a>

Utilice los siguientes comandos para administrar y supervisar ejecuciones de funciones duraderas.

**Enumeración de ejecuciones**  
Enumere todas las ejecuciones de una función duradera:

```
aws lambda list-durable-executions-by-function \
  --function-name myDurableFunction
```

**Detalles de ejecución**  
Obtenga los detalles sobre una ejecución específica:

```
aws lambda get-durable-execution \
  --durable-execution-arn arn:aws:lambda:us-east-1:123456789012:function:myDurableFunction:my-function-version/durable-execution/my-execution-name/my-execution-id
```

**Obtención del historial de ejecuciones**  
Consulte el historial de puntos de control de una ejecución:

```
aws lambda get-durable-execution-history \
  --durable-execution-arn arn:aws:lambda:us-east-1:123456789012:function:myDurableFunction:my-function-version/durable-execution/my-execution-name/my-execution-id
```

**Detención de una ejecución**  
Detenga una ejecución duradera en ejecución:

```
aws lambda stop-durable-execution \
  --durable-execution-arn arn:aws:lambda:us-east-1:123456789012:function:myDurableFunction:my-function-version/durable-execution/my-execution-name/my-execution-id
```

## Actualizar el código de la función
<a name="durable-cli-update-function"></a>

Actualice su código de función duradera y publique una nueva versión:

**Cómo actualizar y publicar una nueva versión**

1. Actualice el código de la función:

   ```
   aws lambda update-function-code \
     --function-name myDurableFunction \
     --zip-file fileb://function.zip
   ```

1. Espere a que se complete la actualización:

   ```
   aws lambda wait function-updated \
     --function-name myDurableFunction
   ```

1. Publique una nueva versión:

   ```
   aws lambda publish-version \
     --function-name myDurableFunction \
     --description "Updated order processing logic"
   ```

1. A continuación, actualice el alias para que apunte a la nueva versión.

   ```
   aws lambda update-alias \
     --function-name myDurableFunction \
     --name prod \
     --function-version 2
   ```

**importante**  
Las ejecuciones en ejecución siguen utilizando la versión con la que empezaron. Las nuevas invocaciones utilizan la versión del alias actualizada.

## Visualización de registros de funciones
<a name="durable-cli-view-logs"></a>

Consulte los registros de funciones duraderas en Registros de CloudWatch:

```
aws logs tail /aws/lambda/myDurableFunction --follow
```

Filtre los registros para una ejecución específica:

```
aws logs filter-log-events \
  --log-group-name /aws/lambda/myDurableFunction \
  --filter-pattern "exec-abc123"
```

## Eliminar recursos
<a name="durable-cli-cleanup"></a>

Elimine la función duradera y los recursos asociados:

```
# Delete the function
aws lambda delete-function --function-name myDurableFunction

# Delete the IAM role policies
aws iam detach-role-policy \
  --role-name durable-function-role \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

aws iam detach-role-policy \
  --role-name durable-function-role \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicDurableExecutionRolePolicy

# Delete the role
aws iam delete-role --role-name durable-function-role
```

## Siguientes pasos
<a name="durable-cli-next-steps"></a>

Tras implementar la función duradera con la AWS CLI:
+ Supervise las ejecuciones mediante los comandos `list-durable-executions` y `get-durable-execution`.
+ Vea las operaciones de los puntos de control en los eventos de datos de AWS CloudTrail.
+ Configure las alarmas de CloudWatch para los errores de ejecución o las ejecuciones de larga duración.
+ Automatice las implementaciones mediante scripts de intérprete de comandos o canalizaciones de CI/CD.

Para obtener más información sobre los comandos de la AWS CLI en Lambda, consulte la [Referencia de comandos de la AWS CLI](https://docs.aws.amazon.com/cli/latest/reference/lambda/index.html).

# Implementación de funciones duraderas de Lambda con la infraestructura como código
<a name="durable-getting-started-iac"></a>

Puede implementar funciones duraderas de Lambda mediante herramientas de Infraestructura como código (IaC) como AWS CloudFormation, AWS CDK, AWS Serverless Application Model o Terraform. Estas herramientas le permiten definir la función, el rol de ejecución y los permisos en el código, lo que permite que las implementaciones sean repetibles y estén controladas por versiones.

Las tres herramientas requieren que haga lo siguiente:
+ Permita una ejecución duradera de la función.
+ Conceda permiso para pasar el rol de ejecución.
+ Publique una versión o cree un alias (las funciones duraderas requieren ARN calificados).

## Funciones duraderas desde un archivo ZIP
<a name="durable-iac-zip"></a>

### AWS CloudFormation
<a name="durable-iac-cloudformation"></a>

Utilice CloudFormation para definir la función duradera en una plantilla. En el siguiente ejemplo, se crea una función duradera con los permisos necesarios.

```
AWSTemplateFormatVersion: '2010-09-09'
Description: Lambda durable function example

Resources:
  DurableFunctionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'		 	 	 
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicDurableExecutionRolePolicy

  DurableFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: myDurableFunction
      Runtime: nodejs22.x
      Handler: index.handler
      Role: !GetAtt DurableFunctionRole.Arn
      Code:
        ZipFile: |
          // Your durable function code here
          export const handler = async (event, context) => {
            return { statusCode: 200 };
          };
      DurableConfig:
        ExecutionTimeout: 3600
        RetentionPeriodInDays: 7

  DurableFunctionVersion:
    Type: AWS::Lambda::Version
    Properties:
      FunctionName: !Ref DurableFunction
      Description: Initial version

  DurableFunctionAlias:
    Type: AWS::Lambda::Alias
    Properties:
      FunctionName: !Ref DurableFunction
      FunctionVersion: !GetAtt DurableFunctionVersion.Version
      Name: prod

Outputs:
  FunctionArn:
    Description: Durable function ARN
    Value: !GetAtt DurableFunction.Arn
  AliasArn:
    Description: Function alias ARN (use this for invocations)
    Value: !Ref DurableFunctionAlias
```

**Para implementar la plantilla**

```
aws cloudformation deploy \
  --template-file template.yaml \
  --stack-name my-durable-function-stack \
  --capabilities CAPABILITY_IAM
```

### AWS CDK
<a name="durable-iac-cdk"></a>

AWS CDK permite definir la infraestructura mediante lenguajes de programación. En los siguientes ejemplos, se muestra cómo crear una función duradera con TypeScript y Python.

------
#### [ TypeScript ]

```
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';

export class DurableFunctionStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Create the durable function
    const durableFunction = new lambda.Function(this, 'DurableFunction', {
      runtime: lambda.Runtime.NODEJS_22_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset('lambda'),
      functionName: 'myDurableFunction',
      durableConfig: { executionTimeout: Duration.hours(1), retentionPeriod: Duration.days(30) },
    });

    // Create version and alias
    const version = durableFunction.currentVersion;
    const alias = new lambda.Alias(this, 'ProdAlias', {
      aliasName: 'prod',
      version: version,
    });

    // Output the alias ARN
    new cdk.CfnOutput(this, 'FunctionAliasArn', {
      value: alias.functionArn,
      description: 'Use this ARN to invoke the durable function',
    });
  }
}
```

------
#### [ Python ]

```
from aws_cdk import (
    Stack,
    aws_lambda as lambda_,
    aws_iam as iam,
    CfnOutput,
)
from constructs import Construct

class DurableFunctionStack(Stack):
    def __init__(self, scope: Construct, id: str, **kwargs):
        super().__init__(scope, id, **kwargs)

        # Create the durable function
        durable_function = lambda_.Function(
            self, 'DurableFunction',
            runtime=lambda_.Runtime.NODEJS_22_X,
            handler='index.handler',
            code=lambda_.Code.from_asset('lambda'),
            function_name='myDurableFunction',
            durable_execution={execution_timeout: Duration.hours(1), retention_period: Duration.days(30)}
        )

        # Add durable execution managed policy for checkpoint permissions
        durable_function.role.add_managed_policy(
            iam.ManagedPolicy.from_aws_managed_policy_name('service-role/AWSLambdaBasicDurableExecutionRolePolicy')
        )

        # Create version and alias
        version = durable_function.current_version
        alias = lambda_.Alias(
            self, 'ProdAlias',
            alias_name='prod',
            version=version
        )

        # Output the alias ARN
        CfnOutput(
            self, 'FunctionAliasArn',
            value=alias.function_arn,
            description='Use this ARN to invoke the durable function'
        )
```

------

**Cómo implementar la pila de CDK**

```
cdk deploy
```

### AWS Serverless Application Model
<a name="durable-iac-sam"></a>

AWS SAM simplifica las plantillas de CloudFormation para aplicaciones sin servidor. La siguiente plantilla crea una función duradera con AWS SAM.

```
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Lambda durable function with SAM

Resources:
  DurableFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: myDurableFunction
      Runtime: nodejs22.x
      Handler: index.handler
      CodeUri: ./src
      DurableConfig:
        ExecutionTimeout: 3600
        RetentionPeriodInDays: 7
      Policies:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicDurableExecutionRolePolicy
      AutoPublishAlias: prod

Outputs:
  FunctionArn:
    Description: Durable function ARN
    Value: !GetAtt DurableFunction.Arn
  AliasArn:
    Description: Function alias ARN (use this for invocations)
    Value: !Ref DurableFunction.Alias
```

**Cómo implementar la plantilla de SAM**

```
sam build
sam deploy --guided
```

### Terraform
<a name="durable-iac-terraform"></a>

Terraform es una popular herramienta de IaC de código abierto que admite recursos de AWS. En el siguiente ejemplo, se crea una función duradera con Terraform mediante la versión 6.25.0 o posterior del proveedor de AWS.

```
terraform {
  required_version = ">= 1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 6.25.0"
    }
  }
}

provider "aws" {
  region = "us-east-2"
}

# IAM Role for Lambda Function
resource "aws_iam_role" "lambda_role" {
  name = "durable-function-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Action = "sts:AssumeRole"
      Effect = "Allow"
      Principal = {
        Service = "lambda.amazonaws.com"
      }
    }]
  })
}

# Attach durable execution policy for checkpoint operations
resource "aws_iam_role_policy_attachment" "lambda_durable" {
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicDurableExecutionRolePolicy"
  role       = aws_iam_role.lambda_role.name
}

# Lambda Function with Durable Execution enabled
resource "aws_lambda_function" "durable_function" {
  filename      = "function.zip"
  function_name = "myDurableFunction"
  role          = aws_iam_role.lambda_role.arn
  handler       = "index.handler"
  runtime       = "nodejs22.x"
  timeout       = 30
  memory_size   = 512

  durable_config {
    execution_timeout = 900
    retention_period  = 7
  }
}

# Publish a version
resource "aws_lambda_alias" "prod" {
  name             = "prod"
  function_name    = aws_lambda_function.durable_function.function_name
  function_version = aws_lambda_function.durable_function.version
}

output "function_arn" {
  description = "ARN of the Lambda function"
  value       = aws_lambda_function.durable_function.arn
}

output "alias_arn" {
  description = "ARN of the function alias (use this for invocations)"
  value       = aws_lambda_alias.prod.arn
}
```

**Cómo implementar con Terraform**

```
terraform init
terraform plan
terraform apply
```

**nota**  
El soporte de Terraform para las funciones duraderas de Lambda requiere la versión 6.25.0 o posterior del proveedor de AWS. Actualice la versión de su proveedor si está usando una versión antigua.

## Funciones duraderas desde una imagen de contenedor OCI
<a name="durable-iac-oci"></a>

También puede crear funciones duraderas a partir de imágenes de contenedor. Para obtener instrucciones sobre cómo crear una imagen de contenedor, consulte [Tiempos de ejecución compatibles para funciones duraderas.](durable-supported-runtimes.md)

### AWS CDK
<a name="durable-iac-oci-cdk"></a>

AWS CDK permite definir la infraestructura mediante lenguajes de programación. En los siguientes ejemplos, se muestra cómo crear una función duradera con TypeScript a partir de una imagen de contenedor.

```
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';

export class DurableFunctionStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Create the durable function
    const durableFunction = new lambda.DockerImageFunction(this, 'DurableFunction', {
      code: lambda.DockerImageCode.fromImageAsset('./lambda', {
        platform: cdk.aws_ecr_assets.Platform.LINUX_AMD64,
      }),
      functionName: 'myDurableFunction',
      memorySize: 512,
      timeout: cdk.Duration.seconds(30),
      durableConfig: { executionTimeout: cdk.Duration.hours(1), retentionPeriod: cdk.Duration.days(30) },
    });

    // Create version and alias
    const version = durableFunction.currentVersion;
    const alias = new lambda.Alias(this, 'ProdAlias', {
      aliasName: 'prod',
      version: version,
    });

    // Output the alias ARN
    new cdk.CfnOutput(this, 'FunctionAliasArn', {
      value: alias.functionArn,
      description: 'Use this ARN to invoke the durable function',
    });
  }
}
```

**Cómo implementar la pila de CDK**

```
cdk deploy
```

### AWS Serverless Application Model
<a name="durable-iac-oci-sam"></a>

AWS SAM simplifica las plantillas de CloudFormation para aplicaciones sin servidor. La siguiente plantilla crea una función duradera con AWS SAM.

```
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Lambda durable function with SAM

Resources:
  DurableFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: myDurableFunction
      PackageType: Image
      ImageUri: ./src
      DurableConfig:
        ExecutionTimeout: 3600
        RetentionPeriodInDays: 7
      Policies:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicDurableExecutionRolePolicy
      AutoPublishAlias: prod
    Metadata:
      DockerTag: latest
      DockerContext: ./src
      Dockerfile: Dockerfile

Outputs:
  FunctionArn:
    Description: Durable function ARN
    Value: !GetAtt DurableFunction.Arn
  AliasArn:
    Description: Function alias ARN (use this for invocations)
    Value: !Ref DurableFunction.Alias
```

**Cómo implementar la plantilla de SAM**

```
sam build
sam deploy --guided
```

## Patrones de configuración frecuentes
<a name="durable-iac-common-patterns"></a>

Independientemente de la herramienta de IaC que utilice, siga estos patrones para ejecutar funciones duraderas:

**Habilitación de la ejecución duradera**  
Defina la propiedad `DurableConfig` en la función para habilitar una ejecución duradera. Esta propiedad solo está disponible cuando se crea la función. No puede habilitar la ejecución duradera en las funciones existentes.

**Concesión de permisos de puntos de control**  
Adjunte la política administrada de `AWSLambdaBasicDurableExecutionRolePolicy` a su rol de ejecución. Esta política incluye los permisos `lambda:CheckpointDurableExecutions` y `lambda:GetDurableExecutionState` necesarios.

**Uso de ARN calificados**  
Cree una versión o un alias para la función. Las funciones duraderas requieren ARN calificados (con versión o alias) para su invocación. Utilice `AutoPublishAlias` en AWS SAM o cree versiones explícitas en CloudFormation, AWS CDK y Terraform.

**Dependencias del paquete**  
Incluya el SDK de ejecución duradera en su paquete de implementación. En el caso de Node.js, instale `@aws/durable-execution-sdk-js`. En el caso de Python, instale `aws-durable-execution-sdk-python`.

## Siguientes pasos
<a name="durable-iac-next-steps"></a>

Tras implementar la función duradera:
+ Pruebe su función con el ARN calificado (versión o alias).
+ Supervise el progreso de la ejecución en la consola de Lambda en la pestaña Ejecuciones duraderas.
+ Vea las operaciones de los puntos de control en los eventos de datos de AWS CloudTrail.
+ Revise Registros de CloudWatch para ver el rendimiento de las funciones y el comportamiento de reproducción.

Para obtener más información acerca de cómo implementar funciones de Lambda con herramientas de IaC, consulte:
+ [CloudFormation Referencia de AWS::Lambda::Function](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html)
+ [AWS CDK Documentación del módulo de Lambda](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda-readme.html)
+ [AWS SAM Guía para desarrolladores de](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html)

# Funciones duraderas o Step Functions
<a name="durable-step-functions"></a>

Tanto las funciones duraderas de Lambda como AWS Step Functions permiten una orquestación de flujos de trabajo fiable con administración automática de estados y recuperación de errores. Se adaptan a diferentes patrones arquitectónicos y preferencias de los desarrolladores. Las funciones duraderas están optimizadas para el desarrollo de aplicaciones en Lambda, mientras que Step Functions está diseñada para la orquestación de flujos de trabajo entre los servicios de AWS.

## Cuándo utilizar funciones de larga duración
<a name="durable-sfn-when-durable"></a>

Utilice funciones duraderas en los siguientes casos:
+ Su equipo prefiere los lenguajes de programación estándar y las herramientas de desarrollo conocidas.
+ La lógica de su aplicación se encuentra principalmente en las funciones de Lambda.
+ Desea un control detallado sobre el estado de ejecución en el código.
+ Está creando aplicaciones centradas en Lambda con un acoplamiento ajustado entre el flujo de trabajo y la lógica empresarial.
+ Desea realizar iteraciones rápidamente sin tener que alternar entre los diseñadores de códigos y los visuales/basados en JSON.

## Cuándo usar Step Functions
<a name="durable-sfn-when-step"></a>

Utilice Step Functions en los siguientes casos:
+ Necesita una representación visual del flujo de trabajo para tener visibilidad entre todos los equipos.
+ Está orquestando varios servicios de AWS y quiere integraciones nativas sin código del SDK personalizado.
+ Necesita una infraestructura que no requiera mantenimiento (sin parches ni actualizaciones en tiempo de ejecución).
+ Las partes interesadas no técnicas necesitan comprender y validar la lógica del flujo de trabajo.

## Marco de decisiones
<a name="durable-sfn-decision-framework"></a>

Utilice las siguientes preguntas para determinar qué servicio se adapta a su caso de uso:
+ **¿Cuál es su enfoque principal?** Desarrollo de aplicaciones en Lambda → funciones duraderas. Orquestación de flujos de trabajo en AWS → Step Functions.
+ **¿Cuál es su modelo de programación preferido?** Lenguajes de programación estándar → funciones duraderas. Diseñador visual o DSL basado en gráficos → Step Functions.
+ **¿Cuántos servicios de AWS están involucrados?** Principalmente Lambda → funciones duraderas. Varios servicios de AWS → Step Functions.
+ **¿Qué herramientas de desarrollo utiliza?** Experiencia de desarrollador para Lambda, IDE con agente LLM, marcos de pruebas unitarias específicos del lenguaje de programación, AWS SAM, AWS CDK, kit de herramientas de AWS → funciones duraderas. Creador visual de flujos de trabajo y AWS CDK para modelar flujos de trabajo → Step Functions.
+ **¿Quién administra la infraestructura?** Quiere flexibilidad dentro de Lambda → funciones duraderas. Quiere una infraestructura totalmente administrada y que no requiera mantenimiento → Step Functions.

## Comparación de características
<a name="durable-sfn-comparison"></a>

En la siguiente tabla se comparan las principales características de Step Functions y las funciones duraderas de Lambda:


| Característica | AWS Step Functions | Funciones duraderas de Lambda | 
| --- | --- | --- | 
| Enfoque principal | Orquestación de flujos de trabajo en AWS | Desarrollo de aplicaciones en Lambda | 
| Tipo de servicio | Servicio de flujo de trabajo independiente y dedicado | Ejecución dentro de Lambda | 
| Modelo de programación | Basado en gráficos, mediante Amazon States Language (un DSL) o AWS CDK | Lenguajes de programación estándar (JavaScript/TypeScript, Python) | 
| Herramientas de desarrollo | Creador visual en la consola/extensión para IDE del kit de herramientas de AWS, AWS CDK | Lambda DX dentro del IDE y con agentes LLM, marcos de pruebas unitarias, AWS SAM, extensión para IDE del kit de herramientas de AWS | 
| Integraciones | Más de 220 servicios de AWS y 16 000 API | Extensión del modelo de programación basada en eventos de Lambda (orígenes de eventos) | 
| Administración | Totalmente administrado, independiente del tiempo de ejecución y no requiere mantenimiento (sin parches ni actualizaciones del tiempo de ejecución) | Administrado dentro del entorno de Lambda | 
| Lo mejor para | Automatización de TI y procesos empresariales, procesamiento de datos y flujos de trabajo de IA | Transacciones distribuidas, lógica de aplicaciones con estado, orquestación de funciones, procesamiento de datos, flujos de trabajo de IA | 

## Arquitecturas híbridas
<a name="durable-sfn-hybrid"></a>

Muchas aplicaciones se benefician del uso de ambos servicios. Un patrón común es el uso de funciones duraderas para la lógica de nivel de aplicación dentro de Lambda, mientras que Step Functions coordina los flujos de trabajo de alto nivel en varios servicios de AWS más allá de las funciones de Lambda.

## Consideraciones sobre la migración
<a name="durable-sfn-migration"></a>

**Comience con lo simple y evolucione hacia lo complejo:** comience con funciones duraderas para flujos de trabajo centrados en Lambda. Añada Step Functions cuando necesite una orquestación de varios servicios o un diseño visual del flujo de trabajo.

**Usuarios actuales de Step Functions:** mantenga Step Functions para flujos de trabajo establecidos entre servicios. Considere utilizar funciones duraderas para una nueva lógica de aplicaciones de Lambda que necesite fiabilidad.

## Recursos relacionados
<a name="durable-sfn-related"></a>
+ [Funciones duraderas de Lambda](durable-functions.md)
+ [Orquestación de funciones de Lambda con Step Functions](with-step-functions.md)
+ [Comience con funciones duraderas](durable-getting-started.md)

# Ejemplos y casos de uso
<a name="durable-examples"></a>

Las funciones duraderas de Lambda le permiten crear aplicaciones de varios pasos con tolerancia a errores mediante operaciones duraderas como pasos y esperas. Con la creación automática de puntos de control y un modelo de reproducción de puntos de control, en el que la ejecución se reinicia desde el principio tras un error, pero omite los puntos de control completados, sus funciones pueden recuperarse de los errores y reanudar la ejecución sin perder el progreso.

## Procesos tolerantes a errores de corta duración
<a name="durable-examples-short-lived"></a>

Utilice funciones duraderas para crear operaciones fiables que, por lo general, se completan en cuestión de minutos. Si bien estos procesos son más cortos que los flujos de trabajo de larga duración, se benefician de la creación automática de puntos de control y de la tolerancia a errores en todos los sistemas distribuidos. Las funciones duraderas ayudan a garantizar que sus procesos de varios pasos se completen correctamente incluso cuando las llamadas de servicio individuales fallan, sin necesidad de una compleja gestión de errores ni de un código de gestión del estado.

Los escenarios más comunes incluyen los sistemas de reserva de hoteles, las plataformas de reserva de restaurantes, las solicitudes de viajes compartidos, la compra de entradas para eventos y las actualizaciones de suscripciones de SaaS. Estos escenarios comparten características comunes: varias llamadas de servicio que deben completarse juntas, la necesidad de reintento automático en caso de errores transitorios y el requisito de mantener un estado uniforme en todos los sistemas distribuidos.

### Transacciones distribuidas en todos los microservicios
<a name="durable-examples-distributed-transactions"></a>

Coordine los pagos, el inventario y los envíos entre varios servicios con la reversión automática de los errores. Cada operación de servicio se encapsula en un paso, lo que garantiza que la transacción se pueda recuperar desde cualquier punto en caso de que un servicio falle.

------
#### [ TypeScript ]

```
import { DurableContext, withDurableExecution } from "@aws/durable-execution-sdk-js";

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    const { orderId, amount, items } = event;
    
    // Reserve inventory across multiple warehouses
    const inventory = await context.step("reserve-inventory", async () => {
      return await inventoryService.reserve(items);
    });
    
    // Process payment
    const payment = await context.step("process-payment", async () => {
      return await paymentService.charge(amount);
    });
    
    // Create shipment
    const shipment = await context.step("create-shipment", async () => {
      return await shippingService.createShipment(orderId, inventory);
    });
    
    return { orderId, status: 'completed', shipment };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import DurableContext, durable_execution

@durable_execution
def lambda_handler(event, context: DurableContext):
    order_id = event['orderId']
    amount = event['amount']
    items = event['items']
    
    # Reserve inventory across multiple warehouses
    inventory = context.step(
        lambda _: inventory_service.reserve(items),
        name='reserve-inventory'
    )
    
    # Process payment
    payment = context.step(
        lambda _: payment_service.charge(amount),
        name='process-payment'
    )
    
    # Create shipment
    shipment = context.step(
        lambda _: shipping_service.create_shipment(order_id, inventory),
        name='create-shipment'
    )
    
    return {'orderId': order_id, 'status': 'completed', 'shipment': shipment}
```

------

Si algún paso falla, la función lo reintenta automáticamente desde el último punto de control correcto. La reserva de inventario se mantiene aunque el procesamiento del pago falle temporalmente. Cuando la función hace un reintento, se salta el paso de inventario completado y pasa directamente al procesamiento del pago. Esto elimina las reservas duplicadas y garantiza un estado uniforme en todo el sistema distribuido.

### Procesamiento de pedidos en varios pasos
<a name="durable-examples-order-processing"></a>

Procese los pedidos mediante la validación, la autorización de pago, la asignación de inventario y el cumplimiento con reintentos y recuperación automáticos. Cada paso tiene un punto de control, lo que garantiza que el pedido avance incluso si los pasos individuales fallan y se reintentan.

------
#### [ TypeScript ]

```
import { DurableContext, withDurableExecution } from "@aws/durable-execution-sdk-js";

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    const { orderId, customerId, items } = event;
    
    // Validate order details
    const validation = await context.step("validate-order", async () => {
      const customer = await customerService.validate(customerId);
      const itemsValid = await inventoryService.validateItems(items);
      return { customer, itemsValid };
    });
    
    if (!validation.itemsValid) {
      return { orderId, status: 'rejected', reason: 'invalid_items' };
    }
    
    // Authorize payment
    const authorization = await context.step("authorize-payment", async () => {
      return await paymentService.authorize(
        validation.customer.paymentMethod,
        calculateTotal(items)
      );
    });
    
    // Allocate inventory
    const allocation = await context.step("allocate-inventory", async () => {
      return await inventoryService.allocate(items);
    });
    
    // Fulfill order
    const fulfillment = await context.step("fulfill-order", async () => {
      return await fulfillmentService.createShipment({
        orderId,
        items: allocation.allocatedItems,
        address: validation.customer.shippingAddress
      });
    });
    
    return {
      orderId,
      status: 'completed',
      trackingNumber: fulfillment.trackingNumber
    };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import DurableContext, durable_execution

@durable_execution
def lambda_handler(event, context: DurableContext):
    order_id = event['orderId']
    customer_id = event['customerId']
    items = event['items']
    
    # Validate order details
    def validate_order(_):
        customer = customer_service.validate(customer_id)
        items_valid = inventory_service.validate_items(items)
        return {'customer': customer, 'itemsValid': items_valid}
    
    validation = context.step(validate_order, name='validate-order')
    
    if not validation['itemsValid']:
        return {'orderId': order_id, 'status': 'rejected', 'reason': 'invalid_items'}
    
    # Authorize payment
    authorization = context.step(
        lambda _: payment_service.authorize(
            validation['customer']['paymentMethod'],
            calculate_total(items)
        ),
        name='authorize-payment'
    )
    
    # Allocate inventory
    allocation = context.step(
        lambda _: inventory_service.allocate(items),
        name='allocate-inventory'
    )
    
    # Fulfill order
    fulfillment = context.step(
        lambda _: fulfillment_service.create_shipment({
            'orderId': order_id,
            'items': allocation['allocatedItems'],
            'address': validation['customer']['shippingAddress']
        }),
        name='fulfill-order'
    )
    
    return {
        'orderId': order_id,
        'status': 'completed',
        'trackingNumber': fulfillment['trackingNumber']
    }
```

------

Este patrón garantiza que los pedidos nunca se atasquen en estados intermedios. Si la validación falla, el pedido se rechaza antes de la autorización de pago. Si se produce un error en la autorización de pago, el inventario no se asigna. Cada paso se basa en el anterior con un reintento y una recuperación automáticos.

**Nota**  
La comprobación condicional `if (!validation.itemsValid)` está fuera de un paso y volverá a ejecutarse durante la reproducción. Esto es seguro porque es determinista: siempre produce el mismo resultado con el mismo objeto de validación.

## Procesos de larga duración
<a name="durable-examples-long-running"></a>

Utilice funciones duraderas para procesos que abarquen horas, días o semanas. Las operaciones de espera suspenden la ejecución sin incurrir en gastos de cómputo, lo que hace que los procesos de larga duración sean rentables. Durante los períodos de espera, la función deja de ejecutarse y Lambda recicla el entorno de ejecución. Cuando llega el momento de reanudarla, Lambda vuelve a invocar la función y la reproduce desde el último punto de control.

Este modelo de ejecución hace que las funciones duraderas sean ideales para los procesos que necesitan pausarse durante períodos prolongados, ya sea a la espera de una decisión humana, respuestas de un sistema externo, períodos de procesamiento programados o retrasos basados en el tiempo. Solo paga por el tiempo de cómputo activo, no por la espera.

Los escenarios más frecuentes incluyen los procesos de aprobación de documentos, el procesamiento por lotes programado, los procesos de incorporación de varios días, los procesos de prueba de suscripciones y los sistemas de notificación diferida. Estos escenarios comparten características comunes: períodos de espera prolongados medidos en horas o días, la necesidad de mantener el estado de ejecución durante esas esperas y requisitos que tengan en cuenta los costos, en los que pagar por el tiempo de cómputo inactivo es prohibitivo.

### Aprobaciones con intervención humana
<a name="durable-examples-human-in-loop"></a>

Pause la ejecución para revisar o aprobar documentos o tomar decisiones sobre estos y, al mismo tiempo, mantenga el estado de ejecución. La función espera las devoluciones de llamada externas sin consumir recursos y se reanuda automáticamente cuando se recibe la aprobación.

Este patrón es esencial para los procesos que requieren el juicio humano o la validación externa. La función se suspende en el punto de devolución de llamada, por lo que no se incurre en gastos de cómputo durante la espera. Cuando alguien envía su decisión a través de la API, Lambda vuelve a invocar la función y la reproduce desde el punto de control; de este modo, continúa con el resultado de la aprobación.

------
#### [ TypeScript ]

```
import { DurableContext, withDurableExecution } from "@aws/durable-execution-sdk-js";

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    const { documentId, reviewers } = event;
    
    // Step 1: Prepare document for review
    const prepared = await context.step("prepare-document", async () => {
      return await documentService.prepare(documentId);
    });
    
    // Step 2: Request approval with callback
    const approval = await context.waitForCallback(
      "approval-callback",
      async (callbackId) => {
        await notificationService.sendApprovalRequest({
          documentId,
          reviewers,
          callbackId,
          expiresIn: 86400
        });
      },
      {
        timeout: { seconds: 86400 }
      }
    );
    
    // Function resumes here when approval is received
    if (approval?.approved) {
      const finalized = await context.step("finalize-document", async () => {
        return await documentService.finalize(documentId, approval.comments);
      });
      
      return {
        status: 'approved',
        documentId,
        finalizedAt: finalized.timestamp
      };
    }
    
    // Handle rejection
    await context.step("archive-rejected", async () => {
      await documentService.archive(documentId, approval?.reason);
    });
    
    return {
      status: 'rejected',
      documentId,
      reason: approval?.reason
    };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import DurableContext, durable_execution, WaitConfig

@durable_execution
def lambda_handler(event, context: DurableContext):
    document_id = event['documentId']
    reviewers = event['reviewers']
    
    # Step 1: Prepare document for review
    prepared = context.step(
        lambda _: document_service.prepare(document_id),
        name='prepare-document'
    )
    
    # Step 2: Request approval with callback
    def send_approval_request(callback_id):
        notification_service.send_approval_request({
            'documentId': document_id,
            'reviewers': reviewers,
            'callbackId': callback_id,
            'expiresIn': 86400
        })
    
    approval = context.wait_for_callback(
        send_approval_request,
        name='approval-callback',
        config=WaitConfig(timeout=86400)
    )
    
    # Function resumes here when approval is received
    if approval and approval.get('approved'):
        finalized = context.step(
            lambda _: document_service.finalize(document_id, approval.get('comments')),
            name='finalize-document'
        )
        
        return {
            'status': 'approved',
            'documentId': document_id,
            'finalizedAt': finalized['timestamp']
        }
    
    # Handle rejection
    context.step(
        lambda _: document_service.archive(document_id, approval.get('reason') if approval else None),
        name='archive-rejected'
    )
    
    return {
        'status': 'rejected',
        'documentId': document_id,
        'reason': approval.get('reason') if approval else None
    }
```

------

Cuando se recibe la llamada y la función se reanuda, se reproduce desde el principio. El paso de preparación del documento devuelve el resultado del punto de control al instante. La operación waitForCallback también regresa al instante con el resultado de la aprobación almacenado, en lugar de tener que volver a esperar. Luego, la ejecución continúa con los pasos de finalización o archivo.

### Canalizaciones de datos de varias etapas
<a name="durable-examples-data-pipelines"></a>

Procese conjuntos de datos de gran tamaño durante las fases de extracción, transformación y carga con puntos de control entre las etapas. Cada etapa puede tardar horas en completarse, y los puntos de control permiten que la canalización se reanude desde cualquier etapa si se interrumpe.

Este patrón es ideal para los flujos de trabajo de ETL, las migraciones de datos o los trabajos de procesamiento por lotes en los que es necesario procesar los datos por etapas con puntos de recuperación entre ellos. Si una etapa falla, la canalización se reanuda desde la última etapa completada en lugar de reiniciarse desde el principio. También puede utilizar las operaciones de espera para hacer pausas entre etapas, respetando los límites de tasa, esperando a que los sistemas posteriores estén listos o programando el procesamiento durante las horas de menor actividad.

------
#### [ TypeScript ]

```
import { DurableContext, withDurableExecution } from "@aws/durable-execution-sdk-js";

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    const { datasetId, batchSize } = event;
    
    // Stage 1: Extract data from source
    const extracted = await context.step("extract-data", async () => {
      const records = await sourceDatabase.extractRecords(datasetId);
      return { recordCount: records.length, records };
    });
    
    // Wait 5 minutes to respect source system rate limits
    await context.wait({ seconds: 300 });
    
    // Stage 2: Transform data in batches
    const transformed = await context.step("transform-data", async () => {
      const batches = chunkArray(extracted.records, batchSize);
      const results = [];
      
      for (const batch of batches) {
        const transformed = await transformService.processBatch(batch);
        results.push(transformed);
      }
      
      return { batchCount: batches.length, results };
    });
    
    // Wait until off-peak hours (e.g., 2 AM)
    const now = new Date();
    const targetHour = 2;
    const msUntilTarget = calculateMsUntilHour(now, targetHour);
    await context.wait({ seconds: Math.floor(msUntilTarget / 1000) });
    
    // Stage 3: Load data to destination
    const loaded = await context.step("load-data", async () => {
      let loadedCount = 0;
      
      for (const result of transformed.results) {
        await destinationDatabase.loadBatch(result);
        loadedCount += result.length;
      }
      
      return { loadedCount };
    });
    
    // Stage 4: Verify and finalize
    const verified = await context.step("verify-pipeline", async () => {
      const verification = await destinationDatabase.verifyRecords(datasetId);
      await pipelineService.markComplete(datasetId, verification);
      return verification;
    });
    
    return {
      datasetId,
      recordsProcessed: extracted.recordCount,
      batchesProcessed: transformed.batchCount,
      recordsLoaded: loaded.loadedCount,
      verified: verified.success
    };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import DurableContext, durable_execution
from datetime import datetime

@durable_execution
def lambda_handler(event, context: DurableContext):
    dataset_id = event['datasetId']
    batch_size = event['batchSize']
    
    # Stage 1: Extract data from source
    def extract_data(_):
        records = source_database.extract_records(dataset_id)
        return {'recordCount': len(records), 'records': records}
    
    extracted = context.step(extract_data, name='extract-data')
    
    # Wait 5 minutes to respect source system rate limits
    context.wait(300)
    
    # Stage 2: Transform data in batches
    def transform_data(_):
        batches = chunk_array(extracted['records'], batch_size)
        results = []
        
        for batch in batches:
            transformed = transform_service.process_batch(batch)
            results.append(transformed)
        
        return {'batchCount': len(batches), 'results': results}
    
    transformed = context.step(transform_data, name='transform-data')
    
    # Wait until off-peak hours (e.g., 2 AM)
    now = datetime.now()
    target_hour = 2
    ms_until_target = calculate_ms_until_hour(now, target_hour)
    context.wait(ms_until_target // 1000)
    
    # Stage 3: Load data to destination
    def load_data(_):
        loaded_count = 0
        
        for result in transformed['results']:
            destination_database.load_batch(result)
            loaded_count += len(result)
        
        return {'loadedCount': loaded_count}
    
    loaded = context.step(load_data, name='load-data')
    
    # Stage 4: Verify and finalize
    def verify_pipeline(_):
        verification = destination_database.verify_records(dataset_id)
        pipeline_service.mark_complete(dataset_id, verification)
        return verification
    
    verified = context.step(verify_pipeline, name='verify-pipeline')
    
    return {
        'datasetId': dataset_id,
        'recordsProcessed': extracted['recordCount'],
        'batchesProcessed': transformed['batchCount'],
        'recordsLoaded': loaded['loadedCount'],
        'verified': verified['success']
    }
```

------

Cada etapa se encapsula en un paso, lo que crea un punto de control que permite que la canalización se reanude desde cualquier etapa si se interrumpe. La espera de 5 minutos entre la extracción y la transformación respeta los límites de tasa del sistema de origen sin consumir recursos de cómputo, mientras que la espera hasta las 2 de la madrugada programa la costosa operación de carga fuera de las horas pico.

**Nota**  
La llamada `new Date()` y la función `calculateMsUntilHour()` están fuera de los pasos y volverán a ejecutarse durante la reproducción. En el caso de las operaciones basadas en el tiempo que deben ser coherentes en todas las reproducciones, calcule la marca de tiempo dentro de un paso o utilícela solo para los períodos de espera (que vienen determinados por puntos de control).

## Patrones avanzados
<a name="durable-examples-advanced"></a>

Utilice funciones duraderas para crear aplicaciones complejas de varios pasos que combinen múltiples operaciones duraderas, ejecución paralela, procesamiento de matrices, lógica condicional y sondeos. Estos patrones le permiten crear aplicaciones sofisticadas que coordinan muchas tareas y, al mismo tiempo, mantienen la tolerancia a errores y la recuperación automática.

Los patrones avanzados van más allá de simples pasos secuenciales. Puede ejecutar operaciones simultáneamente con `parallel()`, procesar matrices con `map()`, esperar a que se produzcan condiciones externas con `waitForCondition()` y combinar estas primitivas para crear aplicaciones fiables. Cada operación duradera crea sus propios puntos de control, por lo que la aplicación puede recuperarse desde cualquier punto en caso de interrupción.

### Procesos de incorporación de usuarios
<a name="durable-examples-user-onboarding"></a>

Guíe a los usuarios a través del registro, la verificación del correo electrónico, la configuración del perfil y la configuración inicial mediante la gestión de reintentos. En este ejemplo, se combinan pasos secuenciales, devoluciones de llamada y lógica condicional para crear un proceso de incorporación completo.

------
#### [ TypeScript ]

```
import { DurableContext, withDurableExecution } from "@aws/durable-execution-sdk-js";

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    const { userId, email } = event;
    
    // Step 1: Create user account
    const user = await context.step("create-account", async () => {
      return await userService.createAccount(userId, email);
    });
    
    // Step 2: Send verification email
    await context.step("send-verification", async () => {
      return await emailService.sendVerification(email);
    });
    
    // Step 3: Wait for email verification (up to 48 hours)
    const verified = await context.waitForCallback(
      "email-verification",
      async (callbackId) => {
        await notificationService.sendVerificationLink({
          email,
          callbackId,
          expiresIn: 172800
        });
      },
      {
        timeout: { seconds: 172800 }
      }
    );
    
    if (!verified) {
      await context.step("send-reminder", async () => {
        await emailService.sendReminder(email);
      });
      
      return {
        status: "verification_timeout",
        userId,
        message: "Email verification not completed within 48 hours"
      };
    }
    
    // Step 4: Initialize user profile in parallel
    const setupResults = await context.parallel("profile-setup", [
      async (ctx: DurableContext) => {
        return await ctx.step("create-preferences", async () => {
          return await preferencesService.createDefaults(userId);
        });
      },
      
      async (ctx: DurableContext) => {
        return await ctx.step("setup-notifications", async () => {
          return await notificationService.setupDefaults(userId);
        });
      },
      
      async (ctx: DurableContext) => {
        return await ctx.step("create-welcome-content", async () => {
          return await contentService.createWelcome(userId);
        });
      }
    ]);
    
    // Step 5: Send welcome email
    await context.step("send-welcome", async () => {
      const [preferences, notifications, content] = setupResults.getResults();
      return await emailService.sendWelcome({
        email,
        preferences,
        notifications,
        content
      });
    });
    
    return {
      status: "onboarding_complete",
      userId,
      completedAt: new Date().toISOString()
    };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import DurableContext, durable_execution, WaitConfig
from datetime import datetime

@durable_execution
def lambda_handler(event, context: DurableContext):
    user_id = event['userId']
    email = event['email']
    
    # Step 1: Create user account
    user = context.step(
        lambda _: user_service.create_account(user_id, email),
        name='create-account'
    )
    
    # Step 2: Send verification email
    context.step(
        lambda _: email_service.send_verification(email),
        name='send-verification'
    )
    
    # Step 3: Wait for email verification (up to 48 hours)
    def send_verification_link(callback_id):
        notification_service.send_verification_link({
            'email': email,
            'callbackId': callback_id,
            'expiresIn': 172800
        })
    
    verified = context.wait_for_callback(
        send_verification_link,
        name='email-verification',
        config=WaitConfig(timeout=172800)
    )
    
    if not verified:
        context.step(
            lambda _: email_service.send_reminder(email),
            name='send-reminder'
        )
        
        return {
            'status': 'verification_timeout',
            'userId': user_id,
            'message': 'Email verification not completed within 48 hours'
        }
    
    # Step 4: Initialize user profile in parallel
    def create_preferences(ctx: DurableContext):
        return ctx.step(
            lambda _: preferences_service.create_defaults(user_id),
            name='create-preferences'
        )
    
    def setup_notifications(ctx: DurableContext):
        return ctx.step(
            lambda _: notification_service.setup_defaults(user_id),
            name='setup-notifications'
        )
    
    def create_welcome_content(ctx: DurableContext):
        return ctx.step(
            lambda _: content_service.create_welcome(user_id),
            name='create-welcome-content'
        )
    
    setup_results = context.parallel(
        [create_preferences, setup_notifications, create_welcome_content],
        name='profile-setup'
    )
    
    # Step 5: Send welcome email
    def send_welcome(_):
        results = setup_results.get_results()
        preferences, notifications, content = results[0], results[1], results[2]
        return email_service.send_welcome({
            'email': email,
            'preferences': preferences,
            'notifications': notifications,
            'content': content
        })
    
    context.step(send_welcome, name='send-welcome')
    
    return {
        'status': 'onboarding_complete',
        'userId': user_id,
        'completedAt': datetime.now().isoformat()
    }
```

------

El proceso combina pasos secuenciales con puntos de control para la creación de cuentas y el envío de correos electrónicos, y luego se detiene hasta 48 horas a la espera de que se verifique el correo electrónico sin consumir recursos. La lógica condicional gestiona diferentes rutas en función de si la verificación se completa o si se agota el tiempo de espera. Las tareas de configuración de perfiles se ejecutan simultáneamente mediante operaciones en paralelo para reducir el tiempo total de ejecución, y cada paso se reintenta automáticamente en caso de errores transitorios para ayudar a garantizar que la incorporación se complete de forma fiable.

### Invocaciones encadenadas entre funciones
<a name="durable-examples-chained-invocations"></a>

Invoque otras funciones de Lambda desde dentro de una función duradera mediante `context.invoke()`. La función de llamada se suspende mientras espera que se complete la función invocada, lo que crea un punto de control que conserva el resultado. Si la función de llamada se interrumpe una vez completada la función invocada, se reanudará con el resultado almacenado sin volver a invocar la función.

Utilice este patrón cuando tenga funciones especializadas que gestionen dominios específicos (validación de clientes, procesamiento de pagos, gestión de inventario) y necesite coordinarlas en un flujo de trabajo. Cada función mantiene su propia lógica y puede ser invocada por varias funciones del orquestador, lo que evita la duplicación de código.

------
#### [ TypeScript ]

```
import { DurableContext, withDurableExecution } from "@aws/durable-execution-sdk-js";

// Main orchestrator function
export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    const { orderId, customerId } = event;
    
    // Step 1: Validate customer by invoking customer service function
    const customer = await context.invoke(
      "validate-customer",
      "arn:aws:lambda:us-east-1:123456789012:function:customer-service:1",
      { customerId }
    );
    
    if (!customer.isValid) {
      return { orderId, status: "rejected", reason: "invalid_customer" };
    }
    
    // Step 2: Check inventory by invoking inventory service function
    const inventory = await context.invoke(
      "check-inventory",
      "arn:aws:lambda:us-east-1:123456789012:function:inventory-service:1",
      { orderId, items: event.items }
    );
    
    if (!inventory.available) {
      return { orderId, status: "rejected", reason: "insufficient_inventory" };
    }
    
    // Step 3: Process payment by invoking payment service function
    const payment = await context.invoke(
      "process-payment",
      "arn:aws:lambda:us-east-1:123456789012:function:payment-service:1",
      {
        customerId,
        amount: inventory.totalAmount,
        paymentMethod: customer.paymentMethod
      }
    );
    
    // Step 4: Create shipment by invoking fulfillment service function
    const shipment = await context.invoke(
      "create-shipment",
      "arn:aws:lambda:us-east-1:123456789012:function:fulfillment-service:1",
      {
        orderId,
        items: inventory.allocatedItems,
        address: customer.shippingAddress
      }
    );
    
    return {
      orderId,
      status: "completed",
      trackingNumber: shipment.trackingNumber,
      estimatedDelivery: shipment.estimatedDelivery
    };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import DurableContext, durable_execution

# Main orchestrator function
@durable_execution
def lambda_handler(event, context: DurableContext):
    order_id = event['orderId']
    customer_id = event['customerId']
    
    # Step 1: Validate customer by invoking customer service function
    customer = context.invoke(
        'arn:aws:lambda:us-east-1:123456789012:function:customer-service:1',
        {'customerId': customer_id},
        name='validate-customer'
    )
    
    if not customer['isValid']:
        return {'orderId': order_id, 'status': 'rejected', 'reason': 'invalid_customer'}
    
    # Step 2: Check inventory by invoking inventory service function
    inventory = context.invoke(
        'arn:aws:lambda:us-east-1:123456789012:function:inventory-service:1',
        {'orderId': order_id, 'items': event['items']},
        name='check-inventory'
    )
    
    if not inventory['available']:
        return {'orderId': order_id, 'status': 'rejected', 'reason': 'insufficient_inventory'}
    
    # Step 3: Process payment by invoking payment service function
    payment = context.invoke(
        'arn:aws:lambda:us-east-1:123456789012:function:payment-service:1',
        {
            'customerId': customer_id,
            'amount': inventory['totalAmount'],
            'paymentMethod': customer['paymentMethod']
        },
        name='process-payment'
    )
    
    # Step 4: Create shipment by invoking fulfillment service function
    shipment = context.invoke(
        'arn:aws:lambda:us-east-1:123456789012:function:fulfillment-service:1',
        {
            'orderId': order_id,
            'items': inventory['allocatedItems'],
            'address': customer['shippingAddress']
        },
        name='create-shipment'
    )
    
    return {
        'orderId': order_id,
        'status': 'completed',
        'trackingNumber': shipment['trackingNumber'],
        'estimatedDelivery': shipment['estimatedDelivery']
    }
```

------

Cada invocación crea un punto de control en la función del orquestador. Si el orquestador se interrumpe una vez finalizada la validación del cliente, se reanudará desde ese punto de control con los datos del cliente almacenados y omitirá la invocación de validación. De este modo, se evitan las llamadas duplicadas a los servicios posteriores y se garantiza una ejecución uniforme en todas las interrupciones.

Las funciones invocadas pueden ser funciones duraderas o estándar de Lambda. Si invoca una función duradera, puede tener su propio flujo de trabajo de varios pasos con esperas y puntos de control. El orquestador simplemente espera a que finalice la ejecución duradera completa para recibir el resultado final.

**nota**  
No se admiten invocaciones entre cuentas. Todas las funciones invocadas deben estar en la misma cuenta de AWS que la función de llamada.

### Procesamiento por lotes con puntos de control
<a name="durable-examples-batch-processing"></a>

Procese millones de registros con recuperación automática desde el último punto de control exitoso después de un error. Este ejemplo demuestra cómo las funciones duraderas combinan las operaciones de `map()` con la fragmentación y la limitación de tasa para gestionar el procesamiento de datos a gran escala.

------
#### [ TypeScript ]

```
import { DurableContext, withDurableExecution } from "@aws/durable-execution-sdk-js";

interface Batch {
  batchIndex: number;
  recordIds: string[];
}

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    const { datasetId, batchSize = 1000 } = event;
    
    // Step 1: Get all record IDs to process
    const recordIds = await context.step("fetch-record-ids", async () => {
      return await dataService.getRecordIds(datasetId);
    });
    
    // Step 2: Split into batches
    const batches: Batch[] = [];
    for (let i = 0; i < recordIds.length; i += batchSize) {
      batches.push({
        batchIndex: Math.floor(i / batchSize),
        recordIds: recordIds.slice(i, i + batchSize)
      });
    }
    
    // Step 3: Process batches with controlled concurrency
    const batchResults = await context.map(
      "process-batches",
      batches,
      async (ctx: DurableContext, batch: Batch, index: number) => {
        const processed = await ctx.step(`batch-${batch.batchIndex}`, async () => {
          const results = [];
          for (const recordId of batch.recordIds) {
            const result = await recordService.process(recordId);
            results.push(result);
          }
          return results;
        });
        
        const validated = await ctx.step(`validate-${batch.batchIndex}`, async () => {
          return await validationService.validateBatch(processed);
        });
        
        return {
          batchIndex: batch.batchIndex,
          recordCount: batch.recordIds.length,
          successCount: validated.successCount,
          failureCount: validated.failureCount
        };
      },
      {
        maxConcurrency: 5
      }
    );
    
    // Step 4: Aggregate results
    const summary = await context.step("aggregate-results", async () => {
      const results = batchResults.getResults();
      const totalSuccess = results.reduce((sum, r) => sum + r.successCount, 0);
      const totalFailure = results.reduce((sum, r) => sum + r.failureCount, 0);
      
      return {
        datasetId,
        totalRecords: recordIds.length,
        batchesProcessed: batches.length,
        successCount: totalSuccess,
        failureCount: totalFailure,
        completedAt: new Date().toISOString()
      };
    });
    
    return summary;
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import DurableContext, durable_execution, MapConfig
from datetime import datetime
from typing import List, Dict

@durable_execution
def lambda_handler(event, context: DurableContext):
    dataset_id = event['datasetId']
    batch_size = event.get('batchSize', 1000)
    
    # Step 1: Get all record IDs to process
    record_ids = context.step(
        lambda _: data_service.get_record_ids(dataset_id),
        name='fetch-record-ids'
    )
    
    # Step 2: Split into batches
    batches = []
    for i in range(0, len(record_ids), batch_size):
        batches.append({
            'batchIndex': i // batch_size,
            'recordIds': record_ids[i:i + batch_size]
        })
    
    # Step 3: Process batches with controlled concurrency
    def process_batch(ctx: DurableContext, batch: Dict, index: int):
        batch_index = batch['batchIndex']
        
        def process_records(_):
            results = []
            for record_id in batch['recordIds']:
                result = record_service.process(record_id)
                results.append(result)
            return results
        
        processed = ctx.step(process_records, name=f'batch-{batch_index}')
        
        validated = ctx.step(
            lambda _: validation_service.validate_batch(processed),
            name=f'validate-{batch_index}'
        )
        
        return {
            'batchIndex': batch_index,
            'recordCount': len(batch['recordIds']),
            'successCount': validated['successCount'],
            'failureCount': validated['failureCount']
        }
    
    batch_results = context.map(
        process_batch,
        batches,
        name='process-batches',
        config=MapConfig(max_concurrency=5)
    )
    
    # Step 4: Aggregate results
    def aggregate_results(_):
        results = batch_results.get_results()
        total_success = sum(r['successCount'] for r in results)
        total_failure = sum(r['failureCount'] for r in results)
        
        return {
            'datasetId': dataset_id,
            'totalRecords': len(record_ids),
            'batchesProcessed': len(batches),
            'successCount': total_success,
            'failureCount': total_failure,
            'completedAt': datetime.now().isoformat()
        }
    
    summary = context.step(aggregate_results, name='aggregate-results')
    
    return summary
```

------

Los registros se dividen en lotes administrables para evitar sobrecargar la memoria o los servicios posteriores. A continuación, se procesan varios lotes simultáneamente con `maxConcurrency` en control del paralelismo. Cada lote tiene su propio punto de control, por lo que los errores reintentan solo el lote fallido en lugar de volver a procesar todos los registros. Este patrón es ideal para trabajos de ETL, migraciones de datos u operaciones masivas en las que el procesamiento puede tardar horas.

## Siguientes pasos
<a name="durable-examples-next-steps"></a>
+ Explore los [conceptos básicos](durable-basic-concepts.md) para comprender DurableContext, los pasos y las esperas.
+ Revise las [prácticas recomendadas](durable-best-practices.md) para escribir código determinista y optimizar el rendimiento.
+ Obtenga información sobre la [prueba de funciones duraderas](durable-testing.md) a nivel local y en la nube.
+ Compare las funciones duraderas con Step Functions para comprender cuándo cada enfoque es más eficaz. Consulte [Funciones duraderas o Step Functions](durable-step-functions.md).

# Seguridad y permisos para las funciones duraderas de Lambda
<a name="durable-security"></a>

Las funciones duraderas de Lambda requieren permisos de IAM específicos para gestionar las operaciones de los puntos de control. Siga el principio de privilegio mínimo; para ello, otorgue solo los permisos que necesita su función.

## Permisos de rol de ejecución
<a name="durable-execution-role"></a>

El rol de ejecución de la función duradera requiere permisos para crear puntos de control y recuperar el estado de ejecución. La siguiente política muestra los permisos mínimos necesarios:

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "lambda:CheckpointDurableExecution",
                "lambda:GetDurableExecutionState"
            ],
            "Resource": "arn:aws:lambda:region:account-id:function:function-name:*"
        }
    ]
}
```

Cuando crea una función duradera mediante la consola, Lambda añade automáticamente estos permisos al rol de ejecución. Si crea la función con la AWS CLI o AWS CloudFormation, añada estos permisos a su rol de ejecución.

**Principio de privilegio mínimo**  
Delimite el elemento de `Resource` a los ARN de funciones específicas en lugar de utilizar caracteres comodín. Esto limita el rol de ejecución a las operaciones de puntos de control únicamente para las funciones que las necesitan.

**Ejemplo: permisos delimitados para varias funciones**

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "lambda:CheckpointDurableExecution",
                "lambda:GetDurableExecutionState"
            ],
            "Resource": [
                "arn:aws:lambda:us-east-1:123456789012:function:orderProcessor:*",
                "arn:aws:lambda:us-east-1:123456789012:function:paymentHandler:*"
            ]
        }
    ]
}
```

Como alternativa, puede utilizar la política administrada de AWS `AWSLambdaBasicDurableExecutionRolePolicy`, que incluye los permisos de ejecución duradera necesarios junto con los permisos básicos de ejecución de Lambda para Registros de Amazon CloudWatch.

## Cifrado de estado
<a name="durable-state-encryption"></a>

Las funciones duraderas de Lambda habilitan automáticamente el cifrado en reposo mediante claves propiedad de AWS sin costo alguno. La ejecución de cada función mantiene un estado aislado al que no pueden acceder las demás ejecuciones. No se admiten las claves administradas por el cliente (CMK).

Los datos de los puntos de control incluyen los siguientes:
+ Resultados escalonados y valores devueltos
+ Progreso y cronograma de la ejecución
+ Información del estado de espera

Todos los datos se cifran en tránsito mediante TLS cuando Lambda lee o escribe datos de puntos de control.

### Cifrado personalizado con serializadores y deserializadores personalizados
<a name="durable-custom-encryption"></a>

Para los requisitos de seguridad críticos, puede implementar su propio mecanismo de cifrado y descifrado mediante serializadores y deserializadores (SerDer) personalizados mediante un SDK duradero. Este enfoque le proporciona un control total de las claves y los algoritmos de cifrado utilizados para proteger los datos de los puntos de control.

**importante**  
Cuando utiliza el cifrado personalizado, pierde la visibilidad de los resultados de la operación en la consola de Lambda y en las respuestas de la API. Los datos de los puntos de control aparecen cifrados en el historial de ejecución y no se pueden inspeccionar sin descifrarlos.

El rol de ejecución de la función necesita permisos de `kms:Encrypt` y `kms:Decrypt` para la clave de AWS KMS utilizada en la implementación personalizada de SerDer.

## Registros de CloudTrail
<a name="durable-cloudtrail-logging"></a>

Lambda registra las operaciones de los puntos de control como eventos de datos en AWS CloudTrail. Puede usar CloudTrail para auditar cuándo se crean los puntos de control, realizar un seguimiento de los cambios en el estado de ejecución y supervisar el acceso a los datos de la ejecución duradera.

Las operaciones de puntos de control aparecen en los registros de CloudTrail con los siguientes nombres de eventos:
+ `CheckpointDurableExecution`: se registra cuando se completa un paso y se crea un punto de control.
+ `GetDurableExecutionState`: se registra cuando Lambda recupera el estado de ejecución durante la reproducción.

Para habilitar el registro de eventos de datos para funciones duraderas, configure un registro de CloudTrail para registrar los eventos de datos de Lambda. Para obtener más información, consulte [Registro de eventos de datos](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/logging-data-events-with-cloudtrail.html) en la Guía del usuario de CloudTrail.

**Ejemplo: entrada de registro de CloudTrail para la operación de puntos de control**

```
{
    "eventVersion": "1.08",
    "eventTime": "2024-11-16T10:30:45Z",
    "eventName": "CheckpointDurableExecution",
    "eventSource": "lambda.amazonaws.com",
    "requestParameters": {
        "functionName": "myDurableFunction",
        "executionId": "exec-abc123",
        "stepId": "step-1"
    },
    "responseElements": null,
    "eventType": "AwsApiCall"
}
```

## Consideraciones sobre el acceso entre cuentas
<a name="durable-cross-account-access"></a>

Si invoca funciones duraderas en todas las cuentas de AWS, la cuenta que realiza la llamada necesita permiso de `lambda:InvokeFunction`, pero las operaciones de puntos de control siempre utilizan el rol de ejecución en la cuenta de la función. La cuenta que realiza la llamada no puede acceder directamente a los datos de los puntos de control ni al estado de ejecución.

Este aislamiento garantiza que los datos de los puntos de control permanezcan seguros en la cuenta de la función, incluso cuando se invoquen desde cuentas externas.

## Características heredadas de seguridad de Lambda
<a name="durable-inherited-security"></a>

Las funciones duraderas heredan todas las características de seguridad, gobernanza y cumplimiento de Lambda, incluidas la conectividad de la VPC, el cifrado de variables de entorno, las colas de mensajes fallidos, la concurrencia reservada, las URL de función, la firma de código y las certificaciones de conformidad (SOC, PCI DSS, HIPAA, etc.).

Para obtener información detallada sobre las características de seguridad de Lambda, consulte [Seguridad en AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/lambda-security.html) en la Guía para desarrolladores de Lambda. Las únicas consideraciones de seguridad adicionales para las funciones duraderas son los permisos de los puntos de control documentados en esta guía.

# SDK de ejecución duradera
<a name="durable-execution-sdk"></a>

El SDK de ejecución duradera es la base para crear funciones duraderas. Proporciona las primitivas que necesita para comprobar el progreso, gestionar los reintentos y administrar el flujo de ejecución. El SDK elimina la complejidad de la administración y reproducción de los puntos de control, y permite escribir código secuencial que se vuelve automáticamente tolerante a errores.

El SDK está disponible para JavaScript, TypeScript, Python y Java (versión preliminar). Para ver ejemplos y la documentación completa de la API, consulte el [SDK de JavaScript/TypeScript](https://github.com/aws/aws-durable-execution-sdk-js), el [SDK de Python](https://github.com/aws/aws-durable-execution-sdk-python) y el [SDK de Java](https://github.com/aws/aws-durable-execution-sdk-java) en GitHub.

## DurableContext
<a name="durable-sdk-context"></a>

El SDK proporciona a la función un objeto de `DurableContext` que expone todas las operaciones duraderas. Este contexto reemplaza el contexto estándar de Lambda y proporciona métodos para crear puntos de control, administrar el flujo de ejecución y coordinar con sistemas externos.

Para usar el SDK, encapsule el controlador de Lambda con el encapsulador de ejecución duradera:

------
#### [ TypeScript ]

```
import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js';

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    // Your function receives DurableContext instead of Lambda context
    // Use context.step(), context.wait(), etc.
    return result;
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext

@durable_execution
def handler(event: dict, context: DurableContext):
    # Your function receives DurableContext
    # Use context.step(), context.wait(), etc.
    return result
```

------
#### [ Java (Preview) ]

```
import software.amazon.lambda.durable.DurableContext;
import software.amazon.lambda.durable.DurableHandler;

public class Handler extends DurableHandler<Object, String> {
    @Override
    public String handleRequest(Object input, DurableContext context) {
        // Your function receives DurableContext
        // Use context.step(), context.wait(), etc.
        return result;
    }
}
```

------

El encapsulador intercepta la invocación de la función, carga cualquier registro de puntos de control existente y proporciona el `DurableContext` que administra la reproducción y los puntos de control.

## Operaciones que realiza el SDK
<a name="durable-sdk-what-it-does"></a>

El SDK gestiona tres responsabilidades fundamentales que permiten una ejecución duradera:

**Administración de puntos de control:** el SDK crea puntos de control automáticamente a medida que la función ejecuta operaciones duraderas. Cada punto de control registra el tipo de operación, las entradas y los resultados. Cuando la función completa un paso, el SDK conserva el punto de control antes de continuar. Esto garantiza que la función pueda reanudarse después de cualquier operación completada en caso de interrupción.

**Coordinación de reproducción:** cuando la función se reanuda tras una pausa o interrupción, el SDK realiza la reproducción. Ejecuta el código desde el principio, pero omite las operaciones completadas y utiliza los resultados de los puntos de control almacenados en lugar de volver a ejecutarlos. El SDK garantiza que la reproducción sea determinista: con las mismas entradas y el mismo registro de puntos de control, la función produce los mismos resultados.

**Aislamiento de estados:** el SDK mantiene el estado de ejecución por separado de la lógica empresarial. Cada ejecución duradera tiene su propio registro de puntos de control al que no pueden acceder las demás ejecuciones. El SDK cifra los datos en reposo de los puntos de control y garantiza que el estado se mantenga uniforme en todas las reproducciones.

## Cómo funciona la creación de puntos de control
<a name="durable-sdk-how-checkpointing-works"></a>

Cuando se llama a una operación duradera, el SDK sigue la secuencia a continuación:

1. **Comprueba si hay un punto de control existente:** el SDK comprueba si esta operación ya se completó en una invocación anterior. Si existe un punto de control, el SDK devuelve el resultado almacenado sin volver a ejecutar la operación.

1. **Ejecuta la operación:** si no existe ningún punto de control, el SDK ejecuta el código de la operación. En cuanto a los pasos, esto significa llamar a la función. En cuanto a las esperas, esto significa programar la reanudación.

1. **Crea un punto de control:** una vez completada la operación, el SDK serializa el resultado y crea un punto de control. El punto de control incluye el tipo de operación, el nombre, las entradas, el resultado y la marca de tiempo.

1. **Conserva el punto de control:** el SDK llama a la API del punto de control de Lambda para conservar el punto de control. Esto garantiza que el punto de control sea duradero antes de continuar con la ejecución.

1. **Devuelve el resultado:** el SDK devuelve el resultado de la operación a su código, que continúa hasta la siguiente operación.

Esta secuencia garantiza que, una vez completada una operación, su resultado se almacene de forma segura. Si la función se interrumpe en algún momento, el SDK puede reproducir hasta el último punto de control completado.

## Comportamiento de reproducción
<a name="durable-sdk-replay-behavior"></a>

Cuando la función se reanuda tras una pausa o interrupción, el SDK realiza la reproducción.

1. **Carga el registro de puntos de control:** el SDK recupera el registro de puntos de control para esta ejecución de Lambda.

1. **Ejecuta desde el principio:** el SDK invoca la función de controlador desde el principio, no desde donde se detuvo.

1. **Omite las operaciones duraderas completadas:** como su código llama a las operaciones duraderas, el SDK compara cada una de ellas con el registro de puntos de control. En el caso de operaciones duraderas completadas, el SDK devuelve el resultado almacenado sin ejecutar el código de la operación.
**nota**  
Si el resultado de un contexto secundario supera el tamaño máximo del punto de control (256 KB), el código del contexto se vuelve a ejecutar durante la reproducción. Esto le permite elaborar grandes resultados a partir de las operaciones duraderas que se ejecutaron dentro del contexto, que se consultarán en el registro de puntos de control. Por lo tanto, es imperativo ejecutar solo código determinista en el contexto mismo. Cuando se utilizan contextos secundarios con resultados de gran tamaño, la práctica recomendada es realizar trabajos de larga duración o no deterministas dentro de los pasos y llevar a cabo únicamente tareas de corta duración que combinen los resultados en el propio contexto.

1. **Reanuda en el punto de interrupción:** cuando el SDK llega a una operación sin un punto de control, se ejecuta con normalidad y crea nuevos puntos de control a medida que se completan las operaciones duraderas.

Este mecanismo de reproducción requiere que el código sea determinista. Con las mismas entradas y el mismo registro de puntos de control, la función debe realizar la misma secuencia de llamadas a operaciones duraderas. El SDK lo impone al validar que los nombres y tipos de operaciones coincidan con el registro de puntos de control durante la reproducción.

## Operaciones duraderas disponibles
<a name="durable-sdk-operations"></a>

El `DurableContext` proporciona operaciones para diferentes patrones de coordinación. Cada operación duradera crea puntos de control automáticamente, lo que garantiza que la función pueda reanudarse desde cualquier punto.

### Steps
<a name="durable-sdk-op-step"></a>

Ejecuta la lógica empresarial con creación automática de puntos de control y hace un reintento. Siga estos pasos para las operaciones que llaman a servicios externos, realizan cálculos o ejecutan cualquier lógica que deba comprobarse. El SDK crea un punto de control antes y después del paso y almacena el resultado para reproducirlo.

------
#### [ TypeScript ]

```
const result = await context.step('process-payment', async () => {
  return await paymentService.charge(amount);
});
```

------
#### [ Python ]

```
result = context.step(
    lambda _: payment_service.charge(amount),
    name='process-payment'
)
```

------
#### [ Java (Preview) ]

```
var result = context.step("process-payment", Payment.class, 
    () -> paymentService.charge(amount)
);
```

------

Los pasos admiten estrategias de reintentos configurables, semánticas de ejecución (como máximo una vez o como mínimo una vez) y serialización personalizada.

### Esperas
<a name="durable-sdk-op-wait"></a>

Pausa la ejecución durante un tiempo específico sin consumir recursos de cómputo. El SDK crea un punto de control, finaliza la invocación de la función y programa la reanudación. Cuando finaliza la espera, Lambda vuelve a invocar la función, y el SDK reproduce el punto de espera antes de continuar.

------
#### [ TypeScript ]

```
// Wait 1 hour without charges
await context.wait({ seconds: 3600 });
```

------
#### [ Python ]

```
# Wait 1 hour without charges
context.wait(3600)
```

------
#### [ Java (Preview) ]

```
// Wait 1 hour without charges
context.wait(Duration.ofHours(1));
```

------

### Devoluciones de llamada
<a name="durable-sdk-op-callback"></a>

Las devoluciones de llamada permiten que la función haga una pausa y espere a que los sistemas externos envíen información. Cuando crea una devolución de llamada, el SDK genera un identificador de devolución de llamada único y crea un punto de control. A continuación, la función suspende (finaliza la invocación) sin incurrir en gastos de cómputo. Los sistemas externos envían los resultados de las devoluciones de llamada mediante las API de `SendDurableExecutionCallbackSuccess` o `SendDurableExecutionCallbackFailure` de Lambda. Cuando se envía una devolución de llamada, Lambda vuelve a invocar la función, el SDK la reproduce en el punto de devolución de llamada, y la función continúa con el resultado de la devolución de llamada.

El SDK proporciona dos métodos para trabajar con las devoluciones de llamada:

**createCallback:** crea una devolución de llamada y devuelve tanto una promesa como un identificador de devolución de llamada. El identificador de devolución de llamada se envía a un sistema externo, que envía el resultado mediante la API de Lambda.

------
#### [ TypeScript ]

```
const [promise, callbackId] = await context.createCallback('approval', {
  timeout: { hours: 24 }
});

await sendApprovalRequest(callbackId, requestData);
const approval = await promise;
```

------
#### [ Python ]

```
callback = context.create_callback(
    name='approval',
    config=CallbackConfig(timeout_seconds=86400)
)

context.step(
    lambda _: send_approval_request(callback.callback_id),
    name='send_request'
)

approval = callback.result()
```

------
#### [ Java (Preview) ]

```
var config = CallbackConfig.builder(Duration.ofHours(24)).timeout()

var callback = context.createCallback("approval", String.class, config);

context.step("send-request", String.class, () -> {
    notificationService.sendApprovalRequest(callback.callbackId(), requestData);
    return "request-sent";
});

// Blocks until the callback finishes or times out
String approval = callback.get();
```

------

**waitForCallback:** simplifica la gestión de las devoluciones de llamada al combinar la creación y el envío de las devoluciones de llamada en una sola operación. El SDK crea la devolución de llamada, ejecuta la función de remitente con el identificador de devolución de llamada y espera el resultado.

------
#### [ TypeScript ]

```
const result = await context.waitForCallback(
  'external-api',
  async (callbackId, ctx) => {
    await submitToExternalAPI(callbackId, requestData);
  },
  { timeout: { minutes: 30 } }
);
```

------
#### [ Python ]

```
result = context.wait_for_callback(
    lambda callback_id: submit_to_external_api(callback_id, request_data),
    name='external-api',
    config=WaitForCallbackConfig(timeout_seconds=1800)
)
```

------
#### [ Java (Preview) ]

waitForCallback aún está en desarrollo para Java.

------

Configura los tiempos de espera para evitar que las funciones esperen indefinidamente. Si se agota el tiempo de espera de una devolución de llamada, el SDK emitirá un `CallbackError` y la función podrá gestionar el tiempo de espera. Utilice los tiempos de espera de latido para las devoluciones de llamada de larga duración y para detectar cuándo los sistemas externos dejan de responder.

Utilice la devolución de llamada para los flujos de trabajo con intervención humana, la integración de sistemas externos, las respuestas a webhooks o cualquier situación en la que la ejecución deba hacer una pausa debido a una intervención externa.

### Ejecución en paralelo
<a name="durable-sdk-op-parallel"></a>

Ejecuta varias operaciones de forma simultánea con el control de concurrencia opcional. El SDK gestiona la ejecución paralela, crea puntos de control para cada operación y gestiona los errores de acuerdo con su política de finalización.

------
#### [ TypeScript ]

```
const results = await context.parallel([
  async (ctx) => ctx.step('task1', async () => processTask1()),
  async (ctx) => ctx.step('task2', async () => processTask2()),
  async (ctx) => ctx.step('task3', async () => processTask3())
]);
```

------
#### [ Python ]

```
results = context.parallel(
    lambda ctx: ctx.step(lambda _: process_task1(), name='task1'),
    lambda ctx: ctx.step(lambda _: process_task2(), name='task2'),
    lambda ctx: ctx.step(lambda _: process_task3(), name='task3')
)
```

------
#### [ Java (Preview) ]

Parallel aún está en desarrollo para Java.

------

Utilice `parallel` para ejecutar operaciones independientes de forma simultánea.

### Asignación
<a name="durable-sdk-op-map"></a>

Ejecute simultáneamente una operación en cada elemento de una matriz con el control de concurrencia opcional. El SDK gestiona la ejecución simultánea, crea puntos de control para cada operación y gestiona los errores de acuerdo con su política de finalización.

------
#### [ TypeScript ]

```
const results = await context.map(itemArray, async (ctx, item, index) =>
  ctx.step('task', async () => processItem(item, index))
);
```

------
#### [ Python ]

```
results = context.map(
    item_array,
    lambda ctx, item, index: ctx.step(
        lambda _: process_item(item, index),
        name='task'
    )
)
```

------
#### [ Java (Preview) ]

Map aún está en desarrollo para Java.

------

Utilice `map` para procesar matrices con control de concurrencia.

### Contextos secundarios
<a name="durable-sdk-op-child-context"></a>

Crea un contexto de ejecución aislado para agrupar operaciones. Los contextos secundarios tienen su propio registro de puntos de control y pueden contener varios pasos, esperas y otras operaciones. El SDK trata todo el contexto secundario como una sola unidad de reintento y recuperación.

Utilice los contextos secundarios para organizar flujos de trabajo complejos, implementar subflujos de trabajo o aislar operaciones que deberían reintentarse juntas.

------
#### [ TypeScript ]

```
const result = await context.runInChildContext(
  'batch-processing',
  async (childCtx) => {
    return await processBatch(childCtx, items);
  }
);
```

------
#### [ Python ]

```
result = context.run_in_child_context(
    lambda child_ctx: process_batch(child_ctx, items),
    name='batch-processing'
)
```

------
#### [ Java (Preview) ]

```
var result = context.runInChildContext(
    "batch-processing", 
    String.class, 
    childCtx -> process_batch(childCtx, items)
);
```

------

El mecanismo de reproducción exige que las operaciones duraderas se realicen en un orden determinista. Cuando se utilizan varios contextos secundarios, se pueden ejecutar varios flujos de trabajo de forma simultánea, y el determinismo se aplica por separado dentro de cada contexto. Esto le permite crear funciones de alto rendimiento que utilizan de manera eficiente varios núcleos de CPU.

Por ejemplo, imagine que iniciamos dos contextos secundarios, A y B. En la invocación inicial, los pasos dentro de los contextos se ejecutaron en este orden, y los pasos «A» se ejecutaron simultáneamente con los pasos «B»: A1, B1, B2, A2, A3. Tras la reproducción, el tiempo es mucho más rápido, ya que los resultados se recuperan del registro del punto de control y los pasos se encuentran en un orden diferente: B1, A1, A2, B2, A3. Como los pasos «A» se encontraron en el orden correcto (A1, A2, A3) y los pasos «B» se encontraron en el orden correcto (B1, B2), la necesidad de determinismo quedó satisfecha correctamente.

### Esperas condicionales
<a name="durable-sdk-op-wait-condition"></a>

Sondea una condición con creación automática de puntos de control entre intentos. El SDK ejecuta la función de verificación, crea un punto de control con el resultado, espera según la estrategia y se repite hasta que se cumpla la condición.

------
#### [ TypeScript ]

```
const result = await context.waitForCondition(
  async (state, ctx) => {
    const status = await checkJobStatus(state.jobId);
    return { ...state, status };
  },
  {
    initialState: { jobId: 'job-123', status: 'pending' },
    waitStrategy: (state) => 
      state.status === 'completed' 
        ? { shouldContinue: false }
        : { shouldContinue: true, delay: { seconds: 30 } }
  }
);
```

------
#### [ Python ]

```
result = context.wait_for_condition(
    lambda state, ctx: check_job_status(state['jobId']),
    config=WaitForConditionConfig(
        initial_state={'jobId': 'job-123', 'status': 'pending'},
        wait_strategy=lambda state, attempt: 
            {'should_continue': False} if state['status'] == 'completed'
            else {'should_continue': True, 'delay': 30}
    )
)
```

------
#### [ Java (Preview) ]

waitForCondition aún está en desarrollo para Java.

------

Utilice `waitForCondition` para sondear sistemas externos, esperar a que los recursos estén listos o implementar el reintento con retroceso.

### Invocación de función
<a name="durable-sdk-op-invoke"></a>

Invoca otra función de Lambda y espera su resultado. El SDK crea un punto de control, invoca la función de destino y reanuda la función cuando se completa la invocación. Esto habilita la composición de funciones y la descomposición del flujo de trabajo.

------
#### [ TypeScript ]

```
const result = await context.invoke(
  'invoke-processor',
  'arn:aws:lambda:us-east-1:123456789012:function:processor:1',
  { data: inputData }
);
```

------
#### [ Python ]

```
result = context.invoke(
    'arn:aws:lambda:us-east-1:123456789012:function:processor:1',
    {'data': input_data},
    name='invoke-processor'
)
```

------
#### [ Java (Preview) ]

```
var result = context.invoke(
    "invoke-processor", 
    "arn:aws:lambda:us-east-1:123456789012:function:processor:1",
    inputData,
    Result.class, 
    InvokeConfig.builder().build()
);
```

------

## Cómo se mide la durabilidad de las operaciones
<a name="durable-operations-checkpoint-consumption"></a>

Cada operación duradera a la que llama mediante `DurableContext` crea puntos de control para seguir el progreso de la ejecución y almacenar los datos de estado. Estas operaciones incurren en gastos en función de su uso, y los puntos de control pueden contener datos que contribuyen a los costos de escritura y retención de datos. Los datos almacenados incluyen los datos de los eventos de invocación, las cargas útiles devueltas por los pasos y los datos transferidos cuando se realizan las devoluciones de llamada. Comprender cómo se miden las operaciones duraderas lo ayudará a estimar los costos de ejecución y a optimizar sus flujos de trabajo. Consulte la página de [Precios de Lambda](https://aws.amazon.com/lambda/pricing/) para obtener información sobre precios.

El tamaño de la carga útil se refiere al tamaño de los datos serializados que conserva una operación duradera. Los datos se miden en bytes, y el tamaño puede variar según el serializador utilizado por la operación. La carga útil de una operación podría ser el resultado en sí mismo de una finalización exitosa o el objeto de error serializado si la operación fallara.

### Operaciones básicas
<a name="durable-operations-basic"></a>

Las operaciones básicas son los componentes fundamentales de las funciones duraderas:


| Operación | Temporización de los puntos de control | Número de operaciones | Persistencia de datos | 
| --- | --- | --- | --- | 
| Ejecución | Started | 1 | Tamaño de carga útil de entrada | 
| Ejecución | Completado (satisfactorio/fallido/detenido) | 0 | Tamaño de carga útil de salida | 
| N.° de paso | Reintento/satisfactorio/fallido | 1 \$1 N reintentos | Se devolvió el tamaño de la carga útil de cada intento. | 
| Espere | Started | 1 | N/A | 
| WaitForCondition | Cada intento de sondeo | 1 \$1 N sondeos | Se devolvió el tamaño de la carga útil de cada intento de sondeo. | 
| Reintento a nivel de invocación | Started | 1 | Carga útil del objeto de error | 

### Operaciones de devolución de llamada
<a name="durable-operations-callbacks"></a>

Las operaciones de devolución de llamada permiten que la función haga una pausa y espere a que los sistemas externos envíen información. Estas operaciones crean puntos de control cuando se crea la devolución de llamada y cuando se completa:


| Operación | Temporización de los puntos de control | Número de operaciones | Persistencia de datos | 
| --- | --- | --- | --- | 
| CreateCallback | Started | 1 | N/A | 
| Finalización de la devolución de llamada mediante una llamada a la API | Completado | 0 | Carga útil de devolución de llamada | 
| WaitForCallback | Started | 3 \$1 N reintentos (contexto \$1 devolución de llamada \$1 paso) | Cargas útiles devueltas por los intentos de paso del remitente, más dos copias de la carga útil de devolución de llamada | 

### Operaciones compuestas
<a name="durable-operations-compound"></a>

Las operaciones compuestas combinan múltiples operaciones duraderas para gestionar patrones de coordinación complejos, como la ejecución paralela, el procesamiento de matrices y los contextos anidados:


| Operación | Temporización de los puntos de control | Número de operaciones | Persistencia de datos | 
| --- | --- | --- | --- | 
| Parallel | Started | 1 \$1 N ramificaciones (1 contexto principal \$1 N contextos secundarios) | Hasta dos copias del tamaño de la carga útil devuelta por cada ramificación, más los estados de cada ramificación | 
| Asignación | Started | 1 \$1 N ramificaciones (1 contexto principal \$1 N contextos secundarios) | Hasta dos copias del tamaño de la carga útil devuelta por cada iteración, más los estados de cada iteración | 
| Ayudantes de promesas | Completado | 1 | El tamaño de la carga útil devuelto según la promesa | 
| RunInChildContext | Satisfactorio/fallido | 1 | El tamaño de la carga útil devuelto desde el contexto secundario | 

En el caso de contextos, como los procedentes de `runInChildContext` o utilizados internamente por operaciones compuestas, los resultados de menos de 256 KB se controlan directamente mediante puntos de control. Los resultados más grandes no se almacenan, sino que se reconstruyen durante la reproducción mediante el reprocesamiento de las operaciones del contexto.

# Tiempos de ejecución compatibles con funciones duraderas
<a name="durable-supported-runtimes"></a>

Las funciones duraderas están disponibles para determinados tiempos de ejecución administrados e imágenes de contenedor OCI, lo que ofrece mayor flexibilidad en las versiones de tiempo de ejecución. Puede crear funciones duraderas para Node.js y Python mediante tiempos de ejecución administrados directamente en la consola o de forma programática mediante infraestructura como código. Actualmente, las funciones duraderas en Java (versión preliminar) solo pueden implementarse mediante imágenes de contenedor.

## Tiempos de ejecución administrados de Lambda
<a name="durable-managed-runtimes"></a>

Los siguientes tiempos de ejecución administrados admiten funciones duraderas cuando crea funciones en la consola de Lambda o utiliza la AWS CLI con el parámetro `--durable-config '{"ExecutionTimeout": 3600, "RetentionPeriodInDays": 7}'`. Para obtener información completa sobre los tiempos de ejecución de Lambda, consulte [Tiempos de ejecución de Lambda](lambda-runtimes.md).


| Idioma | Tiempo de ejecución | 
| --- | --- | 
| Node.js | nodejs22.x | 
| Node.js | nodejs24.x | 
| Python | python3.13 | 
| Python | python3.14 | 

**nota**  
Los tiempos de ejecución de Lambda incluyen el SDK de ejecución duradera para pruebas y desarrollo. Sin embargo, le recomendamos incluir el SDK en su paquete de implementación para producción. Esto garantiza la coherencia de las versiones y evita posibles actualizaciones del tiempo de ejecución que podrían afectar el comportamiento de su función.

### Node.js
<a name="durable-runtime-nodejs"></a>

Instale el SDK en su proyecto de Node.js:

```
npm install @aws/durable-execution-sdk-js
```

El SDK es compatible con JavaScript y TypeScript. Para los proyectos de TypeScript, el SDK incluye definiciones de tipos.

### Python
<a name="durable-runtime-python"></a>

Instale el SDK en el proyecto de Python:

```
pip install aws-durable-execution-sdk-python
```

El SDK para Python usa métodos sincrónicos y no requiere `async/await`.

### Java (versión preliminar)
<a name="durable-runtime-java"></a>

Agregue una dependencia a `pom.xml`:

```
<dependency>
    <groupId>software.amazon.lambda.durable</groupId>
    <artifactId>aws-durable-execution-sdk-java</artifactId>
    <version>VERSION</version>
</dependency>
```

Instale el SDK en su proyecto de Java:

```
mvn install
```

Hay disponible una versión preliminar del SDK de Java. Las operaciones waitForCondition, waitForCallback, parallel y map aún están en desarrollo.

## Imágenes de contenedor
<a name="durable-container-images"></a>

Puede utilizar funciones duraderas con imágenes de contenedor para admitir versiones del tiempo de ejecución adicionales o configuraciones del tiempo de ejecución personalizadas. Las imágenes de contenedor le permiten usar versiones de tiempo de ejecución que no están disponibles como tiempos de ejecución administrados o personalizar su entorno del tiempo de ejecución.

Cómo crear una función duradera con una imagen de contenedor

1. Cree un Dockerfile basado en una imagen base de Lambda.

1. Instale el SDK de ejecución duradera en su contenedor.

1. Cree y envíe la imagen del contenedor a Amazon Elastic Container Registry.

1. Cree la función de Lambda a partir de la imagen de contenedor con la ejecución duradera habilitada.

### Ejemplo de contenedor
<a name="durable-container-python"></a>

Cree un archivo Dockerfile:

------
#### [ Python ]

Cree un Dockerfile para Python 3.11:

```
FROM public.ecr.aws/lambda/python:3.11

# Copy requirements file
COPY requirements.txt ${LAMBDA_TASK_ROOT}/

# Install dependencies including durable SDK
RUN pip install -r requirements.txt

# Copy function code
COPY lambda_function.py ${LAMBDA_TASK_ROOT}/

# Set the handler
CMD [ "lambda_function.handler" ]
```

Cree un archivo de `requirements.txt`:

```
aws-durable-execution-sdk-python
```

------
#### [ Java (Preview) ]

Cree un Dockerfile para Java 25:

```
FROM --platform=linux/amd64 public.ecr.aws/lambda/java:25

# Install Maven
RUN dnf install -y maven

WORKDIR /var/task

# Copy Maven configuration and source code
COPY pom.xml .
COPY src ./src

# Build
RUN mvn clean package -DskipTests

# Move JAR to lib directory
RUN mv target/*.jar lib/

# Set the handler
CMD ["src.path.to.lambdaFunction::handler"]
```

------

Cree y envíe la imagen:

```
# Build the image
docker build -t my-durable-function .

# Tag for ECR
docker tag my-durable-function:latest 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-durable-function:latest

# Push to ECR
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-durable-function:latest
```

Cree la función con la ejecución duradera habilitada:

```
aws lambda create-function \
  --function-name myDurableFunction \
  --package-type Image \
  --code ImageUri=123456789012.dkr.ecr.us-east-1.amazonaws.com/my-durable-function:latest \
  --role arn:aws:iam::123456789012:role/lambda-execution-role \
  --durable-config '{"ExecutionTimeout": 3600, "RetentionPeriodInDays": 7}'
```

Para obtener más información acerca del uso de imágenes de contenedor con Lambda, consulte [Creación de imágenes de contenedor](https://docs.aws.amazon.com/lambda/latest/dg/images-create.html) en la Guía para desarrolladores de Lambda.

## Consideraciones sobre el tiempo de ejecución
<a name="durable-runtime-considerations"></a>

**Administración de versiones del SDK:** incluya el SDK de ejecución duradera en su paquete de implementación o imagen de contenedor. Esto garantiza que la función utilice una versión específica del SDK y no se vea afectada por las actualizaciones del tiempo de ejecución. Fije las versiones del SDK en el `package.json` o `requirements.txt` para controlar cuándo se actualiza.

**Actualizaciones del tiempo de ejecución:** AWS actualiza los tiempos de ejecución administrados para incluir parches de seguridad y correcciones de errores. Estas actualizaciones pueden incluir nuevas versiones del SDK. Para evitar comportamientos inesperados, incluya el SDK en su paquete de implementación y pruébelo minuciosamente antes de implementarlo en producción.

**Tamaño de la imagen de contenedor:** las imágenes de contenedor tienen un tamaño máximo sin comprimir de 10 GB. El SDK de ejecución duradera añade un tamaño mínimo a la imagen. Optimice su contenedor mediante compilaciones de varias etapas y la eliminación de dependencias innecesarias.

**Rendimiento de arranque en frío:** las imágenes de contenedor pueden tener tiempos de arranque en frío más prolongados que los tiempos de ejecución administrados. El SDK de ejecución duradera tiene un impacto mínimo en el rendimiento del arranque en frío. Utilice la concurrencia aprovisionada si la latencia del arranque en frío es fundamental para su aplicación.

# Invocación de funciones duraderas de Lambda
<a name="durable-invoking"></a>

Las funciones duraderas de Lambda admiten los mismos métodos de invocación que las funciones estándar de Lambda. Puede invocar funciones duraderas de forma sincrónica, asíncrona o mediante asignaciones de orígenes de eventos. El proceso de invocación es idéntico al de las funciones estándar, pero las funciones duraderas proporcionan capacidades adicionales para las ejecuciones de larga duración y la administración automática del estado.

## Métodos de invocación
<a name="durable-invoking-methods"></a>

**Invocación sincrónica:** invoca una función duradera y espera la respuesta. Lambda limita las invocaciones sincrónicas a 15 minutos (o menos, según la función configurada y el tiempo de espera de ejecución). Utilice la invocación sincrónica cuando necesite resultados inmediatos o cuando se integre con API y servicios que esperan una respuesta. Puede utilizar las operaciones de espera para un cómputo eficiente sin interrumpir a la persona que llama; la invocación espera a que se complete toda la ejecución duradera. Para que se inicie una ejecución idempotente, utilice el parámetro del nombre de la ejecución, como se describe en [Idempotencia](durable-execution-idempotency.md).

```
aws lambda invoke \
  --function-name my-durable-function:1 \
  --cli-binary-format raw-in-base64-out \
  --payload '{"orderId": "12345"}' \
  response.json
```

**Invocación asíncrona:** coloca un evento en cola para su procesamiento sin esperar una respuesta. Lambda coloca el evento en una cola y lo devuelve de inmediato. Las invocaciones asíncronas admiten duraciones de ejecución de hasta 1 año como máximo. Utilice la invocación asíncrona en situaciones de tipo «disparar y olvidar», o cuando el procesamiento pueda realizarse en segundo plano. Para que se inicie una ejecución idempotente, utilice el parámetro del nombre de la ejecución, como se describe en [Idempotencia](durable-execution-idempotency.md).

```
aws lambda invoke \
  --function-name my-durable-function:1 \
  --invocation-type Event \
  --cli-binary-format raw-in-base64-out \
  --payload '{"orderId": "12345"}' \
  response.json
```

**Asignaciones de orígenes de eventos:** configure Lambda para que invoque automáticamente la función duradera cuando haya registros disponibles en servicios basados en colas o flujos, como Amazon SQS, Kinesis o DynamoDB. Las asignaciones de orígenes de eventos sondean el origen de eventos e invocan su función con lotes de registros. Para obtener más información sobre el uso de las asignaciones de orígenes de eventos con funciones duraderas, incluidos los límites de duración de la ejecución, consulte [Asignaciones de orígenes de eventos con funciones duraderas](durable-invoking-esm.md).

Para obtener información completa sobre cada método de invocación, consulte [invocación sincrónica](invocation-sync.md) e [invocación asíncrona](invocation-async.md).

**nota**  
Las funciones duraderas admiten colas de mensajes fallidos (DLQ) para la gestión de errores, pero no admiten destinos de Lambda. Configure una DLQ para capturar los registros de las invocaciones fallidas.

## Requerimiento de ARN calificados
<a name="durable-invoking-qualified-arns"></a>

Las funciones duraderas requieren identificadores calificados para la invocación. Debe invocar funciones duraderas con un número de versión, un alias o `$LATEST`. Puede utilizar un ARN calificado completo o un nombre de función con el sufijo de versión/alias. No puede utilizar un identificador no calificado (sin un sufijo de versión o alias).

**Invocaciones válidas:**

```
# Using full ARN with version number
arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1

# Using full ARN with alias
arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:prod

# Using full ARN with $LATEST
arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:$LATEST

# Using function name with version number
my-durable-function:1

# Using function name with alias
my-durable-function:prod
```

**Invocaciones inválidas:**

```
# Unqualified ARN (not allowed)
arn:aws:lambda:us-east-1:123456789012:function:my-durable-function

# Unqualified function name (not allowed)
my-durable-function
```

Este requisito garantiza que las ejecuciones duraderas se mantengan consistentes durante todo su ciclo de vida. Cuando se inicia una ejecución duradera, se fija en la versión de la función específica. Si la función se detiene y se reanuda horas o días después, Lambda invoca la misma versión que inició la ejecución, lo que garantiza la coherencia del código en todo el flujo de trabajo.

**Práctica recomendada**  
En lugar de utilizar `$LATEST`, utilice versiones numeradas o alias para las funciones duraderas de producción. Las versiones numeradas son inmutables y admiten una reproducción determinista. Opcionalmente, los alias proporcionan una referencia estable que se puede actualizar para que apunte a nuevas versiones sin cambiar el código de invocación. Cuando actualiza un alias, las nuevas ejecuciones utilizan la nueva versión, mientras que las ejecuciones en curso continúan con su versión original. Puede utilizar `$LATEST` para crear prototipos o acortar los tiempos de implementación durante el desarrollo; debe tener en cuenta que las ejecuciones podrían no reproducirse correctamente (o incluso fallar) si el código subyacente cambia durante las ejecuciones en ejecución.

## Descripción del ciclo de vida de una ejecución
<a name="durable-invoking-execution-lifecycle"></a>

Cuando invoca una función duradera, Lambda crea una ejecución duradera que puede abarcar múltiples invocaciones de funciones:

1. **Invocación inicial:** su solicitud de invocación crea una nueva ejecución duradera. Lambda asigna un identificador de ejecución único e inicia el procesamiento.

1. **Ejecución y puntos de control:** a medida que su función ejecuta operaciones duraderas, el SDK crea puntos de control para seguir el progreso.

1. **Suspensión (si es necesaria):** si la función utiliza esperas duraderas, como `wait` o `waitForCallback`, o reintentos automáticos por pasos, Lambda suspende la ejecución y deja de cobrar por el tiempo de cómputo.

1. **Reanudación:** cuando llega el momento de la reanudación (incluso después de los reintentos), Lambda vuelve a invocar la función. El SDK reproduce el registro de puntos de control y continúa desde donde se detuvo la ejecución.

1. **Finalización:** cuando la función devuelve un resultado final o arroja un error no controlado, se completa la ejecución duradera.

Para las invocaciones sincrónicas, la persona que llama espera a que se complete toda la ejecución duradera, incluidas las operaciones de espera. Si la ejecución supera el tiempo de espera de la invocación (15 minutos o menos), se agota el tiempo de espera de la invocación. Para las invocaciones asíncronas, Lambda regresa de inmediato, y la ejecución continúa de forma independiente. Utilice las API de ejecución duradera para realizar un seguimiento del estado de la ejecución y recuperar los resultados finales.

## Invocación desde el código de la aplicación
<a name="durable-invoking-with-sdk"></a>

Utilice los AWS SDK para invocar funciones duraderas desde el código de la aplicación. El proceso de invocación es idéntico al de las funciones estándar:

------
#### [ TypeScript ]

```
import { LambdaClient, InvokeCommand } from '@aws-sdk/client-lambda';

const client = new LambdaClient({});

// Synchronous invocation
const response = await client.send(new InvokeCommand({
  FunctionName: 'arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1',
  Payload: JSON.stringify({ orderId: '12345' })
}));

const result = JSON.parse(Buffer.from(response.Payload!).toString());

// Asynchronous invocation
await client.send(new InvokeCommand({
  FunctionName: 'arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1',
  InvocationType: 'Event',
  Payload: JSON.stringify({ orderId: '12345' })
}));
```

------
#### [ Python ]

```
import boto3
import json

client = boto3.client('lambda')

# Synchronous invocation
response = client.invoke(
    FunctionName='arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1',
    Payload=json.dumps({'orderId': '12345'})
)

result = json.loads(response['Payload'].read())

# Asynchronous invocation
client.invoke(
    FunctionName='arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1',
    InvocationType='Event',
    Payload=json.dumps({'orderId': '12345'})
)
```

------

## Invocaciones encadenadas
<a name="durable-invoking-chained"></a>

Las funciones duraderas pueden invocar otras funciones duraderas y no duraderas mediante la operación `invoke` desde `DurableContext`. Esto crea una invocación encadenada en la que la función de llamada espera (suspende) a que se complete la función invocada:

------
#### [ TypeScript ]

```
export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    // Invoke another durable function and wait for result
    const result = await context.invoke(
      'process-order',
      'arn:aws:lambda:us-east-1:123456789012:function:order-processor:1',
      { orderId: event.orderId }
    );
    
    return { statusCode: 200, body: JSON.stringify(result) };
  }
);
```

------
#### [ Python ]

```
@durable_execution
def handler(event, context: DurableContext):
    # Invoke another durable function and wait for result
    result = context.invoke(
        'arn:aws:lambda:us-east-1:123456789012:function:order-processor:1',
        {'orderId': event['orderId']},
        name='process-order'
    )
    
    return {'statusCode': 200, 'body': json.dumps(result)}
```

------

Las invocaciones encadenadas crean un punto de control en la función de llamada. Si la función de llamada se interrumpe, se reanuda desde el punto de control con el resultado de la función invocada, sin volver a invocarla.

**nota**  
No se admiten invocaciones encadenadas entre cuentas. La función invocada debe estar en la misma cuenta de AWS que la función de llamada.

# Asignaciones de orígenes de eventos con funciones duraderas
<a name="durable-invoking-esm"></a>

Las funciones duraderas funcionan con todas las asignaciones de orígenes de eventos de Lambda. Configure las asignaciones de orígenes de eventos para funciones duraderas del mismo modo que las configura para funciones estándar. Las asignaciones de orígenes de eventos sondean automáticamente los orígenes de eventos, como Amazon SQS, Kinesis y DynamoDB Streams, e invocan su función con lotes de registros.

Las asignaciones de orígenes de eventos son útiles para funciones duraderas que procesan flujos o colas con flujos de trabajo complejos de varios pasos. Por ejemplo, puede crear una función duradera que procese los mensajes de Amazon SQS con reintentos, llamadas a la API externas y aprobaciones humanas.

## Cómo invocar asignaciones de orígenes de eventos con funciones duraderas
<a name="durable-esm-invocation-behavior"></a>

Las asignaciones de orígenes de eventos invocan funciones duraderas de forma sincrónica; por ello, esperan a que finalice la ejecución duradera completa antes de procesar el siguiente lote o marcar los registros como procesados. Si el tiempo total de la ejecución duradera supera los 15 minutos, se agota el tiempo de espera de la ejecución y se produce un error. La asignación de orígenes de eventos recibe una excepción de tiempo de espera y la gestiona de acuerdo con su configuración de reintentos.

## Límite de ejecución de 15 minutos
<a name="durable-esm-duration-limit"></a>

Cuando las asignaciones de orígenes de eventos invocan funciones duraderas, la duración total de la ejecución duradera no puede superar los 15 minutos. Este límite se aplica a toda la ejecución duradera, desde el principio hasta la finalización, no solo a las invocaciones de funciones individuales.

Este límite de 15 minutos es independiente del tiempo de espera de la función de Lambda (también 15 minutos como máximo). El tiempo de espera de la función controla cuánto tiempo puede ejecutarse cada invocación individual, mientras que el tiempo de espera de la ejecución duradera controla el tiempo total transcurrido desde el inicio de la ejecución hasta su finalización.

**Ejemplos de escenarios:**
+ **Válido:** una función duradera procesa un mensaje de Amazon SQS en tres pasos, cada uno de los cuales dura 2 minutos, y luego espera 5 minutos antes de completar el último paso. Tiempo total de ejecución: 11 minutos. Esto funciona porque el total es inferior a 15 minutos.
+ **Inválido:** una función duradera procesa un mensaje de Amazon SQS, completa el procesamiento inicial en 2 minutos y luego espera 20 minutos por una devolución de llamada externa antes de completarlo. Tiempo total de ejecución: 22 minutos. Si se supera el límite de 15 minutos, se producirá un error.
+ **Inválido:** una función duradera procesa un registro de Kinesis con varias operaciones de espera que suman un total de 30 minutos entre los pasos. Aunque cada invocación individual se completa rápidamente, el tiempo total de ejecución supera los 15 minutos.

**importante**  
Configure el tiempo de espera de la ejecución duradera en 15 minutos o menos cuando utilice asignaciones de orígenes de eventos; de lo contrario, la creación de la asignación de orígenes de eventos fallará. Si su flujo de trabajo requiere tiempos de ejecución más prolongados, utilice el patrón de funciones intermedias que se describe a continuación.

## Configuración de asignaciones de orígenes de eventos
<a name="durable-esm-configuration"></a>

Configure las asignaciones de orígenes de eventos para funciones duraderas mediante la consola de Lambda, la AWS CLI, o los AWS SDK. Todas las propiedades de la asignación de orígenes de eventos estándar se aplican a las funciones duraderas:

```
aws lambda create-event-source-mapping \
  --function-name arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1 \
  --event-source-arn arn:aws:sqs:us-east-1:123456789012:my-queue \
  --batch-size 10 \
  --maximum-batching-window-in-seconds 5
```

Recuerde utilizar un ARN calificado (con número de versión o alias) cuando configure las asignaciones de orígenes de eventos para funciones duraderas.

## Gestión de errores con asignaciones de orígenes de eventos
<a name="durable-esm-error-handling"></a>

Las asignaciones de orígenes de eventos proporcionan una gestión de errores integrada compatible con funciones duraderas:
+ **Comportamiento de reintento:** si la invocación inicial falla, la asignación de orígenes de eventos hace un reintento de acuerdo con su configuración de reintentos. Configure el número máximo de reintentos y los intervalos de reintento en función de sus requisitos.
+ **Colas de mensajes fallidos:** configure una cola de mensajes fallidos para capturar los registros que fallan después de todos los reintentos. Esto evita la pérdida de mensajes y permite la inspección manual de los registros fallidos.
+ **Errores de lotes parciales:** en el caso de Amazon SQS y Kinesis, utilice los informes de errores de lotes parciales para procesar los registros de forma individual y reintentar solo los registros fallidos.
+ **Segmentado en caso de error:** en el caso de Kinesis y DynamoDB Streams, habilite el segmentado en caso de error para dividir los lotes fallidos y aislar los registros problemáticos.

**nota**  
Las funciones duraderas admiten colas de mensajes fallidos (DLQ) para la gestión de errores, pero no admiten destinos de Lambda. Configure una DLQ para capturar los registros de las invocaciones fallidas.

Para obtener información completa sobre la gestión de errores en la asignación de orígenes de eventos, consulte la [asignación de orígenes de eventos](invocation-eventsourcemapping.md).

## Uso de una función intermedia para flujos de trabajo de larga duración
<a name="durable-esm-intermediary-function"></a>

Si el flujo de trabajo requiere más de 15 minutos para completarse, utilice una función estándar intermedia de Lambda entre la asignación de orígenes de eventos y su función duradera. La función intermedia recibe los eventos de la asignación de orígenes de eventos e invoca la función duradera de forma asíncrona, lo que elimina el límite de ejecución de 15 minutos.

Este patrón desacopla el modelo de invocación sincrónica de la asignación de orígenes de eventos del modelo de ejecución de larga duración de la función duradera. La asignación de orígenes de eventos invoca la función intermedia, que regresa rápidamente después de iniciar la ejecución duradera. A continuación, la función duradera se ejecuta de forma independiente durante el tiempo que sea necesario (hasta 1 año).

### Arquitectura
<a name="durable-esm-intermediary-architecture"></a>

El patrón de funciones intermedias utiliza tres componentes:

1. **Asignación de orígenes de eventos:** sondea el origen de eventos (Amazon SQS, Kinesis, DynamoDB Streams) e invoca la función intermedia de forma sincrónica con lotes de registros.

1. **Función intermedia: ** función estándar de Lambda que recibe eventos de la asignación de orígenes de eventos, valida y transforma los datos (si es necesario) e invoca la función duradera de forma asíncrona. Esta función se completa rápidamente (en general en menos de 1 segundo) y devuelve el control a la asignación de orígenes de eventos.

1. **Función duradera:** procesa el evento con una lógica compleja de varios pasos que puede ejecutarse durante períodos prolongados. Se invoca de forma asíncrona, por lo que no está limitada por el límite de 15 minutos.

### Implementación
<a name="durable-esm-intermediary-implementation"></a>

La función intermedia recibe el evento completo de la asignación de orígenes de eventos e invoca la función duradera de forma asíncrona. Utilice el parámetro del nombre de la ejecución para garantizar que se inicie una ejecución idempotente, lo que evitará que se duplique el procesamiento si la asignación de orígenes de eventos hace un reintento:

------
#### [ TypeScript ]

```
import { LambdaClient, InvokeCommand } from '@aws-sdk/client-lambda';
import { SQSEvent } from 'aws-lambda';
import { createHash } from 'crypto';

const lambda = new LambdaClient({});

export const handler = async (event: SQSEvent) => {
  // Invoke durable function asynchronously with execution name
  await lambda.send(new InvokeCommand({
    FunctionName: 'arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1',
    InvocationType: 'Event',
    Payload: JSON.stringify({
      executionName: event.Name,
      event: event
    })
  }));
  
  return { statusCode: 200 };
};
```

------
#### [ Python ]

```
import boto3
import json
import hashlib

lambda_client = boto3.client('lambda')

def handler(event, context):  
    # Invoke durable function asynchronously with execution name
    lambda_client.invoke(
        FunctionName='arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1',
        InvocationType='Event',
        Payload=json.dumps({
            'executionName': execution_name,
            'event': event["name"]
        })
    )
    
    return {'statusCode': 200}
```

------

En el caso de la idempotencia en la propia función intermedia, utilice [Powertools para AWS Lambda](https://docs.aws.amazon.com//powertools/) para evitar que se dupliquen las invocaciones de la función duradera si la asignación de orígenes de eventos reintenta la función intermedia.

La función duradera recibe la carga útil con el nombre de la ejecución y procesa todos los registros con una lógica de larga duración:

------
#### [ TypeScript ]

```
import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js';

export const handler = withDurableExecution(
  async (payload: any, context: DurableContext) => {
    const sqsEvent = payload.event;
    
    // Process each record with complex, multi-step logic
    const results = await context.map(
      sqsEvent.Records,
      async (ctx, record) => {
        const validated = await ctx.step('validate', async () => {
          return validateOrder(JSON.parse(record.body));
        });
        
        // Wait for external approval (could take hours or days)
        const approval = await ctx.waitForCallback(
          'approval',
          async (callbackId) => {
            await requestApproval(callbackId, validated);
          },
          { timeout: { hours: 48 } }
        );
        
        // Complete processing
        return await ctx.step('complete', async () => {
          return completeOrder(validated, approval);
        });
      }
    );
    
    return { statusCode: 200, processed: results.getResults().length };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext
from aws_durable_execution_sdk_python.config import Duration, WaitForCallbackConfig
from collections.abc import Sequence
import json

def validate_order(order_data: dict) -> dict:
    """Validate order data - always passes."""
    return order_data

def request_approval(callback_id: str, validated_order: dict) -> None:
    """Request approval for the order - always passes."""
    pass

def complete_order(validated_order: dict, approval_result: str) -> dict:
    """Complete the order processing - always passes."""
    return validated_order

@durable_execution
def lambda_handler(payload, context: DurableContext):
    sqs_event = payload['event']

    def process_record(
        ctx: DurableContext, 
        record: dict, 
        index: int, 
        items: Sequence[dict]
    ) -> dict:
        validated = ctx.step(
            lambda _: validate_order(json.loads(record['body'])),
            name=f'validate-{index}'
        )

        approval = ctx.wait_for_callback(
            submitter=lambda callback_id, wait_ctx: request_approval(callback_id, validated),
            name=f'approval-{index}',
            config=WaitForCallbackConfig(timeout=Duration.from_seconds(172800))
        )

        return ctx.step(
            lambda _: complete_order(validated, approval),
            name=f'complete-{index}'
        )

    results = context.map(
        inputs=sqs_event['Records'],
        func=process_record,
        name='process-records'
    )

    return {
        'statusCode': 200, 
        'started': results.started_count,
        'completed': results.success_count,
        'failed': results.failure_count,
        'total': results.total_count
    }
```

------

### Consideraciones clave
<a name="durable-esm-intermediary-tradeoffs"></a>

Este patrón elimina el límite de ejecución de 15 minutos al desvincular la asignación de orígenes de eventos de la ejecución duradera. La función intermedia regresa inmediatamente después de iniciar la ejecución duradera, lo que permite que la asignación de orígenes de eventos continúe procesándose. A continuación, la función duradera se ejecuta de forma independiente durante el tiempo que sea necesario.

La función intermedia tiene éxito cuando invoca la función duradera, no cuando se completa la ejecución duradera. Si la ejecución duradera falla más adelante, la asignación de orígenes de eventos no hará un reintento porque ya procesó el lote correctamente. Implemente la gestión de errores en la función duradera y configure las colas de mensajes fallidos para las ejecuciones fallidas.

Utilice el parámetro del nombre de la ejecución para garantizar que se inicie una ejecución idempotente. Si la asignación de orígenes de eventos reintenta la función intermedia, la función duradera no iniciará una ejecución duplicada porque el nombre de la ejecución ya existe.

## Orígenes de eventos compatibles
<a name="durable-esm-supported-sources"></a>

Las funciones duraderas admiten todos los orígenes de eventos de Lambda que utilizan asignaciones de orígenes de eventos:
+ Colas de Amazon SQS (estándar y FIFO)
+ Flujos de Kinesis
+ DynamoDB Streams
+ Amazon Managed Streaming for Apache Kafka (Amazon MSK)
+ Apache Kafka autoadministrado
+ Amazon MQ (ActiveMQ y RabbitMQ)
+ Flujos de cambios de Amazon DocumentDB

Todos los tipos de orígenes de eventos están sujetos al límite de ejecución duradera de 15 minutos cuando se invocan funciones duraderas.

# Reintentos de funciones duraderas de Lambda
<a name="durable-execution-sdk-retries"></a>

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
<a name="durable-step-retries"></a>

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
<a name="durable-step-retry-behavior"></a>

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 \$1 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 \$1 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
<a name="durable-step-retry-configuration"></a>

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
<a name="durable-handler-exceptions"></a>

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
<a name="durable-backend-retries"></a>

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 vuelve a intentar automáticamente estos errores para ayudar a que las funciones duraderas se recuperen de problemas transitorios de infraestructura.

### Escenarios de reintentos en backend
<a name="durable-backend-retry-scenarios"></a>

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 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 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 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
<a name="durable-retry-best-practices"></a>

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.

# Idempotencia
<a name="durable-execution-idempotency"></a>

Las funciones duraderas proporcionan una idempotencia integrada para los inicios de la ejecución a través de los nombres de ejecución. Cuando proporciona un nombre de ejecución, Lambda lo usa para evitar ejecuciones duplicadas y habilitar reintentos seguros de las solicitudes de invocación. De forma predeterminada, los pasos tienen una semántica de ejecución de como mínimo una vez: durante la reproducción, el SDK devuelve los resultados comprobados sin volver a ejecutar los pasos completados, pero su lógica empresarial debe ser idempotente para gestionar los posibles reintentos antes de que se completen.

**nota**  
Las asignaciones de orígenes de eventos (ESM) de Lambda no admiten la idempotencia en el momento del lanzamiento. Por lo tanto, cada invocación (incluidos los reintentos) inicia una nueva ejecución duradera. Para garantizar una ejecución idempotente con asignaciones de orígenes de eventos, implemente la lógica de idempotencia en el código de su función, como con [Powertools para AWS Lambda](https://docs.aws.amazon.com//powertools/) o utilice una función de Lambda normal como proxy (despachador) para invocar una función duradera con una clave de idempotencia (parámetro del nombre de la ejecución).

## Nombres de ejecución
<a name="durable-idempotency-execution-names"></a>

Puede proporcionar un nombre de ejecución cuando invoca una función duradera. El nombre de la ejecución actúa como clave de idempotencia, lo que permite reintentar las solicitudes de invocación de forma segura sin crear ejecuciones duplicadas. Si no proporciona un nombre, Lambda genera automáticamente un identificador de ejecución único.

Los nombres de ejecución deben ser únicos dentro de su cuenta y región. Cuando invoca una función con un nombre de ejecución que ya existe, el comportamiento de Lambda depende del estado de la ejecución existente y de si la carga útil coincide.

## Comportamiento de idempotencia
<a name="durable-idempotency-behavior"></a>

En la siguiente tabla, se describe cómo Lambda gestiona las solicitudes de invocación en función de si proporciona un nombre de ejecución, el estado de ejecución existente y si la carga útil coincide:


| Escenario | ¿Se proporcionó un nombre? | Estado de ejecución existente | ¿Carga útil idéntica? | Comportamiento | 
| --- | --- | --- | --- | --- | 
| 1 | No | N/A | N/A | Nueva ejecución iniciada: Lambda genera un identificador de ejecución único e inicia una nueva ejecución. | 
| 2 | Sí | Nunca existió o la retención caducó. | N/A | Nueva ejecución iniciada: Lambda inicia una nueva ejecución con el nombre proporcionado. | 
| 3 | Sí | Ejecutar | Sí | Inicio idempotente: Lambda devuelve la información de ejecución existente sin iniciar un duplicado. En el caso de las invocaciones sincrónicas, esto actúa como una reconexión a la ejecución en ejecución. | 
| 4 | Sí | Ejecutar | No | Error: Lambda devuelve un error de DurableExecutionAlreadyExists porque ya se está ejecutando una ejecución con este nombre con una carga útil diferente. | 
| 5 | Sí | Cerrado (satisfactorio, fallido, detenido o agotado el tiempo de espera) | Sí | Inicio idempotente: Lambda devuelve la información de ejecución existente sin iniciar una nueva ejecución. Se devuelve el resultado de la ejecución cerrada. | 
| 6 | Sí | Cerrado (satisfactorio, fallido, detenido o agotado el tiempo de espera) | No | Error: Lambda devuelve un error de DurableExecutionAlreadyExists porque una ejecución con este nombre ya se completó con una carga útil diferente. | 

**Nota**  
Los escenarios 3 y 5 demuestran un comportamiento idempotente en el que Lambda gestiona de forma segura las solicitudes de invocación duplicadas al devolver la información de ejecución existente en lugar de crear duplicados.

## Idempotencia escalonada
<a name="durable-idempotency-steps"></a>

De forma predeterminada, los pasos tienen una semántica de ejecución de como mínimo una vez. Cuando la función se reproduce tras una espera, una devolución de llamada o un error, el SDK compara cada paso con el registro de los puntos de control. En el caso de los pasos que ya se hayan completado, el SDK devuelve el resultado del punto de control sin volver a ejecutar la lógica escalonada. Sin embargo, si un paso falla o la función se interrumpe antes de que se complete, es posible que el paso se ejecute varias veces.

Su lógica empresarial, encapsulada en pasos, debe ser idempotente para gestionar posibles reintentos. Utilice claves de idempotencia para asegurarse de que las operaciones como los pagos o la escritura de bases de datos se ejecuten solo una vez, incluso si se reintenta el paso.

**Ejemplo: uso de claves de idempotencia por pasos**

------
#### [ TypeScript ]

```
import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js';
import { randomUUID } from 'crypto';

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    // Generate idempotency key once
    const idempotencyKey = await context.step('generate-key', async () => {
      return randomUUID();
    });
    
    // Use idempotency key in payment API to prevent duplicate charges
    const payment = await context.step('process-payment', async () => {
      return paymentAPI.charge({
        amount: event.amount,
        idempotencyKey: idempotencyKey
      });
    });
    
    return { statusCode: 200, payment };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext
import uuid

@durable_execution
def handler(event, context: DurableContext):
    # Generate idempotency key once
    idempotency_key = context.step(
        lambda _: str(uuid.uuid4()),
        name='generate-key'
    )
    
    # Use idempotency key in payment API to prevent duplicate charges
    payment = context.step(
        lambda _: payment_api.charge(
            amount=event['amount'],
            idempotency_key=idempotency_key
        ),
        name='process-payment'
    )
    
    return {'statusCode': 200, 'payment': payment}
```

------

Puede configurar los pasos para utilizar la semántica de ejecución de como máximo una vez si configura el modo de ejecución en `AT_MOST_ONCE_PER_RETRY`. Esto garantiza que el paso se ejecute como máximo una vez por reintento, pero es posible que no se ejecute en absoluto si la función se interrumpe antes de que se complete el paso.

El SDK impone la reproducción determinista porque valida que los nombres y el orden de los pasos coincidan con el registro de los puntos de control durante la reproducción. Si el código intenta ejecutar los pasos en un orden diferente o con nombres diferentes, el SDK lanza un `NonDeterministicExecutionError`.

**Cómo funciona la reproducción con los pasos completados:**

1. Primera invocación: la función ejecuta el paso A, crea un punto de control y, a continuación, espera.

1. Segunda invocación (después de la espera): la función se reproduce desde el principio, el paso A devuelve el resultado del punto de control al instante sin volver a ejecutarse y, a continuación, continúa con el paso B.

1. Tercera invocación (después de la espera): la función se reproduce desde el principio, los pasos A y B devuelven los resultados de los puntos de control al instante y, a continuación, continúa con el paso C.

Este mecanismo de reproducción garantiza que los pasos completados no vuelvan a ejecutarse, pero su lógica empresarial debe seguir siendo idempotente para gestionar los reintentos antes de completarlos.

# Prueba de funciones duraderas de Lambda
<a name="durable-testing"></a>

AWS proporciona SDK de prueba específicos para funciones duraderas que le permiten ejecutar e inspeccionar las ejecuciones tanto de forma local como en la nube. Instale el SDK de prueba para su lenguaje:

------
#### [ TypeScript ]

```
npm install --save-dev @aws/aws-durable-execution-sdk-js-testing
```

Para ver la documentación completa y los ejemplos, consulte el [SDK de prueba para TypeScript](https://github.com/aws/aws-durable-execution-sdk-js/tree/development/packages/aws-durable-execution-sdk-js-testing) en GitHub.

------
#### [ Python ]

```
pip install aws-durable-execution-sdk-python-testing
```

Para ver la documentación completa y los ejemplos, consulte el [SDK de prueba para Python](https://github.com/aws/aws-durable-execution-sdk-python-testing) en GitHub.

------

El SDK de prueba proporciona dos modos de prueba: pruebas locales para pruebas unitarias rápidas y pruebas en la nube para pruebas de integración con funciones implementadas.

## Testeo local
<a name="durable-local-testing"></a>

Las pruebas locales ejecutan sus funciones duraderas en su entorno de desarrollo sin requerir recursos implementados. El ejecutor de pruebas ejecuta el código de la función directamente y captura todas las operaciones para su inspección.

Utilice las pruebas locales para las pruebas unitarias, el desarrollo basado en pruebas y las canalizaciones de CI/CD. Las pruebas se ejecutan localmente sin latencia de red ni costos adicionales.

**Ejemplo de prueba:**

------
#### [ TypeScript ]

```
import { withDurableExecution } from '@aws/aws-durable-execution-sdk-js';
import { DurableFunctionTestRunner } from '@aws/aws-durable-execution-sdk-js-testing';

const handler = withDurableExecution(async (event, context) => {
  const result = await context.step('calculate', async () => {
    return event.a + event.b;
  });
  return result;
});

test('addition works correctly', async () => {
  const runner = new DurableFunctionTestRunner({ handler });
  const result = await runner.run({ a: 5, b: 3 });
  
  expect(result.status).toBe('SUCCEEDED');
  expect(result.result).toBe(8);
  
  const step = result.getStep('calculate');
  expect(step.result).toBe(8);
});
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext
from aws_durable_execution_sdk_python_testing import DurableFunctionTestRunner
from aws_durable_execution_sdk_python.execution import InvocationStatus

@durable_execution
def handler(event: dict, context: DurableContext) -> int:
    result = context.step(lambda _: event["a"] + event["b"], name="calculate")
    return result

def test_addition():
    runner = DurableFunctionTestRunner(handler=handler)
    with runner:
        result = runner.run(input={"a": 5, "b": 3}, timeout=10)
    
    assert result.status is InvocationStatus.SUCCEEDED
    assert result.result == 8
    
    step = result.get_step("calculate")
    assert step.result == 8
```

------

El ejecutor de pruebas captura el estado de ejecución, incluidos el resultado final, los resultados de los pasos individuales, las operaciones de espera, las devoluciones de llamada y cualquier error. Puede inspeccionar las operaciones por su nombre o repetir todas las operaciones en iteraciones para comprobar el comportamiento de la ejecución.

### Almacenes de ejecución
<a name="durable-execution-stores"></a>

El SDK de prueba utiliza almacenes de ejecución para conservar los datos de ejecución de las pruebas. De forma predeterminada, las pruebas utilizan un almacén en la memoria que es rápido y no requiere limpieza. Para depurar o analizar el historial de ejecuciones, puede usar un almacén del sistema de archivos que guarde las ejecuciones como archivos JSON.

**Almacén en la memoria (predeterminado):**

El almacén en la memoria guarda los datos de ejecución en la memoria durante las pruebas. Los datos se pierden cuando finalizan las pruebas, por lo que resulta ideal para las pruebas unitarias estándar y los procesos de CI/CD, en los que no es necesario inspeccionar las ejecuciones una vez finalizadas las pruebas.

**Almacén del sistema de archivos:**

El almacén del sistema de archivos conserva los datos de ejecución en el disco como archivos JSON. Cada ejecución se guarda en un archivo por separado, lo que facilita la inspección del historial de ejecuciones una vez finalizadas las pruebas. Utilice el almacén del sistema de archivos para depurar errores de prueba complejos o analizar los patrones de ejecución a lo largo del tiempo.

Configure el almacén mediante variables de entorno:

```
# Use filesystem store
export AWS_DEX_STORE_TYPE=filesystem
export AWS_DEX_STORE_PATH=./test-executions

# Run tests
pytest tests/
```

Los archivos de ejecución se almacenan con nombres saneados y contienen el estado de ejecución completo, y se incluyen las operaciones, los puntos de control y los resultados. El almacén del sistema de archivos crea automáticamente el directorio de almacenamiento, si no existe.

## Prueba en la nube
<a name="durable-cloud-testing"></a>

Las pruebas en la nube invocan funciones duraderas implementadas en AWS y recuperan su historial de ejecución mediante la API de Lambda. Utilice las pruebas en la nube para verificar el comportamiento en entornos similares a los de producción con servicios de AWS y configuraciones reales.

Las pruebas en la nube requieren una función implementada y credenciales de AWS con permisos para invocar funciones y leer el historial de ejecución:

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "lambda:InvokeFunction",
                "lambda:GetDurableExecution",
                "lambda:GetDurableExecutionHistory"
            ],
            "Resource": "arn:aws:lambda:region:account-id:function:function-name"
        }
    ]
}
```

**Ejemplo de pruebas en la nube:**

------
#### [ TypeScript ]

```
import { DurableFunctionCloudTestRunner } from '@aws/aws-durable-execution-sdk-js-testing';

test('deployed function processes orders', async () => {
  const runner = new DurableFunctionCloudTestRunner({
    functionName: 'order-processor',
    region: 'us-east-1'
  });
  
  const result = await runner.run({ orderId: 'order-123' });
  
  expect(result.status).toBe('SUCCEEDED');
  expect(result.result.status).toBe('completed');
});
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python_testing import (
    DurableFunctionCloudTestRunner,
    DurableFunctionCloudTestRunnerConfig
)

def test_deployed_function():
    config = DurableFunctionCloudTestRunnerConfig(
        function_name="order-processor",
        region="us-east-1"
    )
    runner = DurableFunctionCloudTestRunner(config=config)
    
    result = runner.run(input={"orderId": "order-123"})
    
    assert result.status is InvocationStatus.SUCCEEDED
    assert result.result["status"] == "completed"
```

------

Las pruebas en la nube invocan la función realmente implementada y recuperan el historial de ejecución de AWS. Esto le permite verificar la integración con otros servicios de AWS, validar las características de rendimiento y realizar pruebas con datos y configuraciones similares a los de producción.

## Qué se debe probar
<a name="durable-testing-patterns"></a>

Puede probar las funciones duraderas si verifica los resultados de la ejecución, el comportamiento de las operaciones y la gestión de errores. Céntrese en la corrección de la lógica empresarial en lugar de en los detalles de la implementación.

**Verifique los resultados de la ejecución:** compruebe que las funciones devuelvan los valores esperados para determinadas entradas. Pruebe tanto las ejecuciones satisfactorias como los casos de error para garantizar que las funciones gestionen adecuadamente las entradas inválidas.

**Inspeccione la ejecución de la operación:** compruebe que los pasos, las esperas y las devoluciones de llamada se ejecuten según lo esperado. Compruebe los resultados de los pasos para asegurarse de que las operaciones intermedias produzcan los valores correctos. Compruebe que las operaciones de espera estén configuradas con los tiempos de espera adecuados y que las devoluciones de llamada se creen con los ajustes correctos.

**Pruebe la gestión de errores:** compruebe que las funciones fallen correctamente con mensajes de error descriptivos cuando se introduzcan datos inválidos. Pruebe el comportamiento de los reintentos; para ello, simule los errores transitorios y confirme que las operaciones se reintentan correctamente. Compruebe que los errores permanentes no desencadenen reintentos innecesarios.

**Valide los flujos de trabajo:** para los flujos de trabajo de varios pasos, compruebe que las operaciones se ejecuten en el orden correcto. Pruebe la ramificación condicional para asegurarse de que las diferentes rutas de ejecución funcionen correctamente. Valide que las operaciones paralelas se ejecuten simultáneamente y produzcan los resultados esperados.

Los repositorios de documentación del SDK contienen numerosos ejemplos de patrones de pruebas, incluidos flujos de trabajo de varios pasos, escenarios de error, gestión de los tiempos de espera y patrones de sondeo.

## Estrategia de prueba
<a name="durable-testing-strategy"></a>

Utilice las pruebas locales para las pruebas unitarias durante el desarrollo y en las canalizaciones de CI/CD. Las pruebas locales se ejecutan rápidamente, no requieren credenciales de AWS y proporcionan información inmediata sobre los cambios en el código. Escriba pruebas locales para verificar la lógica empresarial, la gestión de errores y el comportamiento de las operaciones.

Utilice las pruebas en la nube para las pruebas de integración antes de implementarlas en producción. Las pruebas en la nube verifican el comportamiento con servicios de AWS y configuraciones reales, validan las características de rendimiento y prueban los flujos de trabajo de extremo a extremo. Realice pruebas en la nube en entornos de ensayo para detectar los problemas de integración antes de que lleguen a producción.

Simule dependencias externas en las pruebas locales para aislar la lógica de las funciones y mantener la rapidez de las pruebas. Utilice las pruebas en la nube para verificar la integración real con servicios externos, como bases de datos, API y otros servicios de AWS.

Escriba pruebas específicas que verifiquen un comportamiento específico. Use nombres de prueba descriptivos que expliquen lo que se evalúa. Agrupe las pruebas relacionadas y utilice dispositivos de prueba para un código de configuración común. Mantenga las pruebas simples y evite la lógica de prueba compleja que sea difícil de entender.

## Fallos de depuración
<a name="durable-testing-debugging"></a>

En caso de error en las pruebas, inspeccione el resultado de la ejecución para comprender qué salió mal. Compruebe el estado de la ejecución para ver si la función fue satisfactoria, fallida o se agotó el tiempo de espera. Lea los mensajes de error para comprender la causa del error.

Inspeccione los resultados de cada operación para determinar en qué momento el comportamiento se desvió de las expectativas. Compruebe los resultados de los pasos para ver qué valores se produjeron. Verifique el orden de las operaciones para confirmar que las operaciones se ejecutaron en la secuencia esperada. Cuente las operaciones para garantizar que se haya creado el número correcto de pasos, esperas y devoluciones de llamada.

Los problemas más frecuentes incluyen un código no determinista que produce resultados diferentes en la reproducción, un estado compartido a través de variables globales que se interrumpe durante la reproducción y la falta de operaciones debido a errores de lógica condicional. Utilice depuradores y registros estándar para examinar el código de la función y realizar un seguimiento del flujo de ejecución.

Para las pruebas en la nube, inspeccione el historial de ejecución en Registros de CloudWatch para ver los detalles de los registros de operaciones. Utilice el seguimiento para seguir el flujo de ejecución en todos los servicios e identificar los cuellos de botella.

# Supervisión de funciones duraderas
<a name="durable-monitoring"></a>

Puede supervisar las funciones duraderas mediante las métricas de CloudWatch, Registros de CloudWatch y el seguimiento. Como las funciones duraderas pueden ejecutarse durante períodos prolongados y abarcar varias invocaciones de funciones, su supervisión requiere comprender sus patrones de ejecución únicos, incluidos los puntos de control, las transiciones de estado y el comportamiento de reproducción.

## Métricas de CloudWatch
<a name="durable-monitoring-metrics"></a>

Lambda publica automáticamente las métricas en CloudWatch sin cargo adicional. Las funciones duraderas proporcionan métricas adicionales a las métricas de Lambda estándar para ayudarlo a supervisar los flujos de trabajo de larga duración, la administración del estado y la utilización de los recursos.

### Métricas de ejecuciones duraderas
<a name="durable-monitoring-execution-metrics"></a>

Lambda emite las siguientes métricas para las ejecuciones duraderas:


| Métrica | Descripción | 
| --- | --- | 
| ApproximateRunningDurableExecutions | Número de ejecuciones duraderas en estado EN EJECUCIÓN | 
| ApproximateRunningDurableExecutionsUtilization | Porcentaje de la cuota máxima de ejecuciones duraderas en ejecución de su cuenta actualmente en uso | 
| DurableExecutionDuration | Tiempo transcurrido real en milisegundos durante el cual una ejecución duradera permaneció en estado EN EJECUCIÓN | 
| DurableExecutionStarted | Número de ejecuciones duraderas que se iniciaron | 
| DurableExecutionStopped | Número de ejecuciones duraderas detenidas mediante la API StopDurableExecution | 
| DurableExecutionSucceeded | Número de ejecuciones duraderas realizadas correctamente | 
| DurableExecutionFailed | Número de ejecuciones duraderas realizadas con un error | 
| DurableExecutionTimedOut | Número de ejecuciones duraderas que superaron el tiempo de espera de ejecución configurado | 
| DurableExecutionOperations | Número acumulado de operaciones realizadas en una ejecución duradera (máximo: 3000) | 
| DurableExecutionStorageWrittenBytes | Cantidad acumulada de datos en bytes conservada tras una ejecución duradera (máximo: 100 MB) | 

### Métricas de CloudWatch
<a name="durable-monitoring-standard-metrics"></a>

Lambda emite métricas estándar de invocación, rendimiento y concurrencia para las funciones duraderas. Dado que una ejecución duradera puede abarcar varias invocaciones de funciones a medida que avanza por los puntos de control y las reproducciones, estas métricas se comportan de forma diferente a las de las funciones estándar:
+ **Invocaciones:** cuenta cada invocación de función, incluidas las reproducciones. Una sola ejecución duradera puede generar varios puntos de datos de invocación.
+ **Duración:** mide la invocación de cada función por separado. Utilice `DurableExecutionDuration` para calcular el tiempo total empleado en una sola ejecución duradera.
+ **Errores:** sigue los errores de invocación de funciones. Utilice `DurableExecutionFailed` para errores a nivel de ejecución.

Para obtener una lista completa de las métricas estándar de Lambda, consulte [Tipos de métricas para las funciones de Lambda](https://docs.aws.amazon.com//lambda/latest/dg/monitoring-metrics-types.html).

### Crear alarmas de CloudWatch
<a name="durable-monitoring-alarms"></a>

Cree alarmas de CloudWatch para que le notifiquen cuando las métricas superen los umbrales. Las alarmas frecuentes incluyen las siguientes:
+ `ApproximateRunningDurableExecutionsUtilization` supera el 80 % de su cuota.
+ `DurableExecutionFailed` aumenta por encima de un umbral.
+ `DurableExecutionTimedOut` indica que las ejecuciones están agotando el tiempo de espera.
+ `DurableExecutionStorageWrittenBytes` se acerca a los límites de almacenamiento.

Para obtener más información, [consulte Uso de las alarmas de CloudWatch](https://docs.aws.amazon.com//AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html).

## Eventos de EventBridge
<a name="durable-monitoring-eventbridge"></a>

Lambda publica eventos de cambio de estado de ejecución duradera en EventBridge. Puede utilizar estos eventos para desencadenar flujos de trabajo, enviar notificaciones o realizar un seguimiento de los cambios en el ciclo de vida de la ejecución en todas sus funciones duraderas.

### Eventos de cambio de estado de ejecución duradera
<a name="durable-eventbridge-status-changes"></a>

Lambda emite un evento a EventBridge cada vez que una ejecución duradera cambia de estado. Estos eventos tienen las siguientes características:
+ **Origen:** `aws.lambda`
+ **Tipo de detalle:** `Durable Execution Status Change`

Los eventos de cambio de estado se publican para los siguientes estados de ejecución:
+ `RUNNING`: la ejecución se inició.
+ `SUCCEEDED`: la ejecución se completó correctamente.
+ `STOPPED`: la ejecución se detuvo mediante la API StopDurableExecution.
+ `FAILED`: la ejecución falló debido a un error.
+ `TIMED_OUT`: la ejecución superó el tiempo de espera configurado.

En el siguiente ejemplo, se muestra un evento de cambio de estado de ejecución duradera:

```
{
  "version": "0",
  "id": "d019b03c-a8a3-9d58-85de-241e96206538",
  "detail-type": "Durable Execution Status Change",
  "source": "aws.lambda",
  "account": "123456789012",
  "time": "2025-11-20T13:08:22Z",
  "region": "us-east-1",
  "resources": [],
  "detail": {
    "durableExecutionArn": "arn:aws:lambda:us-east-1:123456789012:function:my-function:$LATEST/durable-execution/090c4189-b18b-4296-9d0c-cfd01dc3a122/9f7d84c9-ea3d-3ffc-b3e5-5ec51c34ffc9",
    "durableExecutionName": "order-123",
    "functionArn": "arn:aws:lambda:us-east-1:123456789012:function:my-function:2",
    "status": "RUNNING",
    "startTimestamp": "2025-11-20T13:08:22.345Z"
  }
}
```

Para los estados terminales (`SUCCEEDED`, `STOPPED`, `FAILED`, `TIMED_OUT`), el evento incluye un campo de `endTimestamp` que indica cuándo se completó la ejecución.

### Creación de reglas de EventBridge
<a name="durable-eventbridge-rules"></a>

Cree reglas para enrutar eventos de cambio de estado de ejecución duradera a destinos como Amazon Simple Notification Service, Amazon Simple Queue Service u otras funciones de Lambda.

En el siguiente ejemplo, se crea una regla que coincide con todos los cambios de estado de ejecución duradera:

```
{
  "source": ["aws.lambda"],
  "detail-type": ["Durable Execution Status Change"]
}
```

En el siguiente ejemplo se crea una regla que coincide solo con las ejecuciones fallidas:

```
{
  "source": ["aws.lambda"],
  "detail-type": ["Durable Execution Status Change"],
  "detail": {
    "status": ["FAILED"]
  }
}
```

En el siguiente ejemplo, se crea una regla que coincide con los cambios de estado de una función específica:

```
{
  "source": ["aws.lambda"],
  "detail-type": ["Durable Execution Status Change"],
  "detail": {
    "functionArn": [{
      "prefix": "arn:aws:lambda:us-east-1:123456789012:function:my-function"
    }]
  }
}
```

Para obtener más información sobre cómo crear reglas, consulte [Tutoriales de Amazon EventBridge](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-tutorial.html) en la Guía del usuario de EventBridge.

## AWS X-RayRastreo de
<a name="durable-monitoring-xray"></a>

Puede habilitar el seguimiento de X-Ray en las funciones duraderas. Lambda pasa el encabezado de seguimiento de X-Ray a la ejecución duradera, lo que le permite seguir las solicitudes en todo el flujo de trabajo.

Para habilitar el seguimiento de X-Ray mediante la consola de Lambda, elija su función, a continuación elija Configuración, Supervisión y herramientas de operaciones y active el Seguimiento activo en X-Ray.

Cómo habilitar el seguimiento de X-Ray mediante la AWS CLI:

```
aws lambda update-function-configuration \
    --function-name my-durable-function \
    --tracing-config Mode=Active
```

Cómo habilitar el seguimiento de AWS X-Ray mediante AWS SAM:

```
Resources:
  MyDurableFunction:
    Type: AWS::Serverless::Function
    Properties:
      Tracing: Active
      DurableConfig:
        ExecutionTimeout: 3600
```

A fin de obtener más información sobre X-Ray, consulte la [Guía para desarrolladores de AWS X-Ray](https://docs.aws.amazon.com//xray/latest/devguide/aws-xray.html).

# Prácticas recomendadas para las funciones duraderas de Lambda
<a name="durable-best-practices"></a>

Las funciones duraderas utilizan un modelo de ejecución basado en la reproducción que requiere patrones diferentes a los de las funciones de Lambda tradicionales. Siga estas prácticas recomendadas para crear flujos de trabajo fiables y rentables.

## Escritura de código determinista
<a name="durable-determinism"></a>

Durante la reproducción, la función se ejecuta desde el principio y debe seguir la misma ruta de ejecución que la ejecución original. El código ajeno a las operaciones duraderas debe ser determinista y producir los mismos resultados con las mismas entradas.

**Encapsule las operaciones no deterministas en pasos:**
+ Generación de números al azar y UUID
+ Hora o marcas de tiempo actuales
+ Llamadas a la API externas y consultas a las bases de datos
+ Operaciones del sistema de archivos

------
#### [ TypeScript ]

```
import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js';
import { randomUUID } from 'crypto';

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    // Generate transaction ID inside a step
    const transactionId = await context.step('generate-transaction-id', async () => {
      return randomUUID();
    });
    
    // Use the same ID throughout execution, even during replay
    const payment = await context.step('process-payment', async () => {
      return processPayment(event.amount, transactionId);
    });
    
    return { statusCode: 200, transactionId, payment };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext
import uuid

@durable_execution
def handler(event, context: DurableContext):
    # Generate transaction ID inside a step
    transaction_id = context.step(
        lambda _: str(uuid.uuid4()),
        name='generate-transaction-id'
    )
    
    # Use the same ID throughout execution, even during replay
    payment = context.step(
        lambda _: process_payment(event['amount'], transaction_id),
        name='process-payment'
    )
    
    return {'statusCode': 200, 'transactionId': transaction_id, 'payment': payment}
```

------

**Importante**  
No utilice variables globales ni cierre para compartir el estado entre los pasos. Transfiera los datos a través de los valores devueltos. El estado global se interrumpe durante la reproducción porque los pasos devuelven resultados en caché, pero las variables globales se restablecen.

**Evite las mutaciones de cierre:** las variables capturadas en los cierres pueden perder mutaciones durante la reproducción. Los pasos devuelven los resultados guardados en caché, pero las actualizaciones de variables ajenas al paso no se reproducen.

------
#### [ TypeScript ]

```
// ❌ WRONG: Mutations lost on replay
export const handler = withDurableExecution(async (event, context) => {
  let total = 0;
  
  for (const item of items) {
    await context.step(async () => {
      total += item.price; // ⚠️ Mutation lost on replay!
      return saveItem(item);
    });
  }
  
  return { total }; // Inconsistent value!
});

// ✅ CORRECT: Accumulate with return values
export const handler = withDurableExecution(async (event, context) => {
  let total = 0;
  
  for (const item of items) {
    total = await context.step(async () => {
      const newTotal = total + item.price;
      await saveItem(item);
      return newTotal; // Return updated value
    });
  }
  
  return { total }; // Consistent!
});

// ✅ EVEN BETTER: Use map for parallel processing
export const handler = withDurableExecution(async (event, context) => {
  const results = await context.map(
    items,
    async (ctx, item) => {
      await ctx.step(async () => saveItem(item));
      return item.price;
    }
  );
  
  const total = results.getResults().reduce((sum, price) => sum + price, 0);
  return { total };
});
```

------
#### [ Python ]

```
# ❌ WRONG: Mutations lost on replay
@durable_execution
def handler(event, context: DurableContext):
    total = 0
    
    for item in items:
        context.step(
            lambda _: save_item_and_mutate(item, total),  # ⚠️ Mutation lost on replay!
            name=f'save-item-{item["id"]}'
        )
    
    return {'total': total}  # Inconsistent value!

# ✅ CORRECT: Accumulate with return values
@durable_execution
def handler(event, context: DurableContext):
    total = 0
    
    for item in items:
        total = context.step(
            lambda _: save_item_and_return_total(item, total),
            name=f'save-item-{item["id"]}'
        )
    
    return {'total': total}  # Consistent!

# ✅ EVEN BETTER: Use map for parallel processing
@durable_execution
def handler(event, context: DurableContext):
    def process_item(ctx, item):
        ctx.step(lambda _: save_item(item))
        return item['price']
    
    results = context.map(items, process_item)
    total = sum(results.get_results())
    
    return {'total': total}
```

------

## Diseño de idempotencia
<a name="durable-idempotency"></a>

Las operaciones pueden ejecutarse varias veces debido a los reintentos o a la reproducción. Las operaciones no idempotentes provocan efectos secundarios duplicados, como cobrar dos veces a los clientes o enviar varios correos electrónicos.

**Utilice tokens de idempotencia:** genere tokens dentro de los pasos e inclúyelos en las llamadas a la API externas para evitar la duplicación de operaciones.

------
#### [ TypeScript ]

```
import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js';

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    // Generate idempotency token once
    const idempotencyToken = await context.step('generate-idempotency-token', async () => {
      return crypto.randomUUID();
    });
    
    // Use token to prevent duplicate charges
    const charge = await context.step('charge-payment', async () => {
      return paymentService.charge({
        amount: event.amount,
        cardToken: event.cardToken,
        idempotencyKey: idempotencyToken
      });
    });
    
    return { statusCode: 200, charge };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext
import uuid

@durable_execution
def handler(event, context: DurableContext):
    # Generate idempotency token once
    idempotency_token = context.step(
        lambda _: str(uuid.uuid4()),
        name='generate-idempotency-token'
    )
    
    # Use token to prevent duplicate charges
    def charge_payment(_):
        return payment_service.charge(
            amount=event['amount'],
            card_token=event['cardToken'],
            idempotency_key=idempotency_token
        )
    
    charge = context.step(charge_payment, name='charge-payment')
    
    return {'statusCode': 200, 'charge': charge}
```

------

**Utilice la semántica de como máximo una vez:** para las operaciones críticas que nunca deben duplicarse (transacciones financieras, deducciones de inventario), configure el modo de ejecución como máximo una vez.

------
#### [ TypeScript ]

```
// Critical operation that must not duplicate
await context.step('deduct-inventory', async () => {
  return inventoryService.deduct(event.productId, event.quantity);
}, {
  executionMode: 'AT_MOST_ONCE_PER_RETRY'
});
```

------
#### [ Python ]

```
# Critical operation that must not duplicate
context.step(
    lambda _: inventory_service.deduct(event['productId'], event['quantity']),
    name='deduct-inventory',
    config=StepConfig(execution_mode='AT_MOST_ONCE_PER_RETRY')
)
```

------

**Idempotencia de la base de datos:** utilice patrones de verificación antes de escribir, actualizaciones condicionales u operaciones de modificación para evitar la duplicación de registros.

## Administración del estado de manera eficiente
<a name="durable-state-management"></a>

Cada punto de control guarda el estado en el almacenamiento persistente. Los objetos de gran tamaño aumentan los costos, ralentizan la creación de puntos de control y afectan el rendimiento. Almacene solo los datos esenciales de coordinación del flujo de trabajo.

**Mantenga el estado mínimo:**
+ Almacene los identificadores y las referencias, no los objetos completos.
+ Obtenga datos detallados dentro de los pasos, según sea necesario.
+ Utilice Amazon S3 o DynamoDB para datos de gran tamaño y pase las referencias en estado.
+ Evite pasar grandes cargas útiles entre pasos.

------
#### [ TypeScript ]

```
import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js';

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    // Store only the order ID, not the full order object
    const orderId = event.orderId;
    
    // Fetch data within each step as needed
    await context.step('validate-order', async () => {
      const order = await orderService.getOrder(orderId);
      return validateOrder(order);
    });
    
    await context.step('process-payment', async () => {
      const order = await orderService.getOrder(orderId);
      return processPayment(order);
    });
    
    return { statusCode: 200, orderId };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext

@durable_execution
def handler(event, context: DurableContext):
    # Store only the order ID, not the full order object
    order_id = event['orderId']
    
    # Fetch data within each step as needed
    context.step(
        lambda _: validate_order(order_service.get_order(order_id)),
        name='validate-order'
    )
    
    context.step(
        lambda _: process_payment(order_service.get_order(order_id)),
        name='process-payment'
    )
    
    return {'statusCode': 200, 'orderId': order_id}
```

------

## Diseñe pasos efectivos.
<a name="durable-step-design"></a>

Los pasos son la unidad de trabajo fundamental de las funciones duraderas. Los pasos bien diseñados facilitan la comprensión, la depuración y el mantenimiento de los flujos de trabajo.

**Principios de diseño de pasos:**
+ **Utilice nombres descriptivos**: los nombres como `validate-order` en lugar de `step1` facilita la comprensión de los registros y los errores.
+ **Mantenga los nombres estáticos**: no utilice nombres dinámicos con marcas de tiempo o valores al azar. Los nombres de los pasos deben ser deterministas para poder reproducirlos.
+ **Equilibre la granularidad**: divida las operaciones complejas en pasos específicos, pero evite los pasos demasiado pequeños que aumentan la sobrecarga de los puntos de control.
+ **Operaciones relacionadas por grupo**: las operaciones que deberían tener éxito o fracasar juntas pertenecen al mismo paso.

## Utilice las operaciones de espera de forma eficiente.
<a name="durable-wait-operations"></a>

Las operaciones de espera suspenden la ejecución sin consumir recursos ni incurrir en costos. Úselos en lugar de mantener la ejecución de Lambda.

**Esperas basadas en el tiempo:** utilice `context.wait()` para los retrasos en lugar de `setTimeout` o `sleep`.

**Devoluciones de llamada externas:** utilice `context.waitForCallback()` cuando se espera por sistemas externos. Establezca siempre tiempos de espera para evitar esperas indefinidas.

**Sondeo:** utilice `context.waitForCondition()` con un retroceso exponencial para sondear los servicios externos sin sobrecargarlos.

------
#### [ TypeScript ]

```
// Wait 24 hours without cost
await context.wait({ seconds: 86400 });

// Wait for external callback with timeout
const result = await context.waitForCallback(
  'external-job',
  async (callbackId) => {
    await externalService.submitJob({
      data: event.data,
      webhookUrl: `https://api.example.com/callbacks/${callbackId}`
    });
  },
  { timeout: { seconds: 3600 } }
);
```

------
#### [ Python ]

```
# Wait 24 hours without cost
context.wait(86400)

# Wait for external callback with timeout
result = context.wait_for_callback(
    lambda callback_id: external_service.submit_job(
        data=event['data'],
        webhook_url=f'https://api.example.com/callbacks/{callback_id}'
    ),
    name='external-job',
    config=WaitForCallbackConfig(timeout_seconds=3600)
)
```

------

## Consideraciones adicionales
<a name="durable-additional-considerations"></a>

**Gestión de errores:** reintente errores transitorios, como los tiempos de espera de la red y los límites de tasa. No reintente con errores permanentes, como errores de autenticación o de entrada inválida. Configure estrategias de reintentos con el máximo de intentos y las tasas de retroceso adecuadas. Para ver ejemplos detallados, consulte [Gestión de errores y reintentos](durable-execution-sdk-retries.md).

**Rendimiento:** minimice el tamaño de los puntos de control; para ello, almacene las referencias en lugar de las cargas útiles completas. Utilice `context.parallel()` y `context.map()` para ejecutar operaciones independientes de forma simultánea. Operaciones relacionadas con lotes para reducir la sobrecarga de los puntos de control.

**Control de versiones:** invoque funciones con alias o números de versión para fijar las ejecuciones a versiones de código específicas. Asegúrese de que las nuevas versiones del código puedan gestionar el estado de las versiones anteriores. No cambie el nombre de los pasos ni su comportamiento de forma que interfiera con la reproducción.

**Serialización:** utilice tipos compatibles con JSON para las entradas y los resultados de las operaciones. Convierta las fechas en cadenas ISO y los objetos personalizados en objetos simples antes de pasarlos a operaciones duraderas.

**Supervisión:** habilite el registro estructurado con los identificadores de ejecución y los nombres de los pasos. Configuración de las alarmas de CloudWatch para conocer las tasas de error y la duración de la ejecución. Uso de la trazabilidad para identificar cuellos de botella. Para obtener una guía detallada, consulte [Supervisión y depuración](durable-monitoring.md).

**Pruebas:** pruebe el flujo ideal, la gestión de errores y el comportamiento de reproducción. Pruebe los escenarios de tiempo de espera para detectar devoluciones de llamada y esperas. Utilice pruebas locales para reducir el tiempo de iteración. Para obtener una guía detallada, consulte [Prueba de funciones duraderas](durable-testing.md).

**Errores comunes que debe evitar:** no anide las llamadas de `context.step()`; en cambio, utilice contextos secundarios. Encapsule las operaciones no deterministas en pasos. Establezca siempre tiempos de espera para las devoluciones de llamada. Equilibre la granularidad de los pasos con la sobrecarga de los puntos de control. Guarde referencias en lugar de objetos grandes en su estado.

## Recursos adicionales
<a name="durable-additional-resources"></a>
+ [Documentación del SDK para Python](https://github.com/aws/aws-durable-execution-sdk-python/tree/main/docs): referencia completa de la API, patrones de prueba y ejemplos avanzados
+ [Documentación del SDK para TypeScript](https://github.com/aws/aws-durable-execution-sdk-js/tree/main/docs): referencia completa de la API, patrones de prueba y ejemplos avanzados