Triggering Lambda Durable Functions from SQS
Table of Contents
Lambda durable functions, introduced in re:Invent 2025, are a great fit for long-running workflows that need to wait for external events, callbacks, or simply pause between steps. A single durable execution can run up to 1 year, which opens up a lot of use cases that previously required Step Functions or custom orchestration.
Even though the execution can span up to 1 year, it is better to be clear about what “1 year” actually refers to. A durable execution is not a single Lambda invocation that stays alive for a year. A durable execution can consist of multiple separate invocations. Between those invocations, the execution can be moved to wait state or go to sleep and you will not be charged for that. Every one of those individual invocations still has to finish within the standard 15 minute Lambda function timeout. And, the total duration of those individual invocations and the wait time must be maximum of 1 year. From the caller’s perspective the execution can span hours, days, or up to a year, even though a single invocation must run for maximum 15 minutes.
However, this is not always true. When you start invoking a durable function from an event source mapping (ESM), such as SQS, Kinesis, or DynamoDB Streams, that total duration of the execution is limited to only 15 minutes. This is including intermediate invocations and the waits.
In this blog post, I discuss the solution that AWS provides to work around this 15 minute limitation and another (better?) alternative.
Why the 15 minute limit exists #
Event source mappings poll the source (SQS, Kinesis, etc.) and invoke the target Lambda function synchronously. The poller holds the connection open and waits for the function to return before it marks records as processed.
For a standard Lambda function this is fine, because the maximum function timeout is 15 minutes anyway. But for a durable function, the whole durable execution (steps, waits, callbacks, everything from start to finish) must also fit inside that same synchronous call. So even though the underlying durable execution model supports up to 1 year, the synchronous nature of ESM caps the total execution time at 15 minutes.
Please note: When using an ESM based trigger, Durable Functions cannot be configured with an execution timeout longer than 15 minutes. Attempting to do so will cause ESM creation to fail.
The recommended workaround: using an intermediary function #
AWS recommends solving this limitation by adding a standard Lambda function between the event source mapping and the durable function:
- The ESM invokes the intermediary Lambda synchronously.
- The intermediary Lambda invokes the durable function asynchronously (
InvocationType=Event) using the Lambda Invoke API. - The intermediary Lambda returns success immediately, and the ESM is happy.
- And, the durable function then runs on its own, independent of the ESM, for as long as it needs (up to 1 year).
The intermediary function is an essential piece here, but now you own and maintain a Lambda function whose only job is to forward an event.
A cleaner approach: EventBridge Pipes #
EventBridge Pipes can be the bridge between an event source and a Lambda target, and the target invocation can be configured as fire-and-forget (asynchronous). That is exactly the behavior we need. The source side polling is decoupled from the durable execution, and there is no intermediary Lambda to write or maintain.
The Pipe polls the SQS queue and invokes the durable function asynchronously. The Pipe considers the message processed as soon as the asynchronous invoke succeeds, not when the durable execution completes. The durable function is then free to run for a longer time.
Try this yourself #
The full code is available at github.com/pubudusj/sqs-to-lambda-durable-function-with-pipes.
Deploy it to your own AWS account using AWS CDK and Python:
- Clone the repository and create a virtual environment:
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
- Deploy the stack:
cdk deploy
- Send a test message to the
QueueUrloutput from the stack:
aws sqs send-message \
--queue-url <QueueUrl> \
--message-body '{"hello": "durable"}'
- Open the durable function in the Lambda console using the
LambdaFunctionNamestack output and watch the execution. You will see the firstprint_event_before_waitlog entry almost immediately, then the wait continues for 30 minutes, then theprint_event_after_waitlog entry. The execution completes successfully even though it took twice as long as a standard ESM invoked Lambda would allow.
Please note: In both the approaches the Pipe or intermediary function succeeds when the async invoke is accepted, not when the durable execution succeeds. If the durable function fails internally (an exception in a step or a callback times out etc), that failure is visible inside the durable execution history, but the SQS source has already considered the message processing is done. It is advised to build your error handling inside the durable function itself for such failures. Source queue level error handling will manage anything that failed to trigger the Pipe or intermediary function.
Summary #
Durable functions are a new way of building long-running, multi-step workflows on Lambda, but the 15 minute ceiling that appears the moment you put an event source mapping in front of them can be a real constraint. The workaround is to use an intermediary Lambda that asynchronously invokes the durable function, but you have to own and manage it.
EventBridge Pipes does the same job natively. By configuring the Pipe target with FIRE_AND_FORGET, you get the same decoupling between the synchronous poller of ESM and the long-running durable execution, without owning or managing a Lambda function.
If you are reaching for durable functions to handle SQS messages with steps, waits, or callbacks that exceed 15 minutes, using Pipes can be a better option than using an intermediary function.
Resources #
- Lambda durable functions overview: https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html
- Event source mappings with durable functions: https://docs.aws.amazon.com/lambda/latest/dg/durable-invoking-esm.html
- Amazon EventBridge Pipes targets: https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-pipes-event-target.html
👋 I regularly create content on AWS and Serverless, and if you’re interested, feel free to follow / connect with me so you don’t miss out on my latest posts!
- LinkedIn: https://www.linkedin.com/in/pubudusj
- Twitter/X: https://x.com/pubudusj