|
| 1 | +--- |
| 2 | +title: Durable Functions |
| 3 | +description: Using Powertools for AWS Lambda (Python) with Lambda Durable Functions |
| 4 | +--- |
| 5 | + |
| 6 | +<!-- markdownlint-disable MD043 --> |
| 7 | + |
| 8 | +[Lambda Durable Functions](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html){target="_blank" rel="nofollow"} enable you to build resilient multi-step workflows that can execute for up to one year. They use checkpoints to track progress and automatically recover from failures through replay. |
| 9 | + |
| 10 | +## Key concepts |
| 11 | + |
| 12 | +| Concept | Description | |
| 13 | +| --------------------- | ------------------------------------------------------------------ | |
| 14 | +| **Durable execution** | Complete lifecycle of a durable function, from start to completion | |
| 15 | +| **Checkpoint** | Saved state that tracks progress through the workflow | |
| 16 | +| **Replay** | Re-execution from the beginning, skipping completed checkpoints | |
| 17 | +| **Steps** | Business logic with built-in retries and progress tracking | |
| 18 | +| **Waits** | Suspend execution without incurring compute charges | |
| 19 | + |
| 20 | +## How it works |
| 21 | + |
| 22 | +Durable functions use a **checkpoint/replay mechanism**: |
| 23 | + |
| 24 | +1. Your code runs from the beginning |
| 25 | +2. Completed operations are skipped using stored results |
| 26 | +3. Execution continues from where it left off |
| 27 | +4. State is automatically managed by the SDK |
| 28 | + |
| 29 | +## Powertools integration |
| 30 | + |
| 31 | +Powertools for AWS Lambda (Python) works seamlessly with Durable Functions. The [Durable Execution SDK](https://github.com/aws/aws-durable-execution-sdk-python){target="_blank" rel="nofollow"} has native integration with Powertools Logger via `context.set_logger()`. |
| 32 | + |
| 33 | +???+ note "Found an issue?" |
| 34 | + If you encounter any issues using Powertools for AWS with Durable Functions, please [open an issue](https://github.com/aws-powertools/powertools-lambda-python/issues/new?template=bug_report.yml){target="_blank"}. |
| 35 | + |
| 36 | +### Logger |
| 37 | + |
| 38 | +The Durable Execution SDK provides a `context.logger` that automatically handles **log deduplication during replays**. You can integrate Powertools Logger to get structured JSON logging while keeping the deduplication benefits. |
| 39 | + |
| 40 | +#### Using Powertools Logger with context.set_logger |
| 41 | + |
| 42 | +For the best experience, set the Powertools Logger on the durable context: |
| 43 | + |
| 44 | +```python hl_lines="5 10" title="Integrating Powertools Logger with Durable Functions" |
| 45 | +--8<-- "examples/lambda_features/durable_functions/src/using_logger.py" |
| 46 | +``` |
| 47 | + |
| 48 | +This gives you: |
| 49 | + |
| 50 | +- **JSON structured logging** from Powertools for AWS |
| 51 | +- **Log deduplication** during replays (logs from completed operations don't repeat) |
| 52 | +- **Automatic SDK enrichment** (execution_arn, parent_id, name, attempt) |
| 53 | +- **Lambda context injection** (request_id, function_name, etc.) |
| 54 | + |
| 55 | +#### Log deduplication during replay |
| 56 | + |
| 57 | +When you use `context.logger`, the SDK prevents duplicate logs during replays: |
| 58 | + |
| 59 | +```python title="Log deduplication behavior" |
| 60 | +--8<-- "examples/lambda_features/durable_functions/src/log_deduplication.py" |
| 61 | +``` |
| 62 | + |
| 63 | +???+ warning "Direct logger usage" |
| 64 | + If you use the Powertools Logger directly (not through `context.logger`), logs will be emitted on every replay: |
| 65 | + |
| 66 | + ```python |
| 67 | + # Logs will duplicate during replays |
| 68 | + logger.info("This appears on every replay") |
| 69 | + |
| 70 | + # Use context.logger instead for deduplication |
| 71 | + context.logger.info("This appears only once") |
| 72 | + ``` |
| 73 | + |
| 74 | +### Tracer |
| 75 | + |
| 76 | +Tracer works with Durable Functions. Each execution creates trace segments. |
| 77 | + |
| 78 | +???+ note "Trace continuity" |
| 79 | + Due to the replay mechanism, traces may not show a continuous flow. Each execution (including replays) creates separate trace segments. Use the `execution_arn` to correlate traces. |
| 80 | + |
| 81 | +```python hl_lines="5 9" title="Using Tracer with Durable Functions" |
| 82 | +--8<-- "examples/lambda_features/durable_functions/src/using_tracer.py" |
| 83 | +``` |
| 84 | + |
| 85 | +### Metrics |
| 86 | + |
| 87 | +Metrics work with Durable Functions, but be aware that **metrics may be emitted multiple times** during replay if not handled carefully. |
| 88 | + |
| 89 | +```python hl_lines="6 10 21" title="Using Metrics with Durable Functions" |
| 90 | +--8<-- "examples/lambda_features/durable_functions/src/using_metrics.py" |
| 91 | +``` |
| 92 | + |
| 93 | +???+ tip "Accurate metrics" |
| 94 | + Emit metrics at workflow completion rather than during intermediate steps to avoid counting replays as new executions. |
| 95 | + |
| 96 | +### Idempotency |
| 97 | + |
| 98 | +The `@idempotent` decorator integrates with Durable Functions and is **replay-aware**. It's useful for protecting the Lambda handler entry point, especially for Event Source Mapping (ESM) invocations like SQS, Kinesis, or DynamoDB Streams. |
| 99 | + |
| 100 | +```python hl_lines="9 15" title="Using Idempotency with Durable Functions" |
| 101 | +--8<-- "examples/lambda_features/durable_functions/src/using_idempotency.py" |
| 102 | +``` |
| 103 | + |
| 104 | +**When to use Powertools Idempotency:** |
| 105 | + |
| 106 | +- Protecting the Lambda handler entry point from duplicate invocations |
| 107 | +- Methods you don't want to convert into steps but need idempotency guarantees |
| 108 | +- Event Source Mapping triggers (SQS, Kinesis, DynamoDB Streams) |
| 109 | + |
| 110 | +**When you don't need it:** |
| 111 | + |
| 112 | +- Steps within a durable function are already idempotent via the checkpoint mechanism |
| 113 | + |
| 114 | +### Parser |
| 115 | + |
| 116 | +Parser works with Durable Functions for validating and parsing event payloads. |
| 117 | + |
| 118 | +```python hl_lines="9 14" title="Using Parser with Durable Functions" |
| 119 | +--8<-- "examples/lambda_features/durable_functions/src/using_parser.py" |
| 120 | +``` |
| 121 | + |
| 122 | +### Parameters |
| 123 | + |
| 124 | +Parameters work normally with Durable Functions. |
| 125 | + |
| 126 | +```python hl_lines="13" title="Using Parameters with Durable Functions" |
| 127 | +--8<-- "examples/lambda_features/durable_functions/src/using_parameters.py" |
| 128 | +``` |
| 129 | + |
| 130 | +???+ note "Parameter freshness" |
| 131 | + For long-running workflows (hours/days), parameters fetched at the start may become stale. Consider fetching parameters within steps that need the latest values. |
| 132 | + |
| 133 | +## Best practices |
| 134 | + |
| 135 | +### Use context.logger for log deduplication |
| 136 | + |
| 137 | +Always use `context.set_logger()` and `context.logger` instead of using the Powertools Logger directly. This ensures logs are deduplicated during replays. |
| 138 | + |
| 139 | +```python title="Recommended logging pattern" |
| 140 | +--8<-- "examples/lambda_features/durable_functions/src/best_practice_logging.py" |
| 141 | +``` |
| 142 | + |
| 143 | +### Emit metrics at workflow completion |
| 144 | + |
| 145 | +To avoid counting replays as new executions, emit metrics only when the workflow completes successfully. |
| 146 | + |
| 147 | +```python title="Metrics at completion" |
| 148 | +--8<-- "examples/lambda_features/durable_functions/src/best_practice_metrics.py" |
| 149 | +``` |
| 150 | + |
| 151 | +### Use Idempotency for ESM triggers |
| 152 | + |
| 153 | +When your durable function is triggered by Event Source Mappings (SQS, Kinesis, DynamoDB Streams), use the `@idempotent` decorator to protect against duplicate invocations. |
| 154 | + |
| 155 | +```python title="Idempotency for ESM" |
| 156 | +--8<-- "examples/lambda_features/durable_functions/src/best_practice_idempotency.py" |
| 157 | +``` |
| 158 | + |
| 159 | +## FAQ |
| 160 | + |
| 161 | +### Do I need Idempotency utility with Durable Functions? |
| 162 | + |
| 163 | +It depends on your use case. Steps within a durable function are already idempotent via checkpoints. However, the `@idempotent` decorator is useful for protecting the Lambda handler entry point, especially for Event Source Mapping invocations (SQS, Kinesis, DynamoDB Streams) where the same event might trigger multiple invocations. |
| 164 | + |
| 165 | +### Why do I see duplicate logs? |
| 166 | + |
| 167 | +If you're using the logger directly instead of `context.logger`, logs will be emitted on every replay. Use `context.set_logger(logger)` and then `context.logger.info()` to get automatic log deduplication. |
| 168 | + |
| 169 | +### How do I correlate logs across replays? |
| 170 | + |
| 171 | +Use the `execution_arn` field that's automatically added to every log entry when using `context.logger`: |
| 172 | + |
| 173 | +```sql |
| 174 | +fields @timestamp, @message, execution_arn |
| 175 | +| filter execution_arn = "arn:aws:lambda:us-east-1:123456789012:function:my-function:execution-id" |
| 176 | +| sort @timestamp asc |
| 177 | +``` |
| 178 | + |
| 179 | +### Can I use Tracer with Durable Functions? |
| 180 | + |
| 181 | +Yes, but be aware that each execution (including replays) creates separate trace segments. Use the `execution_arn` as a correlation identifier for end-to-end visibility. |
| 182 | + |
| 183 | +### How should I emit metrics without duplicates? |
| 184 | + |
| 185 | +Emit metrics at workflow completion rather than during intermediate steps. This ensures you count completed workflows, not replay attempts. |
0 commit comments