feat(lambda): optional version-pinned provisioned concurrency#1110
Merged
Conversation
Add ProvisionedConcurrencyProps.onVersion (default false). When true,
PC + autoscaling attach to the function's published version
(function:<fn>:<version>) instead of the alias
(function:<fn>:<aliasName>).
Why
---
When PC is on the alias, every CFN alias update that changes
FunctionVersion triggers Lambda's built-in canary behaviour: CFN sets
RoutingConfig.AdditionalVersionWeights to keep traffic on the old
version until PC is allocated on the new one. If the new version's
init fails (FUNCTION_ERROR_INIT_FAILURE), the routing weights persist
at 100% on old, and every subsequent deploy fails with "Invalid alias
configuration for Provisioned Concurrency" because Lambda forbids
PC + routing config on the same alias update. The stack wedges until
an operator manually `update-alias --routing-config '{}'`s.
We hit this on keystone-storefront: a layer-shrink dropped
fast-safe-stringify from the standalone bundle, v85 failed init, alias
canary pinned to v84, all subsequent deploys (v86, v87) failed with
the same alias error even after fixing the bundle. Required manual
alias clearing on five lambdas across two deploys.
Attaching PC to the version sidesteps this entirely: the alias
carries no PC, so version swaps are atomic and never set routing
weights. PC warms the new version because CDK publishes a new
currentVersion on every code change and the inline PC config +
autoscaling target attach to that version.
Trade-off
---------
ApplicationAutoScaling target's resource ID embeds the version
number, so one target accumulates per deploy. Regional soft limit is
2,500 targets — fine for normal cadence; worth noting for runaway
rebuild scenarios. Old PC configs get cleaned up when CDK detaches
the underlying CfnVersion.
Implementation
--------------
- types.ts: extend ProvisionedConcurrencyProps with the onVersion flag
and a paragraph documenting the canary-trap rationale.
- main.ts: branch in createLambdaFunction's alias loop. When
onVersion is set, call a new attachProvisionedConcurrencyToVersion
helper that:
1. Sets provisionedConcurrencyConfig inline on the published
CfnVersion (CDK doesn't expose a standalone
AWS::Lambda::ProvisionedConcurrencyConfig L1).
2. Creates a ScalableTarget with resource id
function:<fn>:<version> and a target-tracking policy using
PredefinedMetric.LAMBDA_PROVISIONED_CONCURRENCY_UTILIZATION.
Tests
-----
- New testLambdaWithVersionPinnedConcurrency fixture in
lambdas.json + matching create in TestCommonConstruct.
- Four new assertions:
1. CfnVersion carries ProvisionedConcurrencyConfig
(ProvisionedConcurrentExecutions: 1).
2. The lambda's alias has NO ProvisionedConcurrencyConfig.
3. ScalableTarget exists with resource id built from a
Fn::GetAtt to <CurrentVersion>.Version (i.e. version-scoped).
4. ScalingPolicy uses
LambdaProvisionedConcurrencyUtilization with target 0.7.
- Bumped existing resourceCountIs: AWS::Lambda::Function 7 → 8,
AWS::Lambda::Alias 2 → 3.
1,285 tests pass, lint clean, build clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
When provisioned concurrency is attached to a Lambda alias, every CloudFormation alias update that changes
FunctionVersiontriggers Lambda's built-in canary deploy behaviour — CFN setsRoutingConfig.AdditionalVersionWeightsto keep traffic on the old version until PC allocates on the new one. If the new version's init fails (FUNCTION_ERROR_INIT_FAILURE), those routing weights persist at 100% on old, and every subsequent deploy fails with:because Lambda forbids
RoutingConfigandProvisionedConcurrencyConfigon the same alias update. The stack ends up wedged until an operator manually runsaws lambda update-alias --routing-config '{}'.We hit this on
keystone-storefront: a layer-shrink droppedfast-safe-stringifyfrom the Next standalone bundle, v85 failed init, alias canary pinned to v84, and v86/v87 both failed with the same alias error even after fixing the bundle. Required manual alias clearing on five lambdas across two deploys to unstick.What
Add
onVersion?: booleantoProvisionedConcurrencyProps(defaultfalse). Whentrue:CfnVersion(no standaloneAWS::Lambda::ProvisionedConcurrencyConfigL1 exists in CDK).AWS::ApplicationAutoScaling::ScalableTargetis created withResourceId: function:<fn>:<version>and a target-tracking policy usingPredefinedMetric.LAMBDA_PROVISIONED_CONCURRENCY_UTILIZATION.Trade-off
The autoscaling target's
ResourceIdembeds the version number, so one target accumulates per deploy. Regional soft limit is 2,500 scalable targets per region per account — fine for normal cadence; worth watching for runaway-rebuild scenarios.Backwards compatibility
Default is
false. Existing consumers that don't setonVersionkeep alias-based PC behaviour exactly as before.