Skip to content

Refactor Lambda SDK references by language + add support for .NET SDK - #11

Open
starfleeth wants to merge 3 commits into
mainfrom
codex/refactor-sdk-references
Open

Refactor Lambda SDK references by language + add support for .NET SDK #11
starfleeth wants to merge 3 commits into
mainfrom
codex/refactor-sdk-references

Conversation

@starfleeth

Copy link
Copy Markdown
Collaborator

Moves AWS Lambda SDK-specific APIs, examples, packaging, observability, and diagnostics into provider-scoped language reference files. Keeps setup, observability, and diagnostics focused on shared Lambda lifecycle and infrastructure, and updates all routing documentation. Validation: strict main-to-branch provenance review passed; all 69 changed fenced code blocks are verbatim from main, all technical claims are corroborated by main, routes and links resolve, and git diff --check passes.

@starfleeth
starfleeth requested a review from a team as a code owner September 2, 2026 02:43

@harish-narayanappa-10 harish-narayanappa-10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@harish-narayanappa-10 harish-narayanappa-10 changed the title Refactor Lambda SDK references by language Refactor Lambda SDK references by language + add .NET SDK support changes Sep 2, 2026
@harish-narayanappa-10 harish-narayanappa-10 changed the title Refactor Lambda SDK references by language + add .NET SDK support changes Refactor Lambda SDK references by language + add support for .NET SDK Sep 2, 2026
@harish-narayanappa-10
harish-narayanappa-10 force-pushed the codex/refactor-sdk-references branch from 50735d8 to 51ffbd9 Compare September 3, 2026 17:46
* Add .NET SDK support for Serverless Workers on AWS Lambda

