

# Invocação de funções do Lambda duráveis
<a name="durable-invoking"></a>

As funções do Lambda duráveis oferecem suporte aos mesmos métodos de invocação das funções do Lambda padrão. É possível invocar funções duráveis de forma síncrona, assíncrona ou por meio de mapeamentos da origem do evento. O processo de invocação é idêntico às funções padrão, mas as funções duráveis fornecem recursos adicionais para execuções de longa duração e gerenciamento automático de estados.

## Métodos de invocação
<a name="durable-invoking-methods"></a>

**Invocação síncrona:** invoque uma função durável e aguarde a resposta. As invocações síncronas são limitadas pelo Lambda a 15 minutos (ou menos, dependendo da função configurada e do tempo limite de execução). Use a invocação síncrona quando precisar de resultados imediatos ou ao fazer a integração com APIs e serviços que esperem uma resposta. É possível usar operações de espera para uma computação eficiente sem interromper o chamador. A invocação aguarda a conclusão de toda a execução durável. Para iniciar a execução com idempotência, use o parâmetro do nome da execução conforme descrito em [Idempotência](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
```

**Invocação assíncrona:** coloque um evento na fila para processamento sem esperar por uma resposta. O Lambda coloca o evento em uma fila e retorna imediatamente. Invocações assíncronas oferecem suporte a durações de execução de até um ano. Use a invocação assíncrona para cenários fire-and-forget ou quando o processamento puder ocorrer em segundo plano. Para iniciar a execução com idempotência, use o parâmetro do nome da execução conforme descrito em [Idempotência](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
```

**Mapeamentos da origem do evento:** configure o Lambda para invocar automaticamente sua função durável quando os registros estiverem disponíveis em serviços baseados em streaming ou em filas, como o Amazon SQS, o Kinesis ou o DynamoDB. Os mapeamentos da origem do evento sondam a origem do evento e invocam sua função com lotes de registros. Para obter detalhes sobre o uso de mapeamentos da origem do evento com funções duráveis, incluindo limites de duração de execução, consulte [Mapeamentos da origem do evento](durable-invoking-esm.md) com funções duráveis.

Para obter detalhes completos sobre cada método de invocação, consulte [invocação síncrona](invocation-sync.md) e [invocação assíncrona](invocation-async.md).

**nota**  
As funções duráveis oferecem suporte a filas de mensagens não entregues (DLQs) para tratamento de erros, mas não oferecem suporte a destinos do Lambda. Configure uma DLQ para capturar registros de invocações com falhas.

## Requisito de ARNs qualificados
<a name="durable-invoking-qualified-arns"></a>

As funções duráveis exigem identificadores qualificados para invocação. É necessário invocar funções duráveis usando um número de versão, alias ou `$LATEST`. É possível usar um ARN totalmente qualificado ou um nome de função com sufixo de versão/alias. Não é possível usar um identificador não qualificado (sem uma versão ou sufixo de alias).

**Invocações 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
```

**Invocações 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
```

Esse requisito garante que as execuções duráveis permaneçam consistentes durante todo o seu ciclo de vida. Quando uma execução durável é iniciada, ela é fixada na versão específica da função. Se sua função for pausada e retomada horas ou dias depois, o Lambda invocará a mesma versão que iniciou a execução, garantindo a consistência do código em todo o fluxo de trabalho.

**Melhor prática**  
Use aliases ou versões numeradas para funções duráveis de produção, em vez de `$LATEST`. As versões numeradas são imutáveis e permitem uma reprodução determinística. Opcionalmente, os aliases fornecem uma referência estável que pode ser atualizada para apontar para novas versões sem alterar o código de invocação. Quando você atualiza um alias, as novas execuções usam a nova versão, enquanto as execuções em andamento continuam com a versão original. É possível usar `$LATEST` para prototipagem ou para reduzir os tempos de implantação durante o desenvolvimento, entendendo que as execuções podem não ser reproduzidas corretamente (ou até mesmo falhar) se o código subjacente mudar durante o andamento das execuções.

## Noções básicas sobre o ciclo de vida da execução
<a name="durable-invoking-execution-lifecycle"></a>

Quando você invoca uma função durável, o Lambda cria uma execução durável que pode abranger várias invocações de funções:

1. **Invocação inicial:** sua solicitação de invocação cria uma nova execução durável. O Lambda atribui um ID de execução exclusivo e inicia o processamento.

1. **Execução e criação de pontos de verificação:** à medida que sua função executa operações duráveis, o SDK cria pontos de verificação que monitoram o andamento.

1. **Suspensão (se necessário):** se sua função usa esperas duráveis, como `wait` ou `waitForCallback`, ou novas tentativas automáticas de etapas, o Lambda suspende a execução e interrompe a cobrança pelo tempo de computação.

1. **Retomada:** na hora de prosseguir (inclusive após novas tentativas), o Lambda invoca sua função novamente. O SDK reproduz o log do ponto de verificação e continua de onde a execução foi pausada.

1. **Conclusão:** quando sua função retorna um resultado final ou gera um erro não tratado, a execução durável é concluída.

Para invocações síncronas, o chamador espera que toda a execução durável seja concluída, incluindo qualquer operação de espera. Se a execução exceder o tempo limite de invocação (15 minutos ou menos), a invocação expirará. Para invocações assíncronas, o Lambda retorna imediatamente e a execução continua de forma independente. Use as APIs de execução durável para monitorar o status da execução e recuperar os resultados finais.

## Invocação a partir do código da aplicação
<a name="durable-invoking-with-sdk"></a>

Use os SDKs da AWS para invocar funções duráveis a partir do código da sua aplicação. O processo de invocação é idêntico às funções padrão:

------
#### [ 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'})
)
```

------

## Invocações encadeadas
<a name="durable-invoking-chained"></a>

Funções duráveis podem invocar outras funções duráveis e não duráveis usando a operação `invoke` do `DurableContext`. Isso cria uma invocação em cadeia em que a função de chamada espera (é suspendida) até que a função invocada seja concluída:

------
#### [ 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)}
```

