Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
1f4bd38
docs: terraform for serverless worker
lennessyy Jun 5, 2026
d396b04
small edit
lennessyy Jun 5, 2026
28f978f
Merge branch 'main' into serverless-terraform
lennessyy Jun 12, 2026
2670e2d
Merge branch 'main' into serverless-terraform
lennessyy Jun 12, 2026
0012da0
Add Java and .NET serverless worker SDK pages, update to Public Preview
lennessyy Jun 12, 2026
3007370
Add snipsync markers for Java and .NET serverless worker docs
lennessyy Jun 16, 2026
6817c32
Fix .NET deploy guide: use --self-contained false, add SSL_CERT_FILE …
lennessyy Jun 17, 2026
aa4ecc0
Merge branch 'main' into serverless-terraform
lennessyy Jun 17, 2026
a53f17c
Add SSL_CERT_FILE to .NET parameter table in deploy guide
lennessyy Jun 17, 2026
e5858df
Add highlighted lines to snipsynced code blocks across all SDK server…
lennessyy Jun 18, 2026
85c6076
Improve serverless worker docs across all SDKs
lennessyy Jun 18, 2026
fdaff04
Align Java deploy guide with sample repo and improve accuracy
lennessyy Jun 19, 2026
171676a
Update docs for recent server and UI changes
lennessyy Jun 29, 2026
0494cad
Merge remote-tracking branch 'origin/main' into serverless-terraform
lennessyy Jun 29, 2026
fd252e0
Merge branch 'main' into serverless-terraform
lennessyy Jun 29, 2026
78e2a39
Merge branch 'main' into serverless-terraform
lennessyy Jun 30, 2026
268a31a
Paraphrase Validate Connection failure modes instead of quoting UI text
lennessyy Jun 30, 2026
2d91737
Merge branch 'main' into serverless-terraform
lennessyy Jul 1, 2026
3e26075
Flag Java Lambda OTel tracing as shimmed, not native
lennessyy Jul 7, 2026
9bd9d1d
Note Serverless Workers are not failover-aware for HA Namespaces
lennessyy Jul 10, 2026
12c5795
Lead with impact before mechanics for HA + Serverless Workers note
lennessyy Jul 10, 2026
d717961
Make Constraints link text more descriptive
lennessyy Jul 10, 2026
9490081
Merge branch 'main' into serverless-terraform
lennessyy Jul 10, 2026
f17dd92
Address review feedback and fix stale anchor after main merge
lennessyy Jul 10, 2026
8846414
Fix inaccurate ramping claim in Versioning constraint row
lennessyy Jul 10, 2026
042cc43
Merge branch 'main' into serverless-terraform
flippedcoder Jul 13, 2026
4f6f85d
Merge branch 'main' into serverless-terraform
flippedcoder Jul 14, 2026
edc5a3f
Merge branch 'main' into serverless-terraform
flippedcoder Jul 15, 2026
419f76d
Merge branch 'main' into serverless-terraform
flippedcoder Jul 17, 2026
9502a12
Merge branch 'main' into serverless-terraform
flippedcoder Jul 20, 2026
4043577
Merge branch 'main' into serverless-terraform
flippedcoder Jul 20, 2026
d575a70
Merge branch 'main' into serverless-terraform
flippedcoder Jul 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/cloud/high-availability/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,21 @@ Failovers between cells are always managed automatically by Temporal. Unlike Mul

## Related considerations

A few other Temporal features interact with High Availability in ways worth understanding before you enable it.

### Serverless Workers

You can use [Serverless Workers](/serverless-workers) with a Namespace that has Multi-region or Multi-cloud Replication,
but without manual intervention, the workloads that failed over to the new region will keep invoking Workers in the old
region. If the compute provider's region is experiencing degraded performance, this may impact your workloads even
though your Temporal Cloud Namespace has failed over successfully.

