diff --git a/docs/cloud/high-availability/index.mdx b/docs/cloud/high-availability/index.mdx index 2301297214..552fd779d4 100644 --- a/docs/cloud/high-availability/index.mdx +++ b/docs/cloud/high-availability/index.mdx @@ -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 diff --git a/docs/demos/serverless-workers.mdx b/docs/demos/serverless-workers.mdx index 15d83203b3..97198c194f 100644 --- a/docs/demos/serverless-workers.mdx +++ b/docs/demos/serverless-workers.mdx @@ -25,12 +25,7 @@ llm_exclude: import { ReleaseNoteHeader } from '@site/src/components'; - - To request access during Pre-release, create a - [support ticket](/cloud/support#support-ticket) or contact your account team. APIs are experimental and may be subject - to backwards-incompatible changes. [Sign up for updates](https://temporal.io/pages/serverless-workers-updates) to be - notified when Serverless Workers reach Public Preview. - + Serverless Workers let you run Temporal Workers on serverless compute like AWS Lambda. There are no long-lived processes to provision or scale. Temporal Cloud invokes your Worker when Tasks arrive, and the Worker shuts down when the work is diff --git a/docs/develop/dotnet/workers/serverless-workers/aws-lambda.mdx b/docs/develop/dotnet/workers/serverless-workers/aws-lambda.mdx new file mode 100644 index 0000000000..8d2883d9d9 --- /dev/null +++ b/docs/develop/dotnet/workers/serverless-workers/aws-lambda.mdx @@ -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'; + + + +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. + + +[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 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); +// ... + } +} +``` + + +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`. + + +[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 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; + } +} +``` + + +## 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 */} + +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/aws-lambda#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: + + +[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 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); + } +} +``` + + +`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: + + +[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 +``` + + +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 \ + --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")), + }, +}); +``` diff --git a/docs/develop/dotnet/workers/serverless-workers/index.mdx b/docs/develop/dotnet/workers/serverless-workers/index.mdx new file mode 100644 index 0000000000..8ccb1856a0 --- /dev/null +++ b/docs/develop/dotnet/workers/serverless-workers/index.mdx @@ -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. diff --git a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx index 8678554462..8443047447 100644 --- a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx @@ -21,27 +21,23 @@ tags: import { ReleaseNoteHeader } from '@site/src/components'; - - To request access during Pre-release, create a [support ticket](/cloud/support#support-ticket) or contact your account team. - APIs are experimental and may be subject to backwards-incompatible changes. - [Sign up for updates](https://temporal.io/pages/serverless-workers-updates) to be notified when Serverless Workers reach Public Preview. - + The `lambdaworker` 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](/production-deployment/worker-deployments/serverless-workers). +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 */} Use the `RunWorker` function to start a Lambda-based Worker. Pass a `WorkerDeploymentVersion` and a callback that registers your Workflows and Activities. - + [lambda-worker/worker/main.go](https://github.com/temporalio/samples-go/blob/main/lambda-worker/worker/main.go) -```go +```go {13-17} package main import ( @@ -84,7 +80,7 @@ The `Options` callback gives you access to the same registration methods you use The `lambdaworker` package automatically loads Temporal client configuration from a TOML config file and environment variables. Refer to [Environment Configuration](/develop/environment-configuration) for more details. -The config file is resolved in order: +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`). @@ -133,9 +129,9 @@ The ADOT Lambda layer collects this telemetry and can forward traces to AWS X-Ra The underlying metrics and traces are the same ones the Go SDK emits in any environment. For general observability concepts and the full list of available metrics, see [Observability - Go SDK](/develop/go/platform/observability) and the [SDK metrics reference](/references/sdk-metrics). - + [lambda-worker/worker/main.go](https://github.com/temporalio/samples-go/blob/main/lambda-worker/worker/main.go) -```go +```go {7, 19-21} package main import ( diff --git a/docs/develop/java/workers/serverless-workers/aws-lambda.mdx b/docs/develop/java/workers/serverless-workers/aws-lambda.mdx new file mode 100644 index 0000000000..67c0b7a0a2 --- /dev/null +++ b/docs/develop/java/workers/serverless-workers/aws-lambda.mdx @@ -0,0 +1,259 @@ +--- +id: aws-lambda +title: Serverless Workers on AWS Lambda - Java SDK +sidebar_label: Serverless Workers on AWS Lambda +description: Write a Temporal Worker that runs on AWS Lambda using the Java SDK temporal-aws-lambda contrib module. +slug: /develop/java/workers/serverless-workers/aws-lambda +toc_max_heading_level: 4 +keywords: + - serverless + - lambda + - aws + - java sdk + - worker + - serverless worker +tags: + - Workers + - Java SDK + - Serverless + - AWS Lambda +--- + +import { ReleaseNoteHeader } from '@site/src/components'; + + + +The `temporal-aws-lambda` contrib module 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 */} + +Create a class that implements AWS Lambda's `RequestHandler` interface and delegates to `LambdaWorker.run` in a static field. +Pass a `WorkerDeploymentVersion` and a configure callback that registers your Workflows and Activities. +Assign the handler to a static field so it is created once during Lambda cold start and reused across invocations. + + +[lambda-worker/src/main/java/io/temporal/samples/lambdaworker/LambdaFunction.java](https://github.com/temporalio/samples-java/blob/ea/aws-lambda/lambda-worker/src/main/java/io/temporal/samples/lambdaworker/LambdaFunction.java) +```java {11-15} +package io.temporal.samples.lambdaworker; + +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; +import io.temporal.aws.lambda.LambdaWorker; +import io.temporal.common.WorkerDeploymentVersion; + +/** AWS Lambda entry point for the Temporal worker. */ +public class LambdaFunction implements RequestHandler { + + private static final RequestHandler WORKER = + LambdaWorker.run( + new WorkerDeploymentVersion( + LambdaWorkerSample.deploymentName(), LambdaWorkerSample.buildId()), + LambdaWorkerSample::configure); + + @Override + public Void handleRequest(Object input, Context context) { + return WORKER.handleRequest(input, context); + } +} +``` + + +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 `@WorkflowVersioningBehavior` annotation on the Workflow method, or set a worker-level default with `DefaultVersioningBehavior` in `DeploymentOptions`. + + +[lambda-worker/src/main/java/io/temporal/samples/lambdaworker/SampleWorkflowImpl.java](https://github.com/temporalio/samples-java/blob/ea/aws-lambda/lambda-worker/src/main/java/io/temporal/samples/lambdaworker/SampleWorkflowImpl.java) +```java {21} +package io.temporal.samples.lambdaworker; + +import io.temporal.activity.ActivityOptions; +import io.temporal.common.VersioningBehavior; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowVersioningBehavior; +import java.time.Duration; +import org.slf4j.Logger; + +/** Workflow implementation that executes a greeting Activity. */ +public class SampleWorkflowImpl implements SampleWorkflow { + + private static final Logger logger = Workflow.getLogger(SampleWorkflowImpl.class); + + private final GreetingActivities activities = + Workflow.newActivityStub( + GreetingActivities.class, + ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(10)).build()); + + @Override + @WorkflowVersioningBehavior(VersioningBehavior.PINNED) + public String getGreeting(String name) { + logger.info("SampleWorkflow started for {}", name); + String result = activities.createGreeting(name); + logger.info("SampleWorkflow completed with {}", result); + return result; + } +} +``` + + +The configure callback receives a `LambdaWorkerOptions.Builder` with the same [registration methods as a standard Worker](/develop/java/workers/run-worker-process#register-types): `registerWorkflowImplementationTypes`, `registerActivitiesImplementations`, and `registerDynamicWorkflowImplementationType`. + +If you need to assemble options outside the callback, call `LambdaWorkerOptions.newBuilderFromEnvironment()`, configure the builder, and pass the built options to `LambdaWorker.newHandler(...)`. + +## Configure the Temporal connection {/* #configure-connection */} + +The `temporal-aws-lambda` module 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. + +## Adjust Worker defaults for Lambda {/* #lambda-tuned-defaults */} + +The `temporal-aws-lambda` module 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 | +|---|---| +| `MaxConcurrentActivityExecutionSize` | 2 | +| `MaxConcurrentWorkflowTaskExecutionSize` | 10 | +| `MaxConcurrentLocalActivityExecutionSize` | 2 | +| `MaxConcurrentNexusExecutionSize` | 5 | +| `MaxConcurrentWorkflowTaskPollers` | 2 | +| `MaxConcurrentActivityTaskPollers` | 1 | +| `MaxConcurrentNexusTaskPollers` | 1 | +| `WorkflowCacheSize` | 30 | +| `MaxWorkflowThreadCount` | 30 | +| `GracefulShutdownTimeout` | 5 seconds | +| `ShutdownDeadlineBuffer` | 7 seconds | + +`ShutdownDeadlineBuffer` is specific to the `temporal-aws-lambda` module. +It controls the full shutdown window reserved at the end of the Lambda invocation, including graceful shutdown time, shutdown hooks, and service stub cleanup. +The default is `GracefulShutdownTimeout` (5s) + 2s. + +If you change `GracefulShutdownTimeout` without explicitly setting `ShutdownDeadlineBuffer`, the buffer is recomputed as `GracefulShutdownTimeout` + 2s. +If you explicitly set `ShutdownDeadlineBuffer`, it must be greater than or equal to `GracefulShutdownTimeout`. + +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/aws-lambda#tuning-for-long-running-activities). + +## Add observability with OpenTelemetry {/* #add-observability */} + +The `OtelLambdaWorker` class 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 Java SDK emits in any environment. +For general observability concepts and the full list of available metrics, see [Observability - Java SDK](/develop/java/platform/observability) and the [SDK metrics reference](/references/sdk-metrics). + +:::caution + +Traces are currently produced through a compatibility shim, not native OpenTelemetry support. The trace structure will change in a future release. Metrics are not affected. + +::: + +```java +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; +import io.temporal.aws.lambda.LambdaWorker; +import io.temporal.aws.lambda.OtelLambdaWorker; +import io.temporal.common.WorkerDeploymentVersion; + +public final class Handler implements RequestHandler { + private static final RequestHandler WORKER = + LambdaWorker.run( + new WorkerDeploymentVersion("my-app", "build-1"), + builder -> { + OtelLambdaWorker.configure(builder); + builder.setTaskQueue("serverless-task-queue-1"); + builder.registerWorkflowImplementationTypes(SampleWorkflowImpl.class); + builder.registerActivitiesImplementations(new SampleActivitiesImpl()); + }); + + @Override + public Void handleRequest(Object input, Context context) { + return WORKER.handleRequest(input, context); + } +} +``` + +`OtelLambdaWorker.configure` configures OpenTelemetry with OTLP trace and metric exporters, uses AWS X-Ray-compatible trace ID generation, installs an OpenTelemetry-backed metrics scope, and registers per-invocation flush hooks. +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. + +To collect this telemetry, attach the [ADOT Collector layer](https://aws-otel.github.io/docs/getting-started/lambda) to your Lambda function. +Java does not need a language-specific ADOT layer because the OTel SDK is included as a dependency of the module. + +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: + + +[lambda-worker/otel-collector-config.yaml.sample](https://github.com/temporalio/samples-java/blob/ea/aws-lambda/lambda-worker/otel-collector-config.yaml.sample) +```sample +receivers: + otlp: + protocols: + grpc: + endpoint: "localhost:4317" + http: + endpoint: "localhost:4318" + +exporters: + debug: + awsxray: + region: us-west-2 + awsemf: + namespace: TemporalWorkerMetrics + log_group_name: /aws/lambda/ + region: us-west-2 + 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 +``` + + +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 \ + --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. + +If you only need metrics or tracing, use `OtelLambdaWorker.configureMetrics`, `OtelLambdaWorker.configureTracing`, or `OtelLambdaWorker.configureFlushHook` individually. +To use an application-owned OpenTelemetry provider, call `builder.setOpenTelemetry(...)` instead. In that path, no exporters are created and the helper only installs the metrics scope, interceptors, and per-invocation flush hook. diff --git a/docs/develop/java/workers/serverless-workers/index.mdx b/docs/develop/java/workers/serverless-workers/index.mdx new file mode 100644 index 0000000000..83fe192e8a --- /dev/null +++ b/docs/develop/java/workers/serverless-workers/index.mdx @@ -0,0 +1,26 @@ +--- +id: index +title: Serverless Workers - Java SDK +sidebar_label: Serverless Workers +description: Write Temporal Workers that run on serverless compute using the Java SDK. +slug: /develop/java/workers/serverless-workers +toc_max_heading_level: 4 +keywords: + - serverless + - java sdk + - worker +tags: + - Workers + - Java 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/java/workers/serverless-workers/aws-lambda) - Use the `temporal-aws-lambda` contrib module to run a Worker as a Lambda function. Covers setup, configuration, Lambda-tuned defaults, observability, and the invocation lifecycle. diff --git a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx index ae54ccbd1b..c54c19d8a5 100644 --- a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx @@ -21,18 +21,14 @@ tags: import { ReleaseNoteHeader } from '@site/src/components'; - - To request access during Pre-release, create a [support ticket](/cloud/support#support-ticket) or contact your account team. - APIs are experimental and may be subject to backwards-incompatible changes. - [Sign up for updates](https://temporal.io/pages/serverless-workers-updates) to be notified when Serverless Workers reach Public Preview. - + The `lambda_worker` contrib 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](/production-deployment/worker-deployments/serverless-workers). +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 */} @@ -90,7 +86,7 @@ class MyWorkflow: The `lambda_worker` package automatically loads Temporal client configuration from a TOML config file and environment variables. Refer to [Environment Configuration](/develop/environment-configuration) for more details. -The config file is resolved in order: +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`). @@ -138,7 +134,7 @@ The ADOT Lambda layer collects this telemetry and can forward traces to AWS X-Ra The underlying metrics and traces are the same ones the Python SDK emits in any environment. For general observability concepts and the full list of available metrics, see [Observability - Python SDK](/develop/python/platform/observability) and the [SDK metrics reference](/references/sdk-metrics). - + [lambda_worker/lambda_function.py](https://github.com/temporalio/samples-python/blob/lambda-worker/lambda_worker/lambda_function.py) ```py from activities import hello_activity diff --git a/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx b/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx index 093a0d6441..032dfca3ca 100644 --- a/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx @@ -21,11 +21,7 @@ tags: import { ReleaseNoteHeader } from '@site/src/components'; - - To request access during Pre-release, create a [support ticket](/cloud/support#support-ticket) or contact your account team. - APIs are experimental and may be subject to backwards-incompatible changes. - [Sign up for updates](https://temporal.io/pages/serverless-workers-updates) to be notified when Serverless Workers reach Public Preview. - + The `@temporalio/lambda-worker` 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. @@ -39,9 +35,9 @@ For a full end-to-end deployment guide covering AWS IAM setup, compute configura Use the `runWorker` function to create a Lambda handler that runs a Temporal Worker. Pass a deployment version and a configure callback that sets up your Workflows and Activities. - + [lambda-worker/src/index.ts](https://github.com/temporalio/samples-typescript/blob/main/lambda-worker/src/index.ts) -```ts +```ts {6} import { runWorker } from '@temporalio/lambda-worker'; // ... import * as activities from './activities'; @@ -86,7 +82,7 @@ Then reference the bundle in your handler with `workflowBundle: { codePath: requ The `@temporalio/lambda-worker` package automatically loads Temporal client configuration from a TOML config file and environment variables. Refer to [Environment Configuration](/develop/environment-configuration) for more details. -The config file is resolved in order: +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`). @@ -131,9 +127,9 @@ With this enabled, the Worker emits SDK metrics and distributed traces for Workf The underlying metrics and traces are the same ones the TypeScript SDK emits in any environment. For general observability concepts and the full list of available metrics, see [Observability - TypeScript SDK](/develop/typescript/platform/observability) and the [SDK metrics reference](/references/sdk-metrics). - + [lambda-worker/src/index.ts](https://github.com/temporalio/samples-typescript/blob/main/lambda-worker/src/index.ts) -```ts +```ts {2, 12} import { runWorker } from '@temporalio/lambda-worker'; import { applyDefaults } from '@temporalio/lambda-worker/otel'; import * as activities from './activities'; diff --git a/docs/encyclopedia/workers/serverless-workers/aws-lambda.mdx b/docs/encyclopedia/workers/serverless-workers/aws-lambda.mdx index 341967ed35..d7541ac85a 100644 --- a/docs/encyclopedia/workers/serverless-workers/aws-lambda.mdx +++ b/docs/encyclopedia/workers/serverless-workers/aws-lambda.mdx @@ -23,12 +23,7 @@ tags: import { CaptionedImage, ReleaseNoteHeader } from '@site/src/components'; - - To request access during Pre-release, create a [support ticket](/cloud/support#support-ticket) or contact your account - team. APIs are experimental and may be subject to backwards-incompatible changes. [Sign up for - updates](https://temporal.io/pages/serverless-workers-updates) to be notified when Serverless Workers reach Public - Preview. - + This page covers how Serverless Workers work on AWS Lambda, including the invocation lifecycle, autoscaling behavior, and how Worker Versioning maps to Lambda function versions. diff --git a/docs/encyclopedia/workers/serverless-workers/index.mdx b/docs/encyclopedia/workers/serverless-workers/index.mdx index e441360dd3..0e9e348593 100644 --- a/docs/encyclopedia/workers/serverless-workers/index.mdx +++ b/docs/encyclopedia/workers/serverless-workers/index.mdx @@ -215,7 +215,8 @@ With single-slot configuration, each Activity gets a dedicated execution environ | Activity duration | Depends on the compute provider. On AWS Lambda, an Activity must finish within the invocation limit (15 minutes maximum), minus the shutdown deadline buffer. On GCP Cloud Run, instances are long-lived, so no per-invocation limit applies. See [Worker lifecycle](#worker-lifecycle). | | Workflow duration | No limit. Workflows of any duration work. A Workflow runs across as many Workers as needed. | | Worker code | Same Temporal SDK Worker code, using the serverless Worker package for your SDK. | -| Versioning | [Worker Versioning](/worker-versioning) is required. Each Workflow must have an `AutoUpgrade` or `Pinned` behavior, set per-Workflow or as a Worker-level default. See [Worker Versioning with Serverless Workers](#worker-versioning-with-serverless-workers). | +| Versioning | [Worker Versioning](/worker-versioning) is required. Each Workflow must have an `AutoUpgrade` or `Pinned` behavior, set per-Workflow or as a Worker-level default. See [Worker Versioning](/worker-versioning) for rollout strategies such as ramping, and [Worker Versioning with Serverless Workers](#worker-versioning-with-serverless-workers) for how Worker Deployment Versions map to compute provider primitives. | +| High Availability | On failover of a Namespace with [Multi-region or Multi-cloud Replication](/cloud/high-availability), the WCI keeps invoking Workers in the original region unless you manually repoint the compute provider. Compute provider configuration, such as a Lambda ARN or a Cloud Run Worker Pool, is scoped to a single region. See [Serverless Workers and High Availability](/cloud/high-availability#serverless-workers). | ## Worker Versioning with Serverless Workers {/* #worker-versioning-with-serverless-workers */} diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda/index.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda/index.mdx index c0affb63b0..ea95ab3b64 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda/index.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda/index.mdx @@ -22,12 +22,7 @@ import { ReleaseNoteHeader, SdkTabs } from '@site/src/components'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; - - To request access during Pre-release, create a [support ticket](/cloud/support#support-ticket) or contact your account - team. APIs are experimental and may be subject to backwards-incompatible changes. [Sign up for - updates](https://temporal.io/pages/serverless-workers-updates) to be notified when Serverless Workers reach Public - Preview. - + This guide walks through deploying a Temporal [Serverless Worker](/serverless-workers) on AWS Lambda. @@ -44,15 +39,18 @@ This guide walks through deploying a Temporal [Serverless Worker](/serverless-wo - The AWS-specific steps in this guide require the [`aws` CLI](https://aws.amazon.com/cli/) installed and configured with your AWS credentials. You may use other tools to perform the steps, such as the AWS Console or the AWS SDKs. -- The [Go SDK](/develop/go), [Python SDK](/develop/python), or [TypeScript SDK](/develop/typescript), depending on which - language you are using. Use the tabs to select your language and the rest of the page will update accordingly. +- The [Go SDK](/develop/go), [Python SDK](/develop/python), [TypeScript SDK](/develop/typescript), + [Java SDK](/develop/java), or [.NET SDK](/develop/dotnet), depending on which language you are using. + Use the tabs to select your language and the rest of the page will update accordingly. :::tip - If you are exploring the Serverless Worker feature and don't have a Workflow ready, you can use a sample from the - [Go Lambda Worker sample](https://github.com/temporalio/samples-go/tree/main/lambda-worker), - [Python Lambda Worker sample](https://github.com/temporalio/samples-python/tree/main/lambda_worker), or - [TypeScript Lambda Worker sample](https://github.com/temporalio/samples-typescript/tree/main/lambda-worker). + If you are exploring the Serverless Worker feature and don't have a Workflow ready, you can use a sample from + the [Go Lambda Worker sample](https://github.com/temporalio/samples-go/tree/main/lambda-worker), + [Python Lambda Worker sample](https://github.com/temporalio/samples-python/tree/main/lambda_worker), + [TypeScript Lambda Worker sample](https://github.com/temporalio/samples-typescript/tree/main/lambda-worker), + [Java Lambda Worker sample](https://github.com/temporalio/samples-java/tree/main/lambda-worker), + or [.NET Lambda Worker sample](https://github.com/temporalio/samples-dotnet/tree/main/src/LambdaWorker). ::: @@ -176,6 +174,92 @@ For details on configuration options, Lambda-tuned defaults, and observability, [Serverless Workers - TypeScript SDK](/develop/typescript/workers/serverless-workers/aws-lambda). + + +Use the Java SDK's `temporal-aws-lambda` contrib module. + +```java +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; +import io.temporal.aws.lambda.LambdaWorker; +import io.temporal.common.WorkerDeploymentVersion; + +public final class Handler implements RequestHandler { + private static final RequestHandler WORKER = + LambdaWorker.run( + new WorkerDeploymentVersion("my-app", "build-1"), + builder -> { + builder.setTaskQueue("my-task-queue"); + builder.registerWorkflowImplementationTypes(MyWorkflowImpl.class); + builder.registerActivitiesImplementations(new MyActivitiesImpl()); + }); + + @Override + public Void handleRequest(Object input, Context context) { + return WORKER.handleRequest(input, context); + } +} +``` + +Each Workflow must have a [versioning behavior](/worker-versioning#versioning-behaviors), either `AutoUpgrade` or +`Pinned`. Set it per-Workflow at registration time, or set a Worker-level default with `DefaultVersioningBehavior` in +`DeploymentOptions`. + +For details on configuration options, Lambda-tuned defaults, and the invocation lifecycle, see +[Serverless Workers - Java SDK](/develop/java/workers/serverless-workers/aws-lambda). + + + + +Use the `Temporalio.Extensions.Aws.Lambda` NuGet package. + +```csharp +using Amazon.Lambda.Core; +using Temporalio.Common; +using Temporalio.Extensions.Aws.Lambda; + +public class Function +{ + private static readonly Func WorkerHandler = + TemporalLambdaWorker.CreateHandler( + new WorkerDeploymentVersion("my-app", "build-1"), + config => + { + config.WorkerOptions.TaskQueue = "my-task-queue"; + config.WorkerOptions.AddWorkflow(); + config.WorkerOptions.AddActivity(MyActivities.MyActivityAsync); + }); + + public Task HandlerAsync(object? input, ILambdaContext context) => + WorkerHandler(input, context); +} +``` + +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`. + +```csharp +using Temporalio.Common; +using Temporalio.Workflows; + +[Workflow(VersioningBehavior = VersioningBehavior.Pinned)] +public class MyWorkflow +{ + [WorkflowRun] + public async Task RunAsync(string input) + { + return await Workflow.ExecuteActivityAsync( + () => MyActivities.MyActivityAsync(input), + new() { StartToCloseTimeout = TimeSpan.FromSeconds(10) }); + } +} +``` + +For details on configuration options, Lambda-tuned defaults, and observability, see +[Serverless Workers - .NET SDK](/develop/dotnet/workers/serverless-workers/aws-lambda). + + ## 2. Deploy Lambda function {/* #deploy-lambda-function */} @@ -237,6 +321,34 @@ zip -r function.zip lib/ node_modules/ workflow-bundle.js ``` + + +Build your Lambda function with all dependencies bundled. +For example, with Gradle's Shadow plugin: + +```bash +./gradlew shadowJar +``` + +The shadow JAR is in `build/libs/` and is a valid zip archive that can be uploaded directly to Lambda. + + + + +Publish for the Lambda runtime: + +```bash +dotnet publish -c Release -r linux-x64 --self-contained false \ + -o ./publish +``` + +Package the published output into a zip file: + +```bash +cd publish && zip -r ../function.zip . && cd .. +``` + + ### ii. Deploy Lambda function {/* #deploy-lambda-function-step */} @@ -307,6 +419,51 @@ aws lambda create-function \ | `--handler` | Entry point in `module.export` format. Must point to the handler exported by `runWorker`. | + + +```bash +aws lambda create-function \ + --function-name my-temporal-worker \ + --runtime java17 \ + --handler io.temporal.samples.lambdaworker.LambdaFunction::handleRequest \ + --role \ + --zip-file fileb://build/libs/-all.jar \ + --timeout 90 \ + --memory-size 1024 \ + --environment '{"Variables":{"TEMPORAL_ADDRESS":":7233","TEMPORAL_NAMESPACE":"","TEMPORAL_API_KEY":""}}' +``` + +| Parameter | Description | +| ----------------- | ------------------------------------------------------------------------------------------------------------------------------ | +| `--function-name` | Name of the Lambda function. | +| `--runtime` | Lambda runtime. Use `java17` or another supported Java version. | +| `--handler` | Fully qualified class name of your `RequestHandler` implementation, with `::handleRequest`. | +| `--zip-file` | Path to the shadow JAR in `build/libs/`. The filename follows the pattern `--all.jar` from your `build.gradle`. Shadow JARs are valid zip archives and can be uploaded directly. | +| `--memory-size` | Java Workers typically need more memory than other runtimes. Start with `1024` and adjust based on CloudWatch memory metrics. | + + + + +```bash +aws lambda create-function \ + --function-name my-temporal-worker \ + --runtime dotnet8 \ + --handler MyAssembly::MyNamespace.Function::HandlerAsync \ + --role \ + --zip-file fileb://function.zip \ + --timeout 600 \ + --memory-size 256 \ + --environment '{"Variables":{"TEMPORAL_ADDRESS":":7233","TEMPORAL_NAMESPACE":"","TEMPORAL_API_KEY":"","SSL_CERT_FILE":"/etc/pki/tls/certs/ca-bundle.crt"}}' +``` + +| Parameter | Description | +| ----------------- | ---------------------------------------------------------------------------------------------------------------------- | +| `--function-name` | Name of the Lambda function. | +| `--runtime` | Lambda runtime. Use `dotnet8` or another supported .NET version. | +| `--handler` | Entry point in `Assembly::Namespace.Class::Method` format. Must point to the method that calls the worker handler. | +| `SSL_CERT_FILE` | Required. The .NET Lambda runtime sets a default certificate path that the Temporal SDK cannot read. This overrides it with the system CA bundle so TLS connections work. | + + The following parameters apply to all SDKs: @@ -330,8 +487,8 @@ AWS Lambda functions default to a 3-second timeout, which is too short for the W register the Task Queue. If the first invocation times out before the Worker polls, the Task Queue binding is never created and the Lambda is never invoked again. Always set `--timeout` high enough for the Worker to start, process Tasks, and [shut down gracefully](/serverless-workers#worker-lifecycle). See -[Troubleshoot Serverless Workers on AWS Lambda](/troubleshooting/serverless-workers/aws-lambda#check-wci-detecting-tasks) -if the Task Queue binding is not established. +[Troubleshoot Serverless Workers on AWS Lambda](/troubleshooting/serverless-workers/aws-lambda#validate-connection) if +the Task Queue binding is not established. ::: @@ -386,6 +543,14 @@ your AWS account with a handful of Lambda permissions scoped to your Worker func includes an External ID condition to prevent [confused deputy](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html) attacks. +The Temporal Cloud UI provides a **Launch Stack** button on the **Create Worker Deployment** page that opens the AWS CloudFormation console with the template and parameters pre-filled. Click it to create the role without downloading or configuring the template manually. + +You can also create the role using the templates below. + + + + +[Download the CloudFormation template](/files/temporal-cloud-serverless-worker-role.yaml). Deploy the following CloudFormation template to create the invocation role with these permissions. [Download the template](/files/temporal-cloud-serverless-worker-role.yaml). See the template details below for the exact permissions granted. @@ -518,9 +683,62 @@ aws cloudformation create-stack \ After the stack finishes creating, retrieve the IAM role ARN from the stack outputs: ```bash -aws cloudformation describe-stacks --stack-name --query 'Stacks[0].Outputs[?OutputKey==`RoleARN`].OutputValue' --output text --region +aws cloudformation describe-stacks \ + --stack-name \ + --query 'Stacks[0].Outputs[?OutputKey==`RoleARN`].OutputValue' \ + --output text \ + --region ``` + + + +Use the [Temporal Terraform module](https://github.com/temporalio/terraform-modules/tree/main/modules/serverless-workers/aws/lambda) to create the invocation role. + +| Variable | Description | Required | +| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | +| `external_id` | A string you choose to prevent [confused deputy](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html) attacks. Can be any value. Use the same value when creating the Worker Deployment Version. | Yes | +| `temporal_cloud_principals` | Temporal Cloud AWS IAM role ARNs permitted to assume this role. Use the values shown in the example below. | Yes | +| `lambda_function_arns` | List of Lambda function ARNs that Temporal Cloud is permitted to invoke. | Yes | +| `role_name` | Name of the IAM role to create. Defaults to `Temporal-Cloud-Serverless-Worker`. | No | + +Add the module to your Terraform configuration: + +```hcl +module "serverless_worker_lambda" { + source = "github.com/temporalio/terraform-modules//modules/serverless-workers/aws/lambda" + + external_id = "" + + temporal_cloud_principals = [ + "arn:aws:iam::902542641901:role/wci-lambda-invoke", + "arn:aws:iam::160190466495:role/wci-lambda-invoke", + "arn:aws:iam::819232936619:role/wci-lambda-invoke", + "arn:aws:iam::829909441867:role/wci-lambda-invoke", + "arn:aws:iam::354116250941:role/wci-lambda-invoke", + ] + + lambda_function_arns = [ + "arn:aws:lambda:::function:", + ] +} +``` + +Apply the configuration: + +```bash +terraform init && terraform apply +``` + +After the apply completes, retrieve the IAM role ARN from the outputs: + +```bash +terraform output role_arn +``` + + + + Use this role ARN in your Worker Deployment Version's compute configuration. ## 4. Create Worker Deployment Version {/* #create-worker-deployment-version */} @@ -622,6 +840,7 @@ invokes your Lambda function. The Worker starts, connects to Temporal, picks up You can verify the invocation by checking: - **Temporal UI:** The Workflow execution should show task completions in the event history. +- **Connection status:** In **Workers > Deployments**, the **Connection** column shows whether Temporal can reach the Lambda function. You can also check this from the CLI with `temporal worker deployment describe`. - **AWS CloudWatch Logs:** The Lambda function's log group (`/aws/lambda/my-temporal-worker`) should show invocation logs with the Worker startup, task processing, and graceful shutdown. This requires the Lambda execution role from [Step 2](#deploy-lambda-function) to have CloudWatch Logs permissions, included in the diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda/self-hosted-setup.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda/self-hosted-setup.mdx index 2e739534fd..7edf47e067 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda/self-hosted-setup.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda/self-hosted-setup.mdx @@ -21,9 +21,7 @@ tags: import { ReleaseNoteHeader } from '@site/src/components'; - - APIs are experimental and may be subject to backwards-incompatible changes. - + Serverless Workers require Temporal Service v1.31.0 or later. diff --git a/docs/troubleshooting/serverless-workers/aws-lambda.mdx b/docs/troubleshooting/serverless-workers/aws-lambda.mdx index fe5b73e530..9b906f4418 100644 --- a/docs/troubleshooting/serverless-workers/aws-lambda.mdx +++ b/docs/troubleshooting/serverless-workers/aws-lambda.mdx @@ -22,11 +22,7 @@ tags: import { ReleaseNoteHeader } from '@site/src/components'; - - To request access during Pre-release, create a [support ticket](/cloud/support#support-ticket) or contact your account team. - APIs are experimental and may be subject to backwards-incompatible changes. - [Sign up for updates](https://temporal.io/pages/serverless-workers-updates) to be notified when Serverless Workers reach Public Preview. - + This page walks through the Serverless Worker invocation flow on AWS Lambda and helps you identify where a failure is occurring. For Worker Pools on GCP Cloud Run, see @@ -64,39 +60,29 @@ Work through the following checks in order. ### Validate the connection to Lambda {/* #validate-connection */} -Start by verifying that Temporal can reach the Lambda function. Go to **Workers > Deployments > select your -deployment**, open the **Actions** menu on the version, and click **Validate Connection**. A successful validation -confirms that the Worker Deployment Version has a compute provider configured, that Temporal can assume the invocation -role, and that the Lambda function can be invoked. +Start by verifying that Temporal can reach the Lambda function. In the Temporal UI, go to **Workers > Deployments > select your +deployment**, open the **Actions** menu on the version, and click **Validate Connection**. -If validation fails, verify that the Lambda function ARN and invocation role ARN in the Worker Deployment Version -configuration are correct. Verify the invocation role was created using the -[CloudFormation template](/production-deployment/worker-deployments/serverless-workers/aws-lambda#configure-iam) -and that the External ID matches the value in the Worker Deployment Version configuration. +A successful validation confirms that the Worker Deployment Version has a compute provider configured, that Temporal can assume the invocation role, and that the Lambda function can be invoked. -If the Worker Deployment Version does not have a compute provider configured, no -[Worker Controller Instance (WCI)](/serverless-workers#how-invocation-works) Workflow exists and the Lambda is never -automatically invoked. A common cause is manually invoking the Lambda function before creating the Worker Deployment -Version in the UI or CLI. When the Lambda runs, the Worker connects to Temporal and polls the Task Queue. That polling -registers the Worker Deployment Version and binds the Task Queue on the server, but the version has no compute provider. -To fix the issue, create or update the Worker Deployment Version with the compute provider flags as described in the -[deploy guide](/production-deployment/worker-deployments/serverless-workers/aws-lambda#create-worker-deployment-version). +Validate Connection reports one of the following failure modes: -### Check that the version is set as current {/* #check-version-current */} +- **No compute provider configured.** No [Worker Controller Instance (WCI)](/serverless-workers#how-invocation-works) Workflow exists and the Lambda is never + automatically invoked. A common cause is manually invoking the Lambda function before creating the Worker Deployment + Version in the UI or CLI. The Worker connects and polls, which registers the version on the server, but without a compute provider. + To fix the issue, create or update the Worker Deployment Version with the compute provider flags as described in the + [deploy guide](/production-deployment/worker-deployments/serverless-workers/aws-lambda#create-worker-deployment-version). -The Worker Deployment Version must be set as the current version for new Tasks to route to it. If you created the -version through the CLI, you need to -[set it as current](/production-deployment/worker-deployments/serverless-workers/aws-lambda#set-current-version). - -You can verify the current version with `temporal worker deployment describe`. +- **Invalid connection.** Temporal cannot assume the invocation role or reach the Lambda function. + Verify that the Lambda function ARN and invocation role ARN are correct. Verify the invocation role was created using the + [CloudFormation template](/production-deployment/worker-deployments/serverless-workers/aws-lambda#configure-iam) + and that the External ID matches the value in the Worker Deployment Version configuration. -### Check that the WCI is detecting Tasks {/* #check-wci-detecting-tasks */} +- **Task Queue not registered.** The Lambda invokes successfully but the Worker errors before registering its Task Queue. Check the Lambda function's CloudWatch logs for configuration or runtime errors (missing environment variables, incorrect TLS configuration, missing dependencies). The server binds a Task Queue to a Worker Deployment Version when a Worker successfully connects and polls. Without a successful poll, the binding is never created and the WCI cannot route Tasks to the version. -If the connection validates successfully but the Lambda is still not being invoked, the -[Worker Controller Instance (WCI)](/serverless-workers#worker-controller-instance) may not be detecting Tasks on the -Task Queue. + If the version was recently created, the Worker may still be starting up. Wait a moment and retry. -Check which Task Queues are bound to the Worker Deployment Version and whether there is a backlog: +You can also check Task Queue bindings from the CLI: ```bash temporal worker deployment describe-version \ @@ -106,23 +92,13 @@ temporal worker deployment describe-version \ --report-task-queue-stats ``` -If no Task Queues are listed, the binding has not been established. The server binds a Task Queue to a Worker Deployment -Version when a Worker with that deployment version successfully connects and polls the Task Queue. - -A common cause is a failed first invocation. When you create a Worker Deployment Version, the WCI invokes the Lambda to -validate the configuration. If that first invocation fails (for example, due to missing environment variables, incorrect -TLS configuration, missing dependencies, or a Lambda timeout that is too short), the Worker never connects to Temporal -and never polls. Without a successful poll, the Task Queue binding is never created. +### Check that the version is set as current {/* #check-version-current */} -Pay particular attention to the Lambda timeout. AWS Lambda functions default to a 3-second timeout, which is often too -short for the Worker to start, connect to Temporal, and register the Task Queue before AWS terminates the invocation. If -the function times out during this initial invocation, the binding is never established and the Lambda is not invoked -again. +The Worker Deployment Version must be set as the current version (or the ramping version) for Tasks to route to it. If you created the +version through the CLI, you need to +[set it as current](/production-deployment/worker-deployments/serverless-workers/aws-lambda#set-current-version). -To diagnose a failed first invocation, invoke the Lambda function manually from the AWS Console. The console displays -the execution result and any errors directly, making it easier to identify configuration issues than searching through -CloudWatch logs. Once the Lambda runs successfully and the Worker connects to Temporal, the Task Queue binding is -established. +You can verify the current version with `temporal worker deployment describe`. ## Lambda is invoked but Tasks are not completing {/* #lambda-invoked-not-completing */} diff --git a/sidebars.js b/sidebars.js index 547d3cbe1a..66a6b68610 100644 --- a/sidebars.js +++ b/sidebars.js @@ -60,6 +60,18 @@ const developDotnetCategory = { items: [ 'develop/dotnet/workers/run-worker-process', 'develop/dotnet/workers/interceptors', + { + type: 'category', + label: 'Serverless Workers', + collapsed: true, + link: { + type: 'doc', + id: 'develop/dotnet/workers/serverless-workers/index', + }, + items: [ + 'develop/dotnet/workers/serverless-workers/aws-lambda', + ], + }, ] }, { @@ -342,7 +354,21 @@ const developJavaCategory = { type: 'doc', id: 'develop/java/workers/index', }, - items: ['develop/java/workers/run-worker-process'], + items: [ + 'develop/java/workers/run-worker-process', + { + type: 'category', + label: 'Serverless Workers', + collapsed: true, + link: { + type: 'doc', + id: 'develop/java/workers/serverless-workers/index', + }, + items: [ + 'develop/java/workers/serverless-workers/aws-lambda', + ], + }, + ], }, { type: 'category', diff --git a/snipsync.config.yaml b/snipsync.config.yaml index 3de5f9c1d3..6d20b6cdd7 100644 --- a/snipsync.config.yaml +++ b/snipsync.config.yaml @@ -22,8 +22,10 @@ origins: repo: samples-ruby - owner: temporalio repo: samples-dotnet + ref: ea/aws-lambda - owner: temporalio repo: samples-java + ref: ea/aws-lambda - owner: temporalio repo: features - owner: temporalio diff --git a/src/constants/featureReleaseTypes.js b/src/constants/featureReleaseTypes.js index 5e773bacc0..7db0cd9410 100644 --- a/src/constants/featureReleaseTypes.js +++ b/src/constants/featureReleaseTypes.js @@ -7,6 +7,7 @@ export const FEATURE_RELEASE_TYPES = { nexus: "publicPreview", workflowStreams: "publicPreview", serverlessWorkers: "prerelease", + serverlessWorkersLambda: "publicPreview", serverlessWorkersCloudRun: "prerelease", externalStorage: "publicPreview", };