------

Invocações encadeadas criam um ponto de verificação na função de chamada. Se a função de chamada for interrompida, ela será retomada a partir do ponto de verificação com o resultado da função invocada sem invocar novamente a função.

**nota**  
Não há suporte para invocações encadeadas entre contas. A função invocada deve estar na mesma conta da AWS da função de chamada.

# Mapeamentos da origem do evento com funções duráveis
<a name="durable-invoking-esm"></a>

As funções duráveis funcionam com todos os mapeamentos da origem do evento do Lambda Configure mapeamentos da origem do evento para funções duráveis da mesma forma que você os configura para funções padrão. Os mapeamentos da origem do evento sondam automaticamente fontes de eventos como o Amazon SQS, o Kinesis e o DynamoDB Streams e invocam sua função com lotes de registros.

Os mapeamentos da origem do evento são úteis para funções duráveis que processem fluxos ou filas com fluxos de trabalho complexos de várias etapas. Por exemplo, é possível criar uma função durável que processe mensagens do Amazon SQS com novas tentativas, chamadas de API externas e aprovações humanas.

## Como os mapeamentos da origem do evento invocam as funções duráveis
<a name="durable-esm-invocation-behavior"></a>

Os mapeamentos da origem do evento invocam as funções duráveis de forma síncrona, aguardando a conclusão da execução durável completa antes de processar o próximo lote ou marcar os registros como processados. Se o tempo total de execução durável exceder 15 minutos, a execução expirará e falhará. O mapeamento da origem do evento recebe uma exceção de tempo limite e a trata de acordo com sua configuração de nova tentativa.

## Limite de execução de 15 minutos
<a name="durable-esm-duration-limit"></a>

Quando as funções duráveis são invocadas por mapeamentos da origem do evento, a duração total da execução durável não pode exceder 15 minutos. Esse limite se aplica a toda a execução durável, do início à conclusão, e não apenas às invocações de funções individuais.

Esse limite de 15 minutos é separado do tempo limite da função do Lambda (também de 15 minutos, no máximo). O tempo limite da função controla por quanto tempo cada invocação individual pode ser executada, enquanto o tempo limite de execução durável controla o tempo total decorrido do início à conclusão da execução.