This is because each compute provider configuration (for example, a Lambda ARN) is scoped to a single region. The
[Worker Controller Instance](/serverless-workers#worker-controller-instance) has no mechanism to detect a failover or
redirect invocations to a Worker in the new active region. To keep processing Workflows after a failover, you must
manually reconfigure the Worker Deployment Version's compute provider to point at a Worker in the new region. See
[Constraints - Serverless Workers](/serverless-workers#constraints).

### External Storage

If your Workflows use [External Storage](/external-storage) to offload large payloads, durability of the external store
Expand Down
298 changes: 298 additions & 0 deletions docs/develop/dotnet/workers/serverless-workers/aws-lambda.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,298 @@
---
id: aws-lambda
title: Serverless Workers on AWS Lambda - .NET SDK
sidebar_label: Serverless Workers on AWS Lambda
description: Write a Temporal Worker that runs on AWS Lambda using the .NET SDK Temporalio.Extensions.Aws.Lambda package.
slug: /develop/dotnet/workers/serverless-workers/aws-lambda
toc_max_heading_level: 4
keywords:
- serverless
- lambda
- aws
- dotnet sdk
- worker
- serverless worker
tags:
- Workers
- .NET SDK
- Serverless
- AWS Lambda
---

import { ReleaseNoteHeader } from '@site/src/components';

<ReleaseNoteHeader featureName="serverlessWorkers" />

The `Temporalio.Extensions.Aws.Lambda` NuGet package lets you run a Temporal Serverless Worker on AWS Lambda.
Deploy your Worker code as a Lambda function, and Temporal Cloud invokes it when Tasks arrive.
Each invocation starts a Worker, polls for Tasks, then gracefully shuts down before a configurable invocation deadline.
You register Workflows and Activities the same way you would with a standard Worker.

For a full end-to-end deployment guide covering AWS IAM setup, compute configuration, and verification, see [Deploy a Serverless Worker on AWS Lambda](/production-deployment/worker-deployments/serverless-workers/aws-lambda).

## Create and run a Worker in Lambda {/* #create-and-run */}

Add the `Temporalio.Extensions.Aws.Lambda` NuGet package:

```bash
dotnet add package Temporalio.Extensions.Aws.Lambda
```

Use `TemporalLambdaWorker.CreateHandler` to create a Lambda handler that runs a Temporal Worker.
Pass a `WorkerDeploymentVersion` and a configure callback that registers your Workflows and Activities.
Assign the result to a static field so the handler is created once during Lambda cold start and reused across invocations.

<!--SNIPSTART dotnet-lambda-worker {"selectedLines": ["1-5", "7-22", "24-25"], "highlightedLines": "10-15"}-->
[src/LambdaWorker/Function.cs](https://github.com/temporalio/samples-dotnet/blob/ea/aws-lambda/src/LambdaWorker/Function.cs)
```cs {10-15}
namespace TemporalioSamples.LambdaWorker;

using Amazon.Lambda.Core;
using Temporalio.Common;
using Temporalio.Extensions.Aws.Lambda;
// ...

public class LambdaFunction
{
private static readonly Func<object?, ILambdaContext, Task> WorkerHandler =
TemporalLambdaWorker.CreateHandler(
new WorkerDeploymentVersion(
LambdaWorkerSample.DeploymentName,
LambdaWorkerSample.BuildId),
Configure);

public Task HandlerAsync(Stream input, ILambdaContext context) =>
WorkerHandler(input, context);

private static void Configure(LambdaWorkerConfig config)
{
LambdaWorkerSample.ConfigureWorkerOptions(config.WorkerOptions);
// ...
}
}
```
<!--SNIPEND-->

The `WorkerDeploymentVersion` is required.
Worker Deployment Versioning is always enabled for Serverless Workers.
Each Workflow must have a [versioning behavior](/worker-versioning#versioning-behaviors), either `AutoUpgrade` or `Pinned`.
Set it per-Workflow with the `[Workflow]` attribute, or set a worker-level default with `DefaultVersioningBehavior` in `DeploymentOptions`.
The default versioning behavior is `AutoUpgrade`.

<!--SNIPSTART dotnet-lambda-worker-workflow {"highlightedLines": "7"}-->
[src/LambdaWorker/SampleWorkflow.workflow.cs](https://github.com/temporalio/samples-dotnet/blob/ea/aws-lambda/src/LambdaWorker/SampleWorkflow.workflow.cs)
```cs {7}
namespace TemporalioSamples.LambdaWorker;

using Microsoft.Extensions.Logging;
using Temporalio.Common;
using Temporalio.Workflows;

[Workflow(VersioningBehavior = VersioningBehavior.Pinned)]
public class SampleWorkflow
{
[WorkflowRun]
public async Task<string> RunAsync(string name)
{
Workflow.Logger.LogInformation("SampleWorkflow started with name: {Name}", name);
var result = await Workflow.ExecuteActivityAsync(
() => Activities.HelloActivity(name),
new() { StartToCloseTimeout = TimeSpan.FromSeconds(10) });
Workflow.Logger.LogInformation("SampleWorkflow completed with result: {Result}", result);
return result;
}
}
```
<!--SNIPEND-->

## Configure the Temporal connection {/* #configure-connection */}

The `Temporalio.Extensions.Aws.Lambda` package automatically loads Temporal client configuration from a TOML config file and environment variables. Refer to [Environment Configuration](/develop/environment-configuration) for more details.

Compared with long-lived Workers, the location of the config file is resolved differently, in the following order:

1. `TEMPORAL_CONFIG_FILE` environment variable, if set.
2. `temporal.toml` in `$LAMBDA_TASK_ROOT` (typically `/var/task`).
3. `temporal.toml` in the current working directory.

The file is optional. If absent, only environment variables are used.

Encrypt sensitive values like TLS keys or API keys. Refer to [AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars-encryption.html) for options.

### TLS/CA loading on Lambda {/* #tls-ca-loading */}

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.

📝 [vale] reported by reviewdog 🐶
[Temporal.Headings] 'TLS/CA loading on Lambda ***********************' should use sentence-style capitalization.


Some AWS Lambda .NET images override the `SSL_CERT_FILE` environment variable in a way that prevents the SDK's Rust-based runtime from loading system root CAs.
If you encounter TLS certificate errors on Lambda, see the [AWS Lambda .NET CA loading workaround](https://github.com/temporalio/sdk-dotnet#aws-lambda-net-ca-loading-issues) in the SDK README.

## Adjust Worker defaults for Lambda {/* #lambda-tuned-defaults */}

The `Temporalio.Extensions.Aws.Lambda` package applies conservative defaults suited to short-lived Lambda invocations.
These differ from standard Worker defaults to avoid overcommitting resources in a constrained environment.

| Setting | Lambda default |
|---|---|
| `MaxConcurrentActivities` | 2 |
| `MaxConcurrentWorkflowTasks` | 10 |
| `MaxConcurrentLocalActivities` | 2 |
| `MaxConcurrentNexusTasks` | 5 |
| `MaxConcurrentWorkflowTaskPolls` | 2 |
| `MaxConcurrentActivityTaskPolls` | 1 |
| `MaxConcurrentNexusTaskPolls` | 1 |
| `MaxCachedWorkflows` | 30 |
| `GracefulShutdownTimeout` | 5 seconds |
| `DisableEagerActivityExecution` | Always `true` |
| `ShutdownDeadlineBuffer` | 7 seconds |

`DisableEagerActivityExecution` is always `true` and cannot be overridden.
Eager Activities require a persistent connection, which Lambda invocations don't maintain.

`ShutdownDeadlineBuffer` is specific to the `Temporalio.Extensions.Aws.Lambda` package.
It controls the time reserved after the worker run budget for worker shutdown and hooks.
The default is 7 seconds.

If your Worker handles long-running Activities, increase `GracefulShutdownTimeout`, `ShutdownDeadlineBuffer`, and the Lambda invocation deadline (`--timeout`) together.
For guidance on how these values relate, see [Tuning for long-running Activities](/serverless-workers#tuning-for-long-running-activities).

## Add observability with OpenTelemetry {/* #add-observability */}

The `Temporalio.Extensions.Aws.Lambda.OpenTelemetry` NuGet package provides OpenTelemetry integration with defaults configured for the [AWS Distro for OpenTelemetry (ADOT)](https://aws-otel.github.io/docs/getting-started/lambda) Lambda layer.
With this enabled, the Worker emits SDK metrics and distributed traces for Workflow and Activity executions.
The ADOT Lambda layer collects this telemetry and can forward traces to AWS X-Ray and metrics to Amazon CloudWatch.

The underlying metrics and traces are the same ones the .NET SDK emits in any environment.
For general observability concepts and the full list of available metrics, see the [SDK metrics reference](/references/sdk-metrics).

Add the OpenTelemetry extension package:

```bash
dotnet add package Temporalio.Extensions.Aws.Lambda.OpenTelemetry
```

Call `LambdaWorkerOpenTelemetry.ApplyDefaults` in the configure callback:

<!--SNIPSTART dotnet-lambda-worker {"highlightedLines": "23"}-->
[src/LambdaWorker/Function.cs](https://github.com/temporalio/samples-dotnet/blob/ea/aws-lambda/src/LambdaWorker/Function.cs)
```cs {23}
namespace TemporalioSamples.LambdaWorker;

using Amazon.Lambda.Core;
using Temporalio.Common;
using Temporalio.Extensions.Aws.Lambda;
using Temporalio.Extensions.Aws.Lambda.OpenTelemetry;

public class LambdaFunction
{
private static readonly Func<object?, ILambdaContext, Task> WorkerHandler =
TemporalLambdaWorker.CreateHandler(
new WorkerDeploymentVersion(
LambdaWorkerSample.DeploymentName,
LambdaWorkerSample.BuildId),
Configure);

public Task HandlerAsync(Stream input, ILambdaContext context) =>
WorkerHandler(input, context);

private static void Configure(LambdaWorkerConfig config)
{
LambdaWorkerSample.ConfigureWorkerOptions(config.WorkerOptions);
LambdaWorkerOpenTelemetry.ApplyDefaults(config);
}
}
```
<!--SNIPEND-->

`ApplyDefaults` configures Temporal tracing with `TracingInterceptor`, creates an OTLP trace exporter and tracer provider, configures Core SDK OTLP metrics, uses AWS X-Ray-compatible trace IDs, and registers a per-invocation shutdown hook that force-flushes traces.
By default, telemetry is sent to `localhost:4317`, which is the ADOT Lambda layer's default collector endpoint.
The endpoint can be overridden with the `OTEL_EXPORTER_OTLP_ENDPOINT` environment variable.

You can customize the defaults by passing a `LambdaWorkerOpenTelemetryOptions` object:

```csharp
LambdaWorkerOpenTelemetry.ApplyDefaults(
config,
new LambdaWorkerOpenTelemetryOptions
{
CollectorEndpoint = "http://localhost:4317",
ServiceName = "my-worker",
MetricsExportInterval = TimeSpan.FromSeconds(5),
});
```

Core SDK metrics export every 10 seconds by default. Set `MetricsExportInterval` shorter than your Lambda timeout to increase the chance that at least one metrics export happens during each invocation.

To collect this telemetry, attach the [ADOT Collector layer](https://aws-otel.github.io/docs/getting-started/lambda) to your Lambda function.
.NET does not need a language-specific ADOT layer because the OTel SDK is included as a dependency of the package.

The default Collector configuration does not route OpenTelemetry Protocol (OTLP) data to the traces pipeline.
You must provide a custom Collector configuration that wires the OTLP receiver to both the traces and metrics pipelines.
Bundle the following `otel-collector-config.yaml` in your Lambda deployment package:

<!--SNIPSTART dotnet-lambda-worker-otel-collector-config-->
[src/LambdaWorker/otel-collector-config.yaml.sample](https://github.com/temporalio/samples-dotnet/blob/ea/aws-lambda/src/LambdaWorker/otel-collector-config.yaml.sample)
```sample
receivers:
otlp:
protocols:
grpc:
endpoint: "localhost:4317"
http:
endpoint: "localhost:4318"

exporters:
debug:
awsxray:
region: ${env:AWS_REGION}
awsemf:
namespace: TemporalWorkerMetrics
log_group_name: /aws/lambda/${env:AWS_LAMBDA_FUNCTION_NAME}
region: ${env:AWS_REGION}
dimension_rollup_option: NoDimensionRollup
resource_to_telemetry_conversion:
enabled: true

service:
pipelines:
traces:
receivers: [otlp]
exporters: [awsxray, debug]
metrics:
receivers: [otlp]
exporters: [awsemf]
telemetry:
logs:
level: debug
metrics:
address: localhost:8888
```
<!--SNIPEND-->

Set the following environment variable on the Lambda function to point the Collector at the bundled config:

- `OPENTELEMETRY_COLLECTOR_CONFIG_URI=/var/task/otel-collector-config.yaml`

Enable X-Ray active tracing on the Lambda function:

```bash
aws lambda update-function-configuration \
--function-name <your-function-name> \
--tracing-config Mode=Active
```

The Lambda execution role must have permissions to write to X-Ray and CloudWatch.
Add `xray:PutTraceSegments`, `xray:PutTelemetryRecords`, and `cloudwatch:PutMetricData` permissions to the execution role.
Without these permissions, the Collector fails silently and no telemetry appears.

You can also configure tracing and metrics manually using `TracingInterceptor` and `TemporalRuntime`:

```csharp
using Temporalio.Extensions.OpenTelemetry;

config.ClientOptions.Interceptors = new[] { new TracingInterceptor() };
config.ClientOptions.Runtime = new TemporalRuntime(new TemporalRuntimeOptions
{
Telemetry = new TelemetryOptions
{
Metrics = new MetricsOptions(new OpenTelemetryOptions("http://collector:4317")),
},
});
```
26 changes: 26 additions & 0 deletions docs/develop/dotnet/workers/serverless-workers/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
id: index
title: Serverless Workers - .NET SDK
sidebar_label: Serverless Workers
description: Write Temporal Workers that run on serverless compute using the .NET SDK.
slug: /develop/dotnet/workers/serverless-workers
toc_max_heading_level: 4
keywords:
- serverless
- dotnet sdk
- worker
tags:
- Workers
- .NET SDK
- Serverless
---

Serverless Workers run on ephemeral, on-demand compute rather than long-lived processes.
Temporal invokes the Worker when Tasks arrive, and the Worker shuts down when the work is done.

For a general overview of how Serverless Workers work, see [Serverless Workers](/serverless-workers).
For the end-to-end deployment guide, see [Deploy a Serverless Worker](/production-deployment/worker-deployments/serverless-workers).

## Supported providers

- [**AWS Lambda**](/develop/dotnet/workers/serverless-workers/aws-lambda) - Use the `Temporalio.Extensions.Aws.Lambda` NuGet package to run a Worker as a Lambda function. Covers setup, configuration, Lambda-tuned defaults, observability, and the invocation lifecycle.
Loading