Desenvolva aplicações de múltiplos passos e fluxos de trabalho de IA com funções duráveis do AWS Lambda

Crie Aplicações Multi-etapas e Fluxos de Trabalho de IA com Funções Duráveis do AWS Lambda
Aplicações modernas exigem cada vez mais coordenação complexa e de longa duração entre serviços, como processamento de pagamentos em múltiplas etapas, orquestração de AI agents ou processos de aprovação que aguardam decisões humanas. Tradicionalmente, a construção dessas aplicações exigia um esforço significativo para implementar gerenciamento de estado (state management), lidar com falhas e integrar múltiplos serviços de infraestrutura.
A partir de hoje, você pode usar as funções duráveis (durable functions) do AWS Lambda para construir aplicações multi-etapas confiáveis diretamente na experiência familiar do AWS Lambda. Funções duráveis são funções Lambda comuns, com o mesmo event handler e as mesmas integrações que você já conhece. Você escreve código sequencial na sua linguagem de programação preferida, e as funções duráveis rastreiam o progresso, tentam automaticamente em caso de falhas (retry), e suspendem a execução por até um ano em pontos definidos, sem que você pague por idle compute durante as esperas.
As funções duráveis do AWS Lambda utilizam um mecanismo de checkpoint e repetição (replay) — conhecido como durable execution — para entregar essas capacidades. Após habilitar uma função para durable execution, você adiciona o novo SDK de código aberto à sua função. Em seguida, você usa primitivas do SDK, como “steps”, para adicionar checkpointing automático e retries à sua lógica de negócio, e “waits” para suspender a execução de forma eficiente sem cobranças de compute. Quando a execução é encerrada inesperadamente, o Lambda é retomado a partir do último checkpoint, repetindo seu event handler desde o início, mas ignorando as operações já concluídas.
Introdução às Funções Duráveis do AWS Lambda
Permita-me guiá-lo sobre como usar as funções duráveis. Primeiro, crio uma nova função Lambda no console e seleciono Author from scratch (Criar do zero). Na seção Durable execution, seleciono Enable (Habilitar). É importante notar que a configuração de função durável só pode ser definida durante a criação da função e atualmente não pode ser modificada para funções Lambda existentes.
Após criar minha função durável Lambda, posso começar a trabalhar com o código fornecido. As funções duráveis do Lambda introduzem duas primitivas centrais que lidam com o gerenciamento de estado e a recuperação:
- Steps — O método
context.step()adiciona retries automáticos e checkpointing à sua lógica de negócio. Após a conclusão de uma etapa, ela será ignorada durante o replay. - Wait — O método
context.wait()pausa a execução por uma duração especificada, encerrando a função, suspendendo e retomando a execução sem cobranças de compute.
Adicionalmente, as funções duráveis do Lambda fornecem outras operações para padrões mais complexos: create_callback() cria um callback que você pode usar para aguardar resultados de eventos externos, como respostas de API ou aprovações humanas; wait_for_condition() pausa até que uma condição específica seja atendida, como fazer polling em uma API REST para a conclusão de um processo; e operações parallel() ou map() para casos de uso avançados de concorrência.
Construindo um Fluxo de Trabalho de Processamento de Pedidos Pronto para Produção
Agora, vamos expandir o exemplo padrão para construir um fluxo de trabalho de processamento de pedidos pronto para produção. Isso demonstra como usar callbacks para aprovações externas, lidar com erros adequadamente e configurar estratégias de retry. Mantenho o código intencionalmente conciso para focar nesses conceitos centrais. Em uma implementação completa, você poderia aprimorar a etapa de validação com o Amazon Bedrock para adicionar análise de pedidos impulsionada por IA.
É assim que o fluxo de trabalho de processamento de pedidos funciona:
Primeiro, validate_order() verifica os dados do pedido para garantir que todos os campos obrigatórios estejam presentes. Em seguida, send_for_approval() envia o pedido para aprovação humana externa e aguarda por uma resposta de callback, suspendendo a execução sem cobranças de compute. Depois, process_order() conclui o processamento do pedido.
Ao longo do fluxo de trabalho, o tratamento de erros try-catch distingue entre erros terminais que interrompem a execução imediatamente e erros recuperáveis dentro dos steps que acionam retries automáticos.
Aqui está o fluxo de trabalho completo de processamento de pedidos com definições de step e o handler principal:
import random
from aws_durable_execution_sdk_python import (
DurableContext,
StepContext,
durable_execution,
durable_step,
)
from aws_durable_execution_sdk_python.config import (
Duration,
StepConfig,
CallbackConfig,
)
from aws_durable_execution_sdk_python.retries import (
RetryStrategyConfig,
create_retry_strategy,
)
@durable_step
def validate_order(step_context: StepContext, order_id: str) -> dict:
"""Validates order data using AI."""
step_context.logger.info(f"Validating order: {order_id}")
# In production: calls Amazon Bedrock to validate order completeness and accuracy
return {"order_id": order_id, "status": "validated"}
@durable_step
def send_for_approval(step_context: StepContext, callback_id: str, order_id: str) -> dict:
"""Sends order for approval using the provided callback token."""
step_context.logger.info(f"Sending order {order_id} for approval with callback_id: {callback_id}")
# In production: send callback_id to external approval system
# The external system will call Lambda SendDurableExecutionCallbackSuccess or
# SendDurableExecutionCallbackFailure APIs with this callback_id when approval is complete
return {
"order_id": order_id,
"callback_id": callback_id,
"status": "sent_for_approval"
}
@durable_step
def process_order(step_context: StepContext, order_id: str) -> dict:
"""Processes the order with retry logic for transient failures."""
step_context.logger.info(f"Processing order: {order_id}")
# Simulate flaky API that sometimes fails
if random.random() > 0.4:
step_context.logger.info("Processing failed, will retry")
raise Exception("Processing failed")
return {
"order_id": order_id,
"status": "processed",
"timestamp": "2025-11-27T10:00:00Z",
}
@durable_execution
def lambda_handler(event: dict, context: DurableContext) -> dict:
try:
order_id = event.get("order_id")
# Step 1: Validate the order
validated = context.step(validate_order(order_id))
if validated["status"] != "validated":
raise Exception("Validation failed") # Terminal error - stops execution
context.logger.info(f"Order validated: {validated}")
# Step 2: Create callback
callback = context.create_callback(
name="awaiting-approval",
config=CallbackConfig(timeout=Duration.from_minutes(3))
)
context.logger.info(f"Created callback with id: {callback.callback_id}")
# Step 3: Send for approval with the callback_id
approval_request = context.step(send_for_approval(callback.callback_id, order_id))
context.logger.info(f"Approval request sent: {approval_request}")
# Step 4: Wait for the callback result
# This blocks until external system calls SendDurableExecutionCallbackSuccess or SendDurableExecutionCallbackFailure
approval_result = callback.result()
context.logger.info(f"Approval received: {approval_result}")
# Step 5: Process the order with custom retry strategy
retry_config = RetryStrategyConfig(max_attempts=3, backoff_rate=2.0)
processed = context.step(
process_order(order_id),
config=StepConfig(retry_strategy=create_retry_strategy(retry_config)),
)
if processed["status"] != "processed":
raise Exception("Processing failed") # Terminal error
context.logger.info(f"Order successfully processed: {processed}")
return processed
except Exception as error:
context.logger.error(f"Error processing order: {error}")
raise error # Re-raise to fail the execution
import random
from aws_durable_execution_sdk_python import (
DurableContext,
StepContext,
durable_execution,
durable_step,
)
from aws_durable_execution_sdk_python.config import (
Duration,
StepConfig,
CallbackConfig,
)
from aws_durable_execution_sdk_python.retries import (
RetryStrategyConfig,
create_retry_strategy,
)
@durable_step
def validate_order(step_context: StepContext, order_id: str) -> dict:
"""Validates order data using AI."""
step_context.logger.info(f"Validating order: {order_id}")
# In production: calls Amazon Bedrock to validate order completeness and accuracy
return {"order_id": order_id, "status": "validated"}
@durable_step
def send_for_approval(step_context: StepContext, callback_id: str, order_id: str) -> dict:
"""Sends order for approval using the provided callback token."""
step_context.logger.info(f"Sending order {order_id} for approval with callback_id: {callback_id}")
# In production: send callback_id to external approval system
# The external system will call Lambda SendDurableExecutionCallbackSuccess or
# SendDurableExecutionCallbackFailure APIs with this callback_id when approval is complete
return {
"order_id": order_id,
"callback_id": callback_id,
"status": "sent_for_approval"
}
@durable_step
def process_order(step_context: StepContext, order_id: str) -> dict:
"""Processes the order with retry logic for transient failures."""
step_context.logger.info(f"Processing order: {order_id}")
# Simulate flaky API that sometimes fails
if random.random() > 0.4:
step_context.logger.info("Processing failed, will retry")
raise Exception("Processing failed")
return {
"order_id": order_id,
"status": "processed",
"timestamp": "2025-11-27T10:00:00Z",
}
@durable_execution
def lambda_handler(event: dict, context: DurableContext) -> dict:
try:
order_id = event.get("order_id")
# Step 1: Validate the order
validated = context.step(validate_order(order_id))
if validated["status"] != "validated":
raise Exception("Validation failed") # Terminal error - stops execution
context.logger.info(f"Order validated: {validated}")
# Step 2: Create callback
callback = context.create_callback(
name="awaiting-approval",
config=CallbackConfig(timeout=Duration.from_minutes(3))
)
context.logger.info(f"Created callback with id: {callback.callback_id}")
# Step 3: Send for approval with the callback_id
approval_request = context.step(send_for_approval(callback.callback_id, order_id))
context.logger.info(f"Approval request sent: {approval_request}")
# Step 4: Wait for the callback result
# This blocks until external system calls SendDurableExecutionCallbackSuccess or SendDurableExecutionCallbackFailure
approval_result = callback.result()
context.logger.info(f"Approval received: {approval_result}")
# Step 5: Process the order with custom retry strategy
retry_config = RetryStrategyConfig(max_attempts=3, backoff_rate=2.0)
processed = context.step(
process_order(order_id),
config=StepConfig(retry_strategy=create_retry_strategy(retry_config)),
)
if processed["status"] != "processed":
raise Exception("Processing failed") # Terminal error
context.logger.info(f"Order successfully processed: {processed}")
return processed
except Exception as error:
context.logger.error(f"Error processing order: {error}")
raise error # Re-raise to fail the execution
Este código demonstra vários conceitos importantes:
- Tratamento de Erros (Error Handling) — O bloco
try-catchlida com erros terminais. Quando uma exceção não tratada é lançada fora de um step (como a verificação de validação), ela encerra a execução imediatamente. Isso é útil quando não faz sentido tentar novamente, como no caso de dados de pedido inválidos. - Retentativas de Step (Step Retries) — Dentro do step
process_order, as exceções acionam retries automáticos baseados na estratégia padrão (passo 1) ou naRetryStrategyconfigurada (passo 5). Isso lida com falhas transientes, como indisponibilidade temporária de API. - Log — Eu uso
context.loggerpara o handler principal estep_context.loggerdentro dos steps. O context logger suprime logs duplicados durante o replay.
Agora, crio um evento de teste com order_id e invoco a função assincronamente para iniciar o fluxo de trabalho do pedido. Navego até a aba Test e preencho o campo opcional Durable execution name para identificar esta execução. É importante notar que as funções duráveis fornecem idempotência integrada. Se eu invocar a função duas vezes com o mesmo nome de execução, a segunda invocação retorna o resultado da execução existente em vez de criar uma duplicata.
Posso monitorar a execução navegando até a aba Durable executions no console do Lambda. Lá, posso ver o status e o timing de cada step. A execução mostra CallbackStarted seguido por InvocationCompleted, o que indica que a função foi encerrada e a execução está suspensa para evitar cobranças ociosas enquanto aguarda o callback de aprovação.
Agora posso completar o callback diretamente do console, escolhendo Send success ou Send failure, ou programaticamente usando a API do Lambda. Eu escolho Send success. Após a conclusão do callback, a execução é retomada e processa o pedido. Se o step process_order falhar devido à API instável simulada, ele tentará automaticamente com base na estratégia configurada. Uma vez que todos os retries são bem-sucedidos, a execução é concluída com sucesso.
Monitorando Execuções com Amazon EventBridge
Você também pode monitorar execuções de funções duráveis usando o Amazon EventBridge. O Lambda envia automaticamente eventos de mudança de status de execução para o event bus padrão, permitindo que você construa fluxos de trabalho downstream, envie notificações ou se integre a outros serviços AWS. Para receber esses eventos, crie uma regra do EventBridge no event bus padrão com este padrão:
{
"source": ["aws.lambda"],
"detail-type": ["Durable Execution Status Change"]
}
{
"source": ["aws.lambda"],
"detail-type": ["Durable Execution Status Change"]
}
Informações Importantes
Aqui estão os pontos-chave a serem observados:
- Disponibilidade — As funções duráveis do Lambda estão agora disponíveis na região AWS US East (Ohio). Para a disponibilidade de regiões mais recente, visite a página AWS Capabilities by Region.
- Suporte a Linguagens de Programação — No lançamento, as funções duráveis do AWS Lambda suportam JavaScript/TypeScript (Node.js 22/24) e Python (3.13/3.14). Recomendamos empacotar o SDK de durable execution com o código da sua função usando seu gerenciador de pacotes preferido. Os SDKs estão em rápida evolução, então você pode atualizar facilmente as dependências à medida que novos recursos se tornam disponíveis.
- Uso de Versões do Lambda — Ao implantar funções duráveis em produção, use Lambda versions para garantir que o replay sempre ocorra na mesma versão do código. Se você atualizar o código da sua função enquanto uma execução estiver suspensa, o replay usará a versão que iniciou a execução, prevenindo inconsistências devido a mudanças de código durante fluxos de trabalho de longa duração.
- Teste de Funções Duráveis — Você pode testar funções duráveis localmente sem credenciais AWS usando o testing SDK separado com integração pytest e a command line interface (CLI) do AWS Serverless Application Model (AWS SAM) para testes de integração mais complexos.
- SDKs de Código Aberto — Os SDKs de durable execution são de código aberto para JavaScript/TypeScript e Python. Você pode revisar o código-fonte, contribuir com melhorias e manter-se atualizado com os recursos mais recentes.
- Preços (Pricing) — Para saber mais sobre os preços das funções duráveis do AWS Lambda, consulte a página de preços do AWS Lambda.
Comece a usar as funções duráveis do AWS Lambda visitando o console do AWS Lambda. Para saber mais, consulte a página de documentação das funções duráveis do AWS Lambda.
Boa construção! — Donnie
Precisa de ajuda com suas soluções de TI?
A VirtuAllIT Solutions oferece consultoria especializada em virtualização, cloud computing e infraestrutura tecnológica.

