Add lambda.DurableFunction blueprint (vs2026)#2445
Conversation
| <PackageReference Include="Amazon.Lambda.Core" Version="3.1.1" /> | ||
| <PackageReference Include="Amazon.Lambda.Serialization.SystemTextJson" Version="3.0.0" /> | ||
| <PackageReference Include="Amazon.Lambda.Annotations" Version="2.0.1" /> | ||
| <PackageReference Include="Amazon.Lambda.DurableExecution" Version="0.1.1-preview" /> |
There was a problem hiding this comment.
will update to ga version once released
| <ItemGroup> | ||
| <PackageReference Include="Amazon.Lambda.Core" Version="3.1.1" /> | ||
| <PackageReference Include="Amazon.Lambda.TestUtilities" Version="4.1.0" /> | ||
| <PackageReference Include="Amazon.Lambda.DurableExecution.Testing" Version="0.0.1-preview" /> |
There was a problem hiding this comment.
since this pr isnt merged yet, i tested with local nuget feed.
# 1. Pack the three required packages into a local feed
FEED=/tmp/durable-feed && mkdir -p "$FEED"
cd Libraries/src/Amazon.Lambda.Annotations && dotnet pack -c Release -o "$FEED"
cd ../Amazon.Lambda.DurableExecution && dotnet pack -c Release -o "$FEED"
cd ../Amazon.Lambda.DurableExecution.Testing && dotnet pack -c Release -o "$FEED"
# 2. Install the template from the blueprint folder
cd <repo>/Blueprints/BlueprintDefinitions/vs2026/DurableFunction/template/src/BlueprintBaseName.1
dotnet new install . # or install from the .template.config location
# 3. Instantiate into a scratch dir
mkdir /tmp/dtest && cd /tmp/dtest
dotnet new lambda.DurableFunction --name MyOrders
# 4. Build + test against the local feed
dotnet test --source "$FEED" --source https://api.nuget.org/v3/index.json
| @@ -0,0 +1,39 @@ | |||
| { | |||
There was a problem hiding this comment.
intentionally only added to vs2026. didnt feel like it was worth adding to 2024 folder since dotnet8 will be end of life soon
|
The test project isn't actually bundled when doing a new project (same with other projects) but adding here to be consistent |
normj
left a comment
There was a problem hiding this comment.
The pattern of the template library is templates that start with the lambda. prefix deploy directory to Lambda. For example using the dotnet lambda deploy-function command. For templates that deploy via CloudFormation start with serverless. and you would deploy via the dotnet lambda deploy-serverless command.
I suggest we have 2 templates. One that goes directly to Lambda and uses the static wrapper method instead of annotations so it can be deploy straight to Lambda. Then a second serverless.* template that is what you have here.
The test project is still useful when you create the template via Visual Studio. |
philasmar
left a comment
There was a problem hiding this comment.
approving assuming you address norm's feedback
|
@normj updated to have two templates and i retested both |
|
aws/aws-extensions-for-dotnet-cli#447 needs to be merged and released first |
| Durable functions are invoked with a qualified function reference and a durable execution name: | ||
|
|
||
| ```bash | ||
| dotnet lambda invoke-function BlueprintBaseName.1 --payload '{"OrderId":"order-123","Items":["sku-1","sku-2"]}' |
There was a problem hiding this comment.
Can you add the --invoke-model switch for Durable functions?
| The workflow validates the order, charges payment, waits out a short settlement period, ships the | ||
| order in a child context, and returns the result. | ||
|
|
||
| ## Test |
There was a problem hiding this comment.
Don't have this section since the test project will only exist if the create the project via Visual Studio. You could have a more general section about how to test and and pointing out the Amazon.Lambda.DurableExecution.Testing project. Just don't say there is a Test project.
| ## Test | ||
|
|
||
| The included test project drives the workflow locally with the | ||
| `Amazon.Lambda.DurableExecution.Testing` runner — no AWS resources required: |
There was a problem hiding this comment.
I would be careful calling it a runner or make it more clear that it isn't a test runner but a durable functions runner. That sounds like this is our own flavor of xUnit or mstest which are test runners.
| "display-name": "Durable Function", | ||
| "system-name": "DurableFunction", | ||
| "description": "A durable execution workflow that checkpoints every step, so it can be suspended during waits and resumed after a crash without re-running completed work. Deploys straight to Lambda with the 'dotnet lambda deploy-function' command.", | ||
| "sort-order": 130, |
There was a problem hiding this comment.
| <ItemGroup> | ||
| <PackageReference Include="Amazon.Lambda.Core" Version="3.1.1" /> | ||
| <PackageReference Include="Amazon.Lambda.Serialization.SystemTextJson" Version="3.0.0" /> | ||
| <PackageReference Include="Amazon.Lambda.Annotations" Version="2.0.1" /> |
There was a problem hiding this comment.
I think you want version 2.1.0 of Annotations where it looks like the DurableExecution attribute was added.
There was a problem hiding this comment.
yes your right, i think i built it locally which is why it picked up an old version. will update
| The workflow validates the order, charges payment, waits out a short settlement period, ships the | ||
| order in a child context, and returns the result. | ||
|
|
||
| ## Test |
There was a problem hiding this comment.
Same comments as the previous README about the test section
| After deploying, invoke the function with a sample order payload: | ||
|
|
||
| ```bash | ||
| dotnet lambda invoke-function BlueprintBaseName.1 --payload '{"OrderId":"order-123","Items":["sku-1","sku-2"]}' |
There was a problem hiding this comment.
Same comment about using --invoke-mode.
Also BlueprintBaseName.1 is unlikely to the function name because CloudFormation is going generate the function name. So you might need to give some context on how to find the function name.
| "display-name": "Durable Function", | ||
| "system-name": "DurableFunction", | ||
| "description": "A durable execution workflow that checkpoints every step, so it can be suspended during waits and resumed after a crash without re-running completed work.", | ||
| "sort-order": 130, |
|
Can you also add the new blueprints to this list in the buildtools targets? It is at target I use to sanity check that all of the blueprints can be instantiated and compiled. https://github.com/aws/aws-lambda-dotnet/blob/master/buildtools/build.proj#L70 |
|
i found a bug in my annotations library. apparently it was generating an empty durableconfig object (even though ExecutionTimeout is a required) param which is causing the serverless template to fail. i will make a PR to fix that first. also makes me wonder how https://github.com/aws/aws-extensions-for-dotnet-cli/blob/master/src/Amazon.Lambda.Tools/Commands/UpdateFunctionConfigCommand.cs#L476 works if user doesnt specifcy an executiontimeout? @normj ill have to check |
Adds a new 'dotnet new' template (shortName: lambda.DurableFunction) under Blueprints/BlueprintDefinitions/vs2026 that scaffolds a Lambda durable execution workflow using the Annotations class-library programming model on the managed dotnet10 runtime. The sample workflow demonstrates the core durable primitives: StepAsync, a step with an exponential RetryStrategy and AtMostOncePerRetry semantics, WaitAsync (suspend timer), and RunInChildContextAsync. The generated serverless.template includes DurableConfig and the AWSLambdaBasicDurableExecutionRolePolicy managed policy. A test project drives the workflow locally via Amazon.Lambda.DurableExecution.Testing. Also registers the template in Blueprints/README.md.
The single DurableFunction blueprint was labeled `lambda.DurableFunction` but shipped a serverless.template and deployed via `deploy-serverless` (the Annotations model) — a naming/convention mismatch. Follow the SimpleS3Function / SimpleS3FunctionServerless pattern and provide both: - DurableFunction (lambda.DurableFunction): deploys straight to Lambda with `dotnet lambda deploy-function`. Uses the static-wrapper, class-library programming model (DurableFunction.WrapAsync + [assembly: LambdaSerializer], no [DurableExecution], no serverless.template). aws-lambda-tools-defaults.json carries function-handler/function-runtime and the new durable-execution-timeout key. (Requires the deploy-function durable support from aws-extensions-for-dotnet-cli PR #447.) - DurableFunctionServerless (serverless.DurableFunction): the existing Annotations + serverless.template blueprint, relabeled to the serverless.* identity and deployed via `dotnet lambda deploy-serverless`. Both build and their test projects pass. The lambda.DurableFunction variant was verified end-to-end on the managed dotnet10 runtime (DurableConfig set, durable IAM policy auto-attached, workflow runs to SUCCEEDED).
- Fix VS wizard sort-order: 124 (lambda, near Powertools) and 120 (serverless, near Annotations) - Bump serverless template Annotations reference to 2.1.0 (adds [DurableExecution]) - Document --invoke-mode DurableExecution in both Invoke sections - Explain how to find the CloudFormation-generated function name (serverless) - Reword Test sections: don't assume a test project exists; describe the Amazon.Lambda.DurableExecution.Testing runner without implying an xUnit-style test runner
Adds lambda.DurableFunction and serverless.DurableFunction (vs2026, C#) to the test-blueprints-dotnew target so both are instantiated and compiled.
4351586 to
15e87e9
Compare
| <ItemGroup> | ||
| <PackageReference Include="Amazon.Lambda.Core" Version="3.1.1" /> | ||
| <PackageReference Include="Amazon.Lambda.Serialization.SystemTextJson" Version="3.0.0" /> | ||
| <PackageReference Include="Amazon.Lambda.Annotations" Version="2.1.0" /> |
There was a problem hiding this comment.
need #2453 to ship and then update version here
…2453) The Annotations [DurableExecution] attribute now requires executionTimeout as a constructor argument, and the source generator no longer emits an empty DurableConfig block (which CloudFormation rejects at deploy time). - Function.cs: [DurableExecution] -> [DurableExecution(executionTimeout: 86400)] - serverless.template: populate DurableConfig.ExecutionTimeout; bump managed version marker to v2.2.0.0 - csproj: Amazon.Lambda.Annotations 2.1.0 -> 2.2.0 - Readme: document the required executionTimeout argument Verified end-to-end: both durable blueprints deploy (deploy-function and deploy-serverless/CloudFormation) and run to ExecutionSucceeded on managed dotnet10 in us-east-1.


Summary
Provides two
dotnet newtemplates underBlueprints/BlueprintDefinitions/vs2026for Lambda durable execution workflows, following the existinglambda.*/serverless.*convention (e.g.SimpleS3Function/SimpleS3FunctionServerless):lambda.DurableFunctionDurableFunction.WrapAsync), class-librarydotnet lambda deploy-functionserverless.DurableFunction[LambdaFunction]+[DurableExecution])dotnet lambda deploy-serverlessserverless.templateBoth target the managed dotnet10 runtime (durable execution requires dotnet10) and scaffold the same sample
ProcessOrderworkflow demonstrating the core durable primitives:StepAsync— checkpointed stepStepAsync+RetryStrategy.ExponentialwithStepSemantics.AtMostOncePerRetryWaitAsync— suspend timer (no compute charge while suspended)RunInChildContextAsync— grouping related stepsEach ships a test project that drives the workflow locally via
Amazon.Lambda.DurableExecution.Testing(no AWS resources needed). vs2026 only (matches the existing layout convention).Why two templates
The original single blueprint was labeled
lambda.DurableFunctionbut shipped aserverless.templateand deployed viadeploy-serverless— a naming/convention mismatch. This splits it so thelambda.*name actually deploys straight to Lambda, and the CloudFormation path keeps its ownserverless.*name.Using the templates
lambda.DurableFunction— deploy straight to Lambdadotnet new lambda.DurableFunction --name MyDurableApp cd MyDurableApp/src/MyDurableApp dotnet lambda deploy-functionHandlerdelegates toDurableFunction.WrapAsync<OrderRequest, OrderResult>(ProcessOrder, …); the serializer is declared with[assembly: LambdaSerializer(typeof(DefaultLambdaJsonSerializer))]. NoMain, no[DurableExecution], noserverless.template.aws-lambda-tools-defaults.jsoncarriesfunction-runtime: dotnet10, theAssembly::Type::Methodfunction-handler, anddurable-execution-timeout.deploy-functioncreates the execution role for you, it auto-attachesAWSLambdaBasicDurableExecutionRolePolicy(the checkpoint permissions). If you pass--function-role, attach that policy yourself.deploy-functiondurable support fromaws-extensions-for-dotnet-cliPR #447 (thedurable-execution-timeoutswitch + IAM auto-attach). Until that ships in a releasedAmazon.Lambda.Tools,deploy-functionwon't apply the durable config.serverless.DurableFunction— deploy via CloudFormationdotnet new serverless.DurableFunction --name MyDurableApp cd MyDurableApp/src/MyDurableApp dotnet lambda deploy-serverless[LambdaFunction]+[DurableExecution]. The source generator emits the handler wrapper and keepsserverless.templatein sync —DurableConfigplus theAWSLambdaBasicDurableExecutionRolePolicymanaged policy.Amazon.Lambda.Annotationsthat supports[DurableExecution].Run the local tests (either template)
dotnet testTesting
lambda.DurableFunctioninstantiated (placeholder substitution) and built against the published durable preview packages.lambda.DurableFunctionwith the PR Auto-attach durable execution IAM policy in deploy-function aws-extensions-for-dotnet-cli#447 CLI build →DurableConfig.ExecutionTimeoutset,AWSLambdaBasicDurableExecutionRolePolicyauto-attached to the tool-created role, and the workflow ran to SUCCEEDED (all six operations checkpointed, including theWaitAsyncsuspend/resume). Resources torn down afterward.Notes
lambda.DurableFunctionis gated onaws-extensions-for-dotnet-cliPR #447 landing in a releasedAmazon.Lambda.Tools.Amazon.Lambda.DurableExecution/.Testingare preview packages; the templates reference0.1.1-preview/0.0.1-preview. Restores once those are published (or via a local feed)..autoverchange file needed (autover tracksLibraries/srcprojects only).