**Cenários de exemplo:**
+ **Válido:** uma função durável processa uma mensagem do Amazon SQS com três etapas, cada uma levando 2 minutos, depois espera 5 minutos antes de concluir a etapa final. Tempo total de execução: 11 minutos. Isso funciona porque o total é inferior a 15 minutos.
+ **Inválido:** uma função durável processa uma mensagem do Amazon SQS, conclui o processamento inicial em 2 minutos e, em seguida, espera 20 minutos por um retorno de chamada externo antes de concluir. Tempo total de execução: 22 minutos. Isso excede o limite de 15 minutos e falhará.
+ **Inválido:** uma função durável processa um registro do Kinesis com várias operações de espera, totalizando 30 minutos entre as etapas. Embora cada invocação individual seja concluída rapidamente, o tempo total de execução excede 15 minutos.

**Importante**  
Configure seu tempo limite de execução durável para 15 minutos ou menos ao usar mapeamentos da origem do evento, caso contrário, a criação do mapeamento da origem do evento falhará. Se seu fluxo de trabalho exigir tempos de execução mais longos, use o padrão de função intermediária descrito abaixo.

## Configuração de mapeamentos da origem do evento
<a name="durable-esm-configuration"></a>

Configure mapeamentos da origem do evento para funções duráveis usando o console do Lambda, a AWS CLI ou SDKs da AWS. Todas as propriedades padrão do mapeamento da origem do evento se aplicam às funções duráveis:

```
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
```

Lembre-se de usar um ARN qualificado (com número de versão ou alias) ao configurar mapeamentos da origem do evento para funções duráveis.

## Tratamento de erros com o mapeamento da origem do evento
<a name="durable-esm-error-handling"></a>

Os mapeamentos da origem do evento fornecem tratamento de erros integrado que funciona com funções duráveis:
+ **Comportamento de novas tentativas:** se a invocação inicial falhar, o mapeamento da origem do evento tentará novamente de acordo com sua configuração de nova tentativa. Configure o máximo de tentativas e intervalos de novas tentativas com base em seus requisitos.
+ **Filas de mensagens não entregues:** configure uma fila de mensagens não entregues para capturar registros que falhem após todas as novas tentativas. Isso evita a perda de mensagens e permite a inspeção manual de registros com falha.
+ **Falhas parciais de lotes:** para o Amazon SQS e o Kinesis, use relatórios de falhas parciais de lotes para processar registros individualmente e somente repetir os registros com falha.
+ **bissecção em erros:** para o Kinesis e DynamoDB Streams, habilite a bissecção em caso de erro para dividir lotes com falha e isolar registros problemáticos.

**nota**  
As funções duráveis oferecem suporte a filas de mensagens não entregues (DLQs) para tratamento de erros, mas não oferecem suporte a destinos do Lambda. Configure uma DLQ para capturar registros de invocações com falhas.

Para obter informações completas sobre o tratamento de erros de mapeamento da origem do evento, consulte [mapeamentos da origem do evento](invocation-eventsourcemapping.md).

## Uso de uma função intermediária para fluxos de trabalho de longa duração
<a name="durable-esm-intermediary-function"></a>

Se seu fluxo de trabalho exigir mais de 15 minutos para ser concluído, use uma função do Lambda padrão intermediária entre o mapeamento da origem do evento e a sua função durável. A função intermediária receberá eventos do mapeamento da origem do evento e invocará a função durável de forma assíncrona, removendo o limite de execução de 15 minutos.

Esse padrão separa o modelo de invocação síncrona do mapeamento da origem do evento do modelo de execução de longa duração da função durável. O mapeamento da origem do evento invoca a função intermediária, que retornará rapidamente após iniciar a execução durável. A função durável então funcionará de forma independente pelo tempo necessário (até 1 ano).

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

O padrão da função intermediária usa três componentes:

1. **Mapeamento da origem do evento:** sonda a origem do evento (Amazon SQS, Kinesis, DynamoDB Streams) e invoca a função intermediária de forma síncrona com lotes de registros.

1. **Função intermediária:** uma função do Lambda padrão que recebe eventos do mapeamento da origem do evento, valida e transforma os dados, se necessário, e invoca a função durável de forma assíncrona. Essa função é concluída rapidamente (normalmente em menos de 1 segundo) e retorna o controle para o mapeamento da origem do evento.