Documents the .NET SDK alongside Go, Python, TypeScript, and Java,
verified against Temporalio.Extensions.Aws.Lambda 1.18.0 (public API read
from the package's own XML documentation) and samples-dotnet@main
src/LambdaWorker, which is maintained code with a test project.

.NET specifics documented:
- Separate NuGet package in lockstep with Temporalio 1.18.0, with
  OpenTelemetry in a second package rather than an extra on the first.
- TemporalLambdaWorker.CreateHandler as the entry point, with sync and
  async configure overloads; registrations go through WorkerOptions.
- Publish must be RID-specific (--runtime linux-x64 / linux-arm64):
  the SDK wraps a native Rust core, libtemporalio_sdk_core_c_bridge.so,
  which a portable publish omits. This is .NET's equivalent of Python's
  manylinux wheels and Go's GOARCH, with the same first-invocation
  failure mode. Includes the sample's presence check.
- The handler string has three colon-separated parts,
  ASSEMBLY::NAMESPACE.TYPE::METHOD -- the only SDK with that shape.
- Worker-level default versioning behavior is AutoUpgrade, where
  TypeScript's is PINNED. Defaults are not uniform; set them explicitly.
- The SSL_CERT_FILE / root CA issue on some Lambda .NET images, which
  presents as a TLS failure that is not a configuration problem.
- Telemetry IAM permissions and --tracing-config Mode=Active, from the
  sample's enable-telemetry.sh.

Also corrects the sample location: the docs link to a branch
(blob/ea/aws-lambda) that no longer exists; the sample is on main at
src/LambdaWorker.

Note that .NET uses --timeout 600 and --memory-size 256, the same as Go,
Python and TypeScript, which supports reading Java's 90/1024 as a
Java-specific choice rather than a documentation inconsistency.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Fold findings from a real .NET deployment into the skill

Deployed a .NET hello-world Worker end to end on Lambda. Three findings,
none of which came from reading documentation.

SSL_CERT_FILE is required, not optional. An otherwise-correct .NET
deployment fails its first invocation with:

  Connection failed: Server connection error:
  tonic::transport::Error(Transport, NativeCertsNotFound)

because AWS's .NET 8 Lambda images force-override SSL_CERT_FILE and the
SDK's Rust core cannot load system root CAs. The variable now appears in
the .NET create-function block and the environment-variable table rather
than only in troubleshooting, since without it the deployment does not
work at all.

The error is also actively misleading: "certs not found" refers to the
OS root CA store, not to any credential, and the connection fails before
authentication is attempted. Diagnostics now says so explicitly and
gives two discriminators, because the natural response -- checking the
API key, Namespace, invocation role and External ID -- is wasted effort.
Only .NET is affected: Python shares the Rust core but its runtime image
does not override the variable, and Java uses the JVM truststore.

Workflow.Logger is silent by default in .NET, because
TemporalWorkerOptions.LoggerFactory defaults to the client's, which is
also unset. Activity Console.WriteLine still reaches CloudWatch, so the
gap looks selective rather than total. That completes a set of three
SDKs with three unrelated causes for the same symptom.

Also adds a caution to iam.md: read the invocation role's policy back
after any update-stack that changes LambdaFunctionARNs. UPDATE_COMPLETE
does not mean the ARNs are well-formed, the list is replaced rather than
merged, and malformed entries silently revoke access for every function
they omit. Includes the zsh $VAR:l expansion trap that produced exactly
that outcome during this run.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* minor updates to readme/sdk config

* minor edits to fix unverifed reference to files

* updates to some .net specifics

* removing .NET related change

* updates to code references again

* minor fix based on copilot suggestion

* Carry dotnet-sdk-support's Java citation fixes into sdk-java.md

The merged branch corrected four unverified doc citations in setup.md's Java
create-function section. The SDK-reference refactor had moved that text to
sdk-java.md, so resolving the merge in favour of the new structure dropped
them. Apply them where the text now lives.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* adding minor change to the top level skill md file

* Drops prose that argues for rules the bold leads already state. No rule or technical claim changes.

  - SKILL.md: remove trailing rationale from four rules; correct the pre-question note to point at steps 2 and 3, not step 2 alone.
  - sdk-*.md: drop "useful" from the "Ordering when sources disagree" heading, which the refactor had copied into all five files.

* remove redundant/repeated information

* addressing review comment - reducing verbosity

* updated based on review comments

* addressed partial set of review comments

* addressing comments to leave java-specific changes out of this pr

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

@DABH DABH left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One fix I'd like before merge (the version field), one .NET accuracy note, and two nits.

Comment thread SKILL.md
name: temporal-serverless
description: 'Deploy and operate Temporal Workers on serverless compute (AWS Lambda) driven by the Worker Controller Instance (WCI). Use when the user mentions: "serverless worker", "Temporal serverless", "Worker Controller Instance", "WCI", "deploy Temporal worker on Lambda", "Lambda packaging", "Lambda timeout", "WCI inspection", "CloudFormation Temporal".'
version: 0.6.0
version: 0.6.1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two problems with this line, both inherited from main but worth fixing here since the PR touches it. The Agent Skills validator rejects a top-level version key (agentskills validate on this branch: "Unexpected fields in frontmatter: version"), which is why 9cfc8fb moved it to metadata.version; ea0b73a then reverted that along with the number. And 0.6.1 is lower than the 0.7.0 we shipped with Java support. Suggest metadata: / version: "0.8.0", since adding an SDK is a feature bump.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correction on two points, after checking the release tooling and the tag history rather than just the validator:

  1. skill-ci's shared package-and-sync workflow releases off the top-level version: in SKILL.md ("edit SKILL.md's version and push"), and in Add Java SDK support for Serverless Workers #9 Amir asked to keep it top-level for consistency across the skill repos. So please ignore my metadata.version suggestion. The validator/tooling mismatch is real, but it's an org-level question for skill-ci, not for this PR.
  2. 0.7.0 was never tagged (the only release is v0.6.0), so 0.6.1 is not below a shipped version.

What's left is only patch vs minor: Java and .NET have both landed since v0.6.0, so 0.7.0 reads as the more accurate bump, but that's a judgment call and I'm fine either way.


## Configure callback

Receives a `TemporalLambdaWorkerOptions` with public `ClientOptions`, `WorkerOptions`, `ShutdownDeadlineBuffer`, and `AddShutdownHook(Func<CancellationToken, Task>)` members. The Task Queue and registrations go through `WorkerOptions` — an ordinary `TemporalWorkerOptions`, so `TaskQueue`, `AddWorkflow<T>()` and `AddActivity(...)` behave exactly as they do for a long-lived Worker. The callback runs **per invocation**.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One .NET-specific precedence detail worth stating here: TemporalLambdaWorker applies TEMPORAL_TASK_QUEUE to WorkerOptions.TaskQueue before the configure callback runs (CreateOptions in TemporalLambdaWorker.cs), so the unconditional assignment in the handler example below wins over the environment variable. That contradicts the shared table in setup.md ("Overrides the value set in code"). The official sample reads the variable itself with a fallback (LambdaWorkerSample.TaskQueue). Either note the precedence here or make the example follow the sample.

@@ -0,0 +1,267 @@
# .NET SDK on AWS Lambda

Sources: [`Temporalio.Extensions.Aws.Lambda` 1.18.0](https://www.nuget.org/packages/Temporalio.Extensions.Aws.Lambda/1.18.0), [Lambda extension source](https://github.com/temporalio/sdk-dotnet/tree/90c4ef35e260ed5bf553de7ef458053da28e3912/src/Temporalio.Extensions.Aws.Lambda), [OpenTelemetry extension source](https://github.com/temporalio/sdk-dotnet/tree/90c4ef35e260ed5bf553de7ef458053da28e3912/src/Temporalio.Extensions.Aws.Lambda.OpenTelemetry), and the [maintained Lambda Worker sample](https://github.com/temporalio/samples-dotnet/tree/6aba4fb9ea08177e303352ec9a4c61e303cefb0e/src/LambdaWorker).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: 90c4ef3 is 28 commits past the 1.18.0 tag (3b6b5be). The only Lambda-directory differences are internal refactors from #844, so nothing is wrong today, but pinning the source links to the release tag keeps them aligned with the 1.18.0 package the rest of the file describes.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concretely: put the release tag in the URL so the source matches the 1.18.0 package. The 1.18.0 nuspec records commit="3b6b5be...", which is exactly what the 1.18.0 tag points at, and the tag reads better than a SHA. The samples-dotnet pin is fine as is, since that repo has no release tags to align with.

Suggested change
Sources: [`Temporalio.Extensions.Aws.Lambda` 1.18.0](https://www.nuget.org/packages/Temporalio.Extensions.Aws.Lambda/1.18.0), [Lambda extension source](https://github.com/temporalio/sdk-dotnet/tree/90c4ef35e260ed5bf553de7ef458053da28e3912/src/Temporalio.Extensions.Aws.Lambda), [OpenTelemetry extension source](https://github.com/temporalio/sdk-dotnet/tree/90c4ef35e260ed5bf553de7ef458053da28e3912/src/Temporalio.Extensions.Aws.Lambda.OpenTelemetry), and the [maintained Lambda Worker sample](https://github.com/temporalio/samples-dotnet/tree/6aba4fb9ea08177e303352ec9a4c61e303cefb0e/src/LambdaWorker).
Sources: [`Temporalio.Extensions.Aws.Lambda` 1.18.0](https://www.nuget.org/packages/Temporalio.Extensions.Aws.Lambda/1.18.0), [Lambda extension source](https://github.com/temporalio/sdk-dotnet/tree/1.18.0/src/Temporalio.Extensions.Aws.Lambda), [OpenTelemetry extension source](https://github.com/temporalio/sdk-dotnet/tree/1.18.0/src/Temporalio.Extensions.Aws.Lambda.OpenTelemetry), and the [maintained Lambda Worker sample](https://github.com/temporalio/samples-dotnet/tree/6aba4fb9ea08177e303352ec9a4c61e303cefb0e/src/LambdaWorker).


## Entry point

**`TemporalLambdaWorker.CreateHandler(version, configure)`** — returns a `Func<object?, ILambdaContext, Task>` that your handler method delegates to. Overloads take either a synchronous `Action<TemporalLambdaWorkerOptions>` or an asynchronous `Func<TemporalLambdaWorkerOptions, Task>` for setup that must await. A further overload taking `TemporalLambdaWorkerHandlerOptions` is an internal test seam and is not for production use.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the TemporalLambdaWorkerHandlerOptions overloads are internal, so they aren't callable from user code at all. Suggest dropping the last sentence rather than describing a non-public overload.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants