fix(lambda): publish stable alias for durable functions#13589
Conversation
Durable Lambda functions require qualified ARNs for invocation -
AWS rejects unqualified invocations with InvalidParameterValueException.
This affected every event source the framework wired with an unqualified
target (scheduled events, EventBridge, SNS, API Gateway, etc.) since
they all emit `Fn::GetAtt: [Function, Arn]` by default.
A `$LATEST` qualifier is not a generalizable fix because AWS rejects
`$LATEST` on `AWS::Lambda::Permission` ("We currently do not support
adding policies for $LATEST"), which most non-scheduler event sources
rely on.
Auto-create an `AWS::Lambda::Alias` named `durable` for every function
with `durableConfig`, mirroring the existing snapStart and
provisionedConcurrency alias patterns. Set `functionObject.targetAlias`
so all downstream consumers pick up the alias via the existing
`resolveLambdaTarget` plumbing - no per-event-source changes needed.
Reject the `durableConfig + versionFunction: false` combination
explicitly, since it would produce broken CFN with a dangling Version
reference.
Closes #13587
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
📝 WalkthroughWalkthroughAdds durable Lambda alias support: naming helpers, validation that disables incompatible configs, automatic creation of a stable ChangesDurable Lambda Alias Support
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/serverless/test/unit/lib/plugins/aws/package/compile/functions.test.js (1)
449-480: ⚡ Quick winTest name overstates provisionedConcurrency coverage.
This case validates only
snapStart, but the title claimssnapStartorprovisionedConcurrency. Either rename it or add a dedicatedprovisionedConcurrencyprecedence test to match the stated contract.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/serverless/test/unit/lib/plugins/aws/package/compile/functions.test.js` around lines 449 - 480, The test titled "should not overwrite a targetAlias already set by snapStart or provisionedConcurrency" only exercises snapStart; either rename the test to reflect snapStart-only behavior (e.g., mention snapStart precedence) or add a separate test that sets up provisionedConcurrency on the function and asserts the same precedence behavior; locate the test suite using the existing it(...) block around the awsCompileFunctions.compileFunctions invocation and the func fixture to update the test name or duplicate the block with provisionedConcurrency configured to verify its precedence.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/sf/providers/aws/guide/functions.md`:
- Line 455: Update the Durable Functions note to explicitly state the exception:
when durableConfig is enabled it normally sets versionFunctions: true and
publishes an AWS::Lambda::Alias named durable and targets that alias for
event-source integrations, but if another feature already sets a target alias
(e.g., snapStart or provisionedConcurrency via targetAlias), the durable alias
creation is skipped and integrations will target the existing alias instead;
also mention that setting versionFunctions: false together with durableConfig
remains rejected.
---
Nitpick comments:
In
`@packages/serverless/test/unit/lib/plugins/aws/package/compile/functions.test.js`:
- Around line 449-480: The test titled "should not overwrite a targetAlias
already set by snapStart or provisionedConcurrency" only exercises snapStart;
either rename the test to reflect snapStart-only behavior (e.g., mention
snapStart precedence) or add a separate test that sets up provisionedConcurrency
on the function and asserts the same precedence behavior; locate the test suite
using the existing it(...) block around the awsCompileFunctions.compileFunctions
invocation and the func fixture to update the test name or duplicate the block
with provisionedConcurrency configured to verify its precedence.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 3a0ac771-a6d2-4bc8-86a9-9630a59050fc
📒 Files selected for processing (4)
docs/sf/providers/aws/guide/functions.mdpackages/serverless/lib/plugins/aws/lib/naming.jspackages/serverless/lib/plugins/aws/package/compile/functions.jspackages/serverless/test/unit/lib/plugins/aws/package/compile/functions.test.js
| ``` | ||
|
|
||
| **Note:** Durable Functions are currently supported only for Node.js 22+ and Python 3.13+ runtimes. Enabling `durableConfig` will automatically enable function versioning (`versionFunctions: true`) as durable functions require qualified ARNs. | ||
| **Note:** Durable Functions are currently supported only for Node.js 22+ and Python 3.13+ runtimes. Enabling `durableConfig` will automatically enable function versioning (`versionFunctions: true`) and publish an `AWS::Lambda::Alias` named `durable` pointing at the latest version, because AWS rejects unqualified invocations of durable functions. All event-source integrations (schedule, EventBridge, SNS, API Gateway, etc.) target this alias so invocations succeed without further configuration. Setting `versionFunction: false` together with `durableConfig` is rejected. |
There was a problem hiding this comment.
Clarify alias behavior when another feature already sets targetAlias.
The note currently implies durable is always published and always targeted. In practice, this PR skips durable alias creation when snapStart/provisionedConcurrency already set a target alias. Please document that exception explicitly.
Suggested wording tweak
-... publish an `AWS::Lambda::Alias` named `durable` ... All event-source integrations ... target this alias ...
+... publish an `AWS::Lambda::Alias` named `durable` (unless another feature such as SnapStart or provisioned concurrency already sets a target alias) ... Event-source integrations target the resolved target alias ...🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/sf/providers/aws/guide/functions.md` at line 455, Update the Durable
Functions note to explicitly state the exception: when durableConfig is enabled
it normally sets versionFunctions: true and publishes an AWS::Lambda::Alias
named durable and targets that alias for event-source integrations, but if
another feature already sets a target alias (e.g., snapStart or
provisionedConcurrency via targetAlias), the durable alias creation is skipped
and integrations will target the existing alias instead; also mention that
setting versionFunctions: false together with durableConfig remains rejected.
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit a1414b3. Configure here.
Summary
Fixes durable Lambda functions failing to be invoked through any event source the framework wires with an unqualified ARN (
Fn::GetAtt: [Function, Arn]). AWS rejects unqualified invocations of durable functions with:Affected event sources include scheduled events (both
method: schedulerandmethod: eventBus), SNS, API Gateway, and every other source that relies on the framework's standard target wiring.Why an alias and not
$LATESTA blanket
$LATESTqualifier is not viable: AWS rejects$LATESTonAWS::Lambda::Permission("We currently do not support adding policies for $LATEST"), which is required by most non-scheduler event sources. The only qualifier that works uniformly acrossRule.Target.Arn,Subscription.Endpoint,Lambda::Permission.FunctionName,EventInvokeConfig.Qualifier, etc. is a real alias or numeric version. An alias is the stable choice — same rationale used forsnapStartandprovisionedConcurrencyaliases.Changes
packages/serverless/lib/plugins/aws/package/compile/functions.js— whenfunctionObject.durableConfigis set andfunctionObject.targetAliasis not already set by snapStart/provisionedConcurrency, auto-create anAWS::Lambda::Aliasnameddurablepointing at the publishedAWS::Lambda::Version, and populatefunctionObject.targetAlias. Mirrors the existing snapStart block at the same line region.packages/serverless/lib/plugins/aws/package/compile/functions.js— throwFUNCTION_DURABLE_REQUIRES_VERSIONINGearly whendurableConfigis combined withversionFunction: false, since that combination would generate broken CloudFormation referencing a non-existent Version resource.packages/serverless/lib/plugins/aws/lib/naming.js— addgetLambdaDurableAliasLogicalId(functionName)andgetLambdaDurableEnabledAliasName()helpers, following thesnapStartnaming convention.docs/sf/providers/aws/guide/functions.md— update the Durable Functions note to describe the alias and theversionFunction: falserejection.packages/serverless/test/unit/lib/plugins/aws/package/compile/functions.test.js— five new tests insideDurable Functions Support > Alias:functionObject.targetAliasis populated for downstream consumerstargetAlias(e.g. fromsnapStart) wins; no double-aliasingversionFunction: true+durableConfigpositive caseversionFunction: false+durableConfigrejectionIAM impact
None on identity-based policies — the scheduler role's
lambda:InvokeFunctionalready coversfunction:NAME:*, which matches any alias name. The AWS-managedAWSLambdaBasicDurableExecutionRolePolicyisResource: "*"and works for any qualifier. Resource-basedLambda::Permissionresources have theirFunctionNamechange from unqualified to alias-qualified — this is the actual fix mechanism.Test plan
npm test— 1710/1710 unit tests passnpm run lint— cleannpm run prettier— cleanevents.schedulemethod: scheduler— verified invocations succeed, alias-qualified targetevents.schedulemethod: eventBus— verified invocations succeed, alias-qualified Target and Permissionevents.sns— verified SNS delivery succeeds and Lambda is invoked through the aliasBackwards compatibility
For functions without
durableConfig, the generated CloudFormation is byte-identical. For existing durable users, the upgrade deploy adds oneAWS::Lambda::Aliasresource and changesLambda::Permission.FunctionNameto alias-qualified (a CFN resource replacement). Since durable + event sources was not working before this fix, the transition turns a broken stack into a working one without regressing any previously-working path.Closes #13587
Summary by CodeRabbit
New Features
Bug Fixes / Validation
Documentation
Note
Medium Risk
Changes CloudFormation for durable functions (new alias, qualified permissions/targets) and affects all event-source wiring via
targetAlias, though non-durable stacks are unchanged and behavior matches existing snapStart alias patterns.Overview
Fixes durable Lambda deployments so framework-wired event sources invoke a qualified target instead of an unqualified function ARN, which AWS rejects for durable functions.
When
durableConfigis set and no other feature already chose an alias (snapStart, provisioned concurrency), compile now emits anAWS::Lambda::Aliasnameddurableon the latest published version and setsfunctionObject.targetAliasso schedules, SNS, API Gateway, permissions, and similar integrations follow the same alias path as other versioned features.versionFunction: falsewithdurableConfigfails fast withFUNCTION_DURABLE_REQUIRES_VERSIONING. Naming helpers and docs describe the alias and rejection; unit tests cover alias creation,targetAlias, precedence, and the versioning guard.Reviewed by Cursor Bugbot for commit a1414b3. Bugbot is set up for automated code reviews on this repo. Configure here.