1. **Função durável:** processa o evento com uma lógica complexa de várias etapas que pode ser executada por longos períodos. É invocada de forma assíncrona, portanto, não é limitada pelo limite de 15 minutos.

### Implementação
<a name="durable-esm-intermediary-implementation"></a>

A função intermediária receberá o evento inteiro do mapeamento da origem do evento e invocará a função durável de forma assíncrona. Use o parâmetro do nome da execução para garantir que a execução com idempotência seja iniciada, evitando o processamento duplicado se o mapeamento da origem do evento tentar novamente:

------
#### [ 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}
```

------

Para obter idempotência na própria função intermediária, use o [Powertools para AWS Lambda](https://docs.aws.amazon.com//powertools/) para evitar invocações duplicadas da função durável se o mapeamento da origem do evento tentar novamente a função intermediária.

A função durável receberá a carga com o nome da execução e processará todos os registros com uma lógica de longa duração:

------
#### [ 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
    }
```

------

### Considerações importantes
<a name="durable-esm-intermediary-tradeoffs"></a>

Esse padrão remove o limite de execução de 15 minutos ao desacoplar o mapeamento da origem do evento da execução durável. A função intermediária retornará imediatamente após iniciar a execução durável, permitindo que o mapeamento da origem do evento continue sendo processado. A função durável então funcionará de forma independente pelo tempo necessário.

A função intermediária terá êxito quando invocar a função durável, não quando a execução durável for concluída. Se a execução durável falhar posteriormente, o mapeamento da origem do evento não será repetido porque ele já processou o lote com êxito. Implemente o tratamento de erros na função durável e configure filas de mensagens não entregues para execuções com falha.

Use o parâmetro do nome da execução para garantir o início da execução com idempotência. Se o mapeamento da origem do evento tentar novamente a função intermediária, a função durável não iniciará uma execução duplicada porque o nome da execução já existe.

## Origens de eventos com suporte
<a name="durable-esm-supported-sources"></a>

As funções duráveis oferecem suporte a todas as origens de eventos do Lambda que usem mapeamentos da origem do evento:
+ Filas do Amazon SQS (padrão e FIFO)
+ Streams do Kinesis
+ DynamoDB Streams
+ Amazon Managed Streaming for Apache Kafka (Amazon MSK)
+ Apache Kafka autogerenciado
+ Amazon MQ (ActiveMQ e RabbitMQ)
+ Fluxos de mudança do Amazon DocumentDB

Todos os tipos de origens de eventos estão sujeitos ao limite de execução durável de 15 minutos ao invocar funções duráveis.

# Novas tentativas para funções duráveis do Lambda
<a name="durable-execution-sdk-retries"></a>

As funções duráveis fornecem recursos de novas tentativas automáticas que tornam suas aplicações resilientes a falhas transitórias. O SDK lida com novas tentativas em dois níveis: novas tentativas de etapas para falhas na lógica de negócios e novas tentativas de backend em caso de falhas de infraestrutura.

## Novas tentativas de etapa
<a name="durable-step-retries"></a>

Quando ocorre uma exceção não detectada em uma etapa, o SDK faz uma nova tentativa da etapa automaticamente com base na estratégia de novas tentativas configurada. As novas tentativas de etapas são operações com pontos de verificação que permitem que o SDK suspenda a execução e continue posteriormente sem perder o andamento.

### Comportamento de novas tentativas de etapa
<a name="durable-step-retry-behavior"></a>

A tabela a seguir descreve como o SDK lida com exceções em etapas:


| Cenário | O que acontece | Medição de impacto | 
| --- | --- | --- | 
| Exceção em etapa com novas tentativas restantes | O SDK cria um ponto de verificação para a nova tentativa e suspende a função. Na próxima invocação, a etapa sofre nova tentativa com o retardo de recuo configurado. | 1 operação \$1 tamanho da carga útil de erro | 
| Exceção em etapa sem novas tentativas restantes | A etapa falha e emite uma exceção. Se o seu código do manipulador não capturar essa exceção, toda a execução falhará. | 1 operação \$1 tamanho da carga útil de erro | 

Quando uma etapa precisa ser repetida, o SDK verifica o estado de novas tentativas e sai da invocação do Lambda se nenhum outro trabalho estiver em execução. Isso permite que o SDK implemente retardos de recuo sem consumir recursos computacionais. A função é retomada automaticamente após o período de recuo.

### Configuração de estratégias de novas tentativas de etapas
<a name="durable-step-retry-configuration"></a>

Configure estratégias de novas tentativas para controlar como as etapas tratam as falhas. É possível especificar o máximo de tentativas, os intervalos de recuo e as condições para novas tentativas.

**Recuo exponencial com o máximo de tentativas:**

------
#### [ 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)
)
```

------

**Recuo com intervalo fixo:**

------
#### [ 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)
)
```

------

**Nova tentativa condicional (tentar novamente somente erros 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)
)
```

------

**Desativar novas tentativas:**

------
#### [ 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}
    )
)
```

------

Quando a estratégia de novas tentativas retorna `shouldRetry: false`, a etapa falha imediatamente sem novas tentativas. Use isso para operações que não devam ser repetidas, como verificações de idempotência ou operações com efeitos colaterais que não possam ser repetidos com segurança.

## Exceções fora das etapas
<a name="durable-handler-exceptions"></a>

Quando ocorre uma exceção não detectada no código do manipulador, mas fora de qualquer etapa, o SDK marca a execução como com falha. Isso garante que os erros na lógica da aplicação sejam capturados e relatados adequadamente.


| Cenário | O que acontece | Medição de impacto | 
| --- | --- | --- | 
| Exceção no código do manipulador fora de qualquer etapa | O SDK marca a execução como COM FALHA e retorna o erro. A exceção não sofre nova tentativa automaticamente. | Tamanho da carga útil de erro | 

Para habilitar a nova tentativa automática para código propenso a erros, encapsule-o em uma etapa com uma estratégia de nova tentativa. As etapas fornecem uma nova tentativa automática com recuo configurável, enquanto as etapas externas do código falham imediatamente.

## Novas tentativas de backend
<a name="durable-backend-retries"></a>

As novas tentativas de backend ocorrem quando o Lambda encontra falhas de infraestrutura, erros de runtime ou quando o SDK não consegue se comunicar com o serviço de execução durável. O Lambda faz uma nova tentativa dessas falhas automaticamente para ajudar suas funções duráveis a se recuperarem de problemas transitórios de infraestrutura.

### Cenários de nova tentativa de backend
<a name="durable-backend-retry-scenarios"></a>

O Lambda faz uma nova tentativa da sua função automaticamente quando encontra os cenários a seguir:
+ **Erros de serviço internos**: quando o Lambda ou o serviço de execução durável retorna um erro 5xx, indicando um problema temporário no serviço.
+ **Limitação**: quando sua função sofre controle de utilização devido a limites de simultaneidade ou cotas de serviço.
+ **Tempos limite**: quando o SDK não consegue alcançar o serviço de execução durável dentro do período de tempo limite.
+ **Falhas na inicialização da sandbox**: quando o Lambda não consegue inicializar o ambiente de execução.
+ **Erros de runtime**: quando o runtime do Lambda encontra erros fora do seu código de função, como erros de falta de memória ou falhas no processo.
+ **Erros de token de ponto de verificação inválido**: quando o token de ponto de verificação não é mais válido, normalmente devido a mudanças de estado do lado do serviço.

A tabela a seguir descreve como o SDK trata esses cenários.


| Cenário | O que acontece | Medição de impacto | 
| --- | --- | --- | 
| Erro de runtime fora do manipulador durável (OOM, tempo limite, falha) | O Lambda automaticamente faz uma nova tentativa de invocação. O SDK é reproduzido a partir do último ponto de verificação, ignorando as etapas concluídas. | Tamanho da carga útil de erro \$1 1 operação por nova tentativa | 
| Erro de serviço (5xx) ou tempo limite ao chamar as APIs CheckpointDurableExecution / GetDurableExecutionState | O Lambda automaticamente faz uma nova tentativa de invocação. O SDK reproduz a partir do último ponto de verificação. | Tamanho da carga útil de erro \$1 1 operação por nova tentativa | 
| Controle de utilização (429) ou token de ponto de verificação inválido ao chamar as APIs CheckpointDurableExecution / GetDurableExecutionState | O Lambda automaticamente faz uma nova tentativa de invocação com recuo exponencial. O SDK reproduz a partir do último ponto de verificação. | Tamanho da carga útil de erro \$1 1 operação por nova tentativa | 
| Erro do cliente (4xx, exceto 429 e token inválido) quando as APIs CheckpointDurableExecution / GetDurableExecutionState | O SDK marca a execução como COM FALHA. Nenhuma nova tentativa automática ocorre porque o erro indica um problema permanente. | Tamanho da carga útil de erro | 

As novas tentativas de backend usam o recuo exponencial e prosseguem até que a função tenha êxito ou o tempo limite de execução seja atingido. Durante a reprodução, o SDK ignora os pontos de verificação concluídos e continua a execução da última operação com êxito, garantindo que sua função não reexecute o trabalho concluído.

## Práticas recomendadas de novas tentativas
<a name="durable-retry-best-practices"></a>

Siga estas práticas recomendadas ao configurar estratégias de novas tentativas:
+ **Configure estratégias de novas tentativas explícitas**: não confie no comportamento padrão de novas tentativas na produção. Configure estratégias de novas tentativas explícitas com o máximo de tentativas e intervalos de recuo apropriados para seu caso de uso.
+ **Use novas tentativas condicionais**: - implemente a lógica `shouldRetry` para repetir somente erros transitórios (limites de taxa, tempos limite) e antecipe-se à falha em erros permanentes (falhas de validação, não encontrado).
+ **Defina o máximo de tentativas apropriadas**: equilíbrio entre resiliência e tempo de execução. Muitas tentativas podem atrasar a detecção de falhas, enquanto poucas podem causar falhas desnecessárias.
+ **Use o recuo exponencial**: o recuo exponencial reduz a carga nos serviços subsequentes e aumenta a probabilidade de recuperação de falhas transitórias.
+ **Encapsule o código propenso a erros em etapas**: o código fora das etapas não pode sofrer novas tentativas automaticamente. Encapsule chamadas externas de API, consultas de banco de dados e outras operações sujeitas a erros em etapas com estratégias de novas tentativas.
+ **Monitore as métricas de novas tentativas**: acompanhe as operações de novas tentativas de etapas e falhas de execução no Amazon CloudWatch para identificar padrões e otimizar estratégias de novas tentativas.

# Potência igual
<a name="durable-execution-idempotency"></a>

As funções duráveis fornecem idempotência integrada para o início da execução por meio de nomes de execução. Quando você fornece um nome de execução, o Lambda o usa para evitar execuções duplicadas e permitir novas tentativas seguras de solicitações de invocação. Por padrão, as etapas têm semântica de execução de pelo menos uma vez. Durante a reprodução, o SDK retorna resultados verificados sem reexecutar as etapas concluídas, mas sua lógica de negócios deve ter idempotência para lidar com possíveis novas tentativas antes da conclusão.

**nota**  
Os mapeamentos da origem do evento (ESM) do Lambda não oferecem suporte à idempotência na inicialização. Portanto, cada invocação (incluindo novas tentativas) inicia uma nova execução durável. Para garantir a execução com idempotência com mapeamentos da origem do evento, implemente a lógica de idempotência em seu código de função, como com o [Powertools para AWS Lambda](https://docs.aws.amazon.com//powertools/) use uma função do Lambda comum como proxy (despachante) para invocar uma função durável com uma chave de idempotência (parâmetro do nome da execução).

## Nomes de execuções
<a name="durable-idempotency-execution-names"></a>

É possível fornecer um nome de execução ao invocar uma função durável. O nome da execução atua como uma chave de idempotência, permitindo que você repita com segurança as solicitações de invocação sem criar execuções duplicadas. Se você não fornecer um nome, o Lambda gerará automaticamente um ID de execução exclusivo.

Os nomes de execução deves ser exclusivos na sua conta e na sua região atual. Quando você invoca uma função com um nome de execução que já existe, o comportamento do Lambda depende do estado da execução existente e da correspondência da carga útil.

## Comportamento de idempotência
<a name="durable-idempotency-behavior"></a>

A tabela a seguir descreve como o Lambda lida com solicitações de invocação com base no fato de você fornecer um nome de execução, no estado de execução existente e na correspondência da carga útil:


| Cenário | Nome fornecido? | Status de execução existente | Carga útil idêntica? | Comportamento | 
| --- | --- | --- | --- | --- | 
| 1 | Não | N/D | N/D | Nova execução iniciada: o Lambda gera um ID de execução exclusivo e inicia uma nova execução | 
| 2 | Sim | Nunca existiu ou a retenção expirou | N/D | Nova execução iniciada: o Lambda inicia uma nova execução com o nome fornecido | 
| 3 | Sim | Executar | Sim | Início com idempotência: o Lambda retorna as informações de execução existentes sem iniciar uma duplicata. Para invocações síncronas, isso atua como uma reconexão com a execução em andamento | 
| 4 | Sim | Executar | Não | Erro: o Lambda retorna um erro DurableExecutionAlreadyExists porque uma execução com esse nome já está em andamento com uma carga útil diferente | 
| 5 | Sim | Fechado (com êxito, com falha, interrompido ou atingiu o tempo limite) | Sim | Início com idempotência: o Lambda retorna as informações de execução existentes sem iniciar uma nova execução. O resultado da execução fechada é retornado | 
| 6 | Sim | Fechado (com êxito, com falha, interrompido ou atingiu o tempo limite) | Não | Erro: o Lambda retorna um erro DurableExecutionAlreadyExists porque uma execução com esse nome já foi concluída com uma carga útil diferente | 

**Observação**  
Os cenários 3 e 5 demonstram um comportamento com idempotência em que o Lambda lida com segurança com solicitações de invocação duplicadas, retornando as informações de execução existentes em vez de criar duplicatas.

## Idempotência de etapas
<a name="durable-idempotency-steps"></a>

Por padrão, as etapas têm semântica de execução de ao menos uma vez. Quando sua função é reproduzida após uma espera, um retorno de chamada ou uma falha, o SDK compara cada etapa com base no log do ponto de verificação. Para etapas que já foram concluídas, o SDK retorna o resultado do checkpoint sem reexecutar a lógica da etapa. No entanto, se uma etapa falhar ou a função for interrompida antes da conclusão da etapa, a etapa poderá ser executada várias vezes.

Sua lógica de negócios encapsulada em etapas deve ter idempotência para lidar com possíveis novas tentativas. Use chaves de idempotência para garantir que operações como pagamentos ou gravações de banco de dados sejam executadas somente uma vez, mesmo que a etapa sofra uma nova tentativa.

**Exemplo: uso de chaves de idempotência em etapas**

------
#### [ 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}
```

------

É possível configurar etapas para usar a semântica de execução de no máximo uma vez definindo o modo de execução como `AT_MOST_ONCE_PER_RETRY`. Isso garante que a etapa seja executada no máximo uma vez por nova tentativa, mas pode não ser executada se a função for interrompida antes da conclusão da etapa.

O SDK impõe a reprodução determinística ao validar se os nomes e a ordem das etapas correspondem ao log do ponto de verificação durante a reprodução. Se seu código tentar executar etapas em uma ordem diferente ou com nomes diferentes, o SDK emitirá um `NonDeterministicExecutionError`

**Como a reprodução funciona com etapas concluídas:**

1. Primeira invocação: a função executa a etapa A, cria o ponto de verificação e aguarda

1. Segunda invocação (após a espera): a função é reproduzida desde o início, a etapa A retorna o resultado do ponto de verificação instantaneamente sem reexecução e, em seguida, prossegue até a etapa B

1. Terceira invocação (após outra espera): a função é reproduzida desde o início, as etapas A e B retornam os resultados marcados instantaneamente e, em seguida, prossegue até a etapa C

Esse mecanismo de reprodução garante que as etapas concluídas não sejam reexecutadas, mas sua lógica de negócios ainda deve ter idempotência para lidar com novas tentativas antes da conclusão.