From 32736ace69f2013247c5747bae5e2024b0eaf4b8 Mon Sep 17 00:00:00 2001 From: Lenny Chen <55669665+lennessyy@users.noreply.github.com> Date: Thu, 16 Apr 2026 16:06:32 -0700 Subject: [PATCH 01/62] docs: Serverless Workers - Go SDK pages (2/4) (#4418) * docs: Serverless Workers - Go SDK pages (2/4) Add Go SDK Serverless Workers documentation including the lambdaworker package guide for AWS Lambda, rewrite run-worker-process to focus on long-lived Workers, and remove cloud-worker (content folded in). Update sidebars, add redirect, and set broken links to warn for cross-PR references. Part of #4405. Co-Authored-By: Claude Opus 4.6 (1M context) * docs: expand OTel section with context and links for serverless Go SDK page Co-Authored-By: Claude Opus 4.6 (1M context) * docs: link worker defaults to Go SDK reference, clarify ShutdownDeadlineBuffer is serverless-only Co-Authored-By: Claude Opus 4.6 (1M context) * docs: address review feedback on Go SDK pages - Replace ambiguous "Lambda deadline" with "configurable invocation deadline" on the AWS Lambda page (akhayam) - Rewrite tautological "serverless compute" intro on the Go SDK serverless landing page (smuneebahmad) Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- docs/develop/go/index.mdx | 4 +- docs/develop/go/workers/cloud-worker.mdx | 200 ------- docs/develop/go/workers/index.mdx | 6 +- .../develop/go/workers/run-worker-process.mdx | 513 ++---------------- .../workers/serverless-workers/aws-lambda.mdx | 140 +++++ .../go/workers/serverless-workers/index.mdx | 26 + docs/develop/worker-performance.mdx | 4 +- .../encyclopedia/workers/sticky-execution.mdx | 2 +- docusaurus.config.js | 4 +- sidebars.js | 13 +- vercel.json | 5 + 11 files changed, 236 insertions(+), 681 deletions(-) delete mode 100644 docs/develop/go/workers/cloud-worker.mdx create mode 100644 docs/develop/go/workers/serverless-workers/aws-lambda.mdx create mode 100644 docs/develop/go/workers/serverless-workers/index.mdx diff --git a/docs/develop/go/index.mdx b/docs/develop/go/index.mdx index e824cbbdaf..a239b8d549 100644 --- a/docs/develop/go/index.mdx +++ b/docs/develop/go/index.mdx @@ -66,9 +66,9 @@ Execute Activities independently without a Workflow using the Temporal Client. ## [Workers](/develop/go/workers) -- [Worker processes](/develop/go/workers/run-worker-process) -- [Cloud Worker](/develop/go/workers/cloud-worker) +- [Run a Worker](/develop/go/workers/run-worker-process) - [Sessions](/develop/go/workers/sessions) +- [Serverless Workers](/develop/go/workers/serverless-workers) ## [Temporal Client](/develop/go/client) diff --git a/docs/develop/go/workers/cloud-worker.mdx b/docs/develop/go/workers/cloud-worker.mdx deleted file mode 100644 index a05c06b8e7..0000000000 --- a/docs/develop/go/workers/cloud-worker.mdx +++ /dev/null @@ -1,200 +0,0 @@ ---- -id: cloud-worker -title: Cloud Worker - Go SDK -sidebar_label: Cloud Worker -description: This section explains Cloud Workers with the Go SDK -toc_max_heading_level: 4 -keywords: - - Go SDK -tags: - - Go SDK - - Temporal SDKs ---- - -## How to run a Temporal Cloud Worker {#run-a-temporal-cloud-worker} - -To run a Worker that uses [Temporal Cloud](/cloud), you need to provide additional connection and client options that include the following: - -- An address that includes your [Cloud Namespace Name](/namespaces) and a port number: `..tmprl.cloud:`. -- mTLS CA certificate. -- mTLS private key. - -For more information about managing and generating client certificates for Temporal Cloud, see [How to manage certificates in Temporal Cloud](/cloud/certificates). - -For more information about configuring TLS to secure inter- and intra-network communication for a Temporal Service, see [Temporal Customization Samples](https://github.com/temporalio/samples-server). - -To run a Worker that talks to Temporal Cloud, you need the following: - -- A compatible mTLS CA certificate and mTLS private key that has been added to your Namespace. - See [certificate requirements](/cloud/certificates#certificate-requirements). -- Your [Temporal Cloud Namespace Id](/cloud/namespaces#temporal-cloud-namespace-id), which includes your [Temporal Cloud Namespace Name](/cloud/namespaces#temporal-cloud-namespace-name) and the unique five- or six-digit [Temporal Cloud Account Id](/cloud/namespaces#temporal-cloud-account-id) that is appended to it. - This information can be found in the URL of your Namespace; for example, `https://cloud.temporal.io/namespaces/yournamespace.a2fx6/`. - Remember that the Namespace Id must include the Account Id: `yournamespace.a2fx6`. - -For more information about managing and generating client certificates for Temporal Cloud, see [How to manage certificates in Temporal Cloud](/cloud/certificates). - -For more information about configuring TLS to secure inter- and intra-network communication for a Temporal Service, see [Temporal Customization Samples](https://github.com/temporalio/samples-server). - -
- - View the source code - {' '} - in the context of the rest of the application code. -
- -```go -package main - -import ( - "crypto/tls" - "log" - - "go.temporal.io/sdk/client" - "go.temporal.io/sdk/worker" - - "documentation-samples-go/cloud" -) - -func main() { - // Get the key and cert from your env or local machine - clientKeyPath := "./secrets/yourkey.key" - clientCertPath := "./secrets/yourcert.pem" - // Specify the host and port of your Temporal Cloud Namespace - // Host and port format: namespace.unique_id.tmprl.cloud:port - hostPort := "..tmprl.cloud:7233" - namespace := "." - // Use the crypto/tls package to create a cert object - cert, err := tls.LoadX509KeyPair(clientCertPath, clientKeyPath) - if err != nil { - log.Fatalln("Unable to load cert and key pair.", err) - } - // Add the cert to the tls certificates in the ConnectionOptions of the Client - temporalClient, err := client.Dial(client.Options{ - HostPort: hostPort, - Namespace: namespace, - ConnectionOptions: client.ConnectionOptions{ - TLS: &tls.Config{Certificates: []tls.Certificate{cert}}, - }, - }) - if err != nil { - log.Fatalln("Unable to connect to Temporal Cloud.", err) - } - defer temporalClient.Close() - // Create a new Worker. - yourWorker := worker.New(temporalClient, "cloud-connection-example-go-task-queue", worker.Options{}) -// ... -} -``` - -### How to register types {#register-types} - -All Workers listening to the same Task Queue name must be registered to handle the exact same Workflows Types and Activity Types. - -If a Worker polls a Task for a Workflow Type or Activity Type it does not know about, it fails that Task. -However, the failure of the Task does not cause the associated Workflow Execution to fail. - -The `RegisterWorkflow()` and `RegisterActivity()` calls essentially create an in-memory mapping between the Workflow Types and their implementations, inside the Worker process. - -**Registering Activity `structs`** - -Per [Activity Definition](/develop/go/activities/basics#activity-definition) best practices, you might have an Activity struct that has multiple methods and fields. -When you use `RegisterActivity()` for an Activity struct, that Worker has access to all exported methods. - -**Registering multiple Types** - -To register multiple Activity Types and/or Workflow Types with the Worker Entity, just make multiple Activity registration calls, but make sure each Type name is unique: - -```go -w.RegisterActivity(ActivityA) -w.RegisterActivity(ActivityB) -w.RegisterActivity(ActivityC) -w.RegisterWorkflow(WorkflowA) -w.RegisterWorkflow(WorkflowB) -w.RegisterWorkflow(WorkflowC) -``` - -### How to set RegisterWorkflowOptions in Go {#registerworkflowoptions} - -Create an instance of [`RegisterOptions`](https://pkg.go.dev/go.temporal.io/sdk/workflow#RegisterOptions) from the `go.temporal.io/sdk/workflow` package and pass it to the [`RegisterWorkflowWithOptions`](https://pkg.go.dev/go.temporal.io/sdk/worker#WorkflowRegistry) call when registering the Workflow Type with the Worker. - -- Used to set options for registering a Workflow - -| Field | Required | Type | -| ----------------------------------------------------------------- | -------- | -------- | -| [`Name`](#name) | No | `string` | -| [`DisableAlreadyRegisteredCheck`](#disablealreadyregisteredcheck) | No | `bool` | - -#### Name - -See [How to customize a Workflow Type in Go](/develop/go/workflows/basics#customize-workflow-type) - -#### DisableAlreadyRegisteredCheck - -Disables the check to see if the Workflow Type has already been registered. - -- Type: `bool` -- Default: `false` - -```go -// ... -w := worker.New(temporalClient, "your_task_queue_name", worker.Options{}) -registerOptions := workflow.RegisterOptions{ - DisableAlreadyRegisteredCheck: `false`, - // ... -} -w.RegisterWorkflowWithOptions(YourWorkflowDefinition, registerOptions) -// ... -``` - -### How to set RegisterActivityOptions in Go {#registeractivityoptions} - -Create an instance of [`RegisterOptions`](https://pkg.go.dev/go.temporal.io/sdk/activity#RegisterOptions) from the `go.temporal.io/sdk/activity` package and pass it to the [`RegisterActivityWithOptions`](https://pkg.go.dev/go.temporal.io/sdk/worker#ActivityRegistry) call when registering the Activity Type with the Worker. - -Options for registering an Activity - -| Field | Required | Type | -| ----------------------------------------------------------------- | -------- | -------- | -| [`Name`](#name) | No | `string` | -| [`DisableAlreadyRegisteredCheck`](#disablealreadyregisteredcheck) | No | `bool` | -| [`SkipInvalidStructFunctions`](#skipinvalidstructfunctions) | No | `bool` | - -#### Name - -See [How to customize Activity Type in Go](/develop/go/activities/basics#customize-activity-type). - -#### DisableAlreadyRegisteredCheck - -Disables the check to see if the Activity has already been registered. - -- Type: `bool` -- Default: `false` - -```go -// ... -w := worker.New(temporalClient, "your_task_queue_name", worker.Options{}) -registerOptions := activity.RegisterOptions{ - DisableAlreadyRegisteredCheck: false, - // ... -} -w.RegisterActivityWithOptions(a.YourActivityDefinition, registerOptions) -// ... -``` - -#### SkipInvalidStructFunctions - -When registering a struct that has Activities, skip functions that are not valid. -If false, registration panics. - -- Type: `bool` -- Default: `false` - -```go -// ... -w := worker.New(temporalClient, "your_task_queue_name", worker.Options{}) -registerOptions := activity.RegisterOptions{ - SkipInvalidStructFunctions: false, - // ... -} -w.RegisterActivityWithOptions(a.YourActivityDefinition, registerOptions) -// ... -``` diff --git a/docs/develop/go/workers/index.mdx b/docs/develop/go/workers/index.mdx index ce12748c9b..a5ca521ee7 100644 --- a/docs/develop/go/workers/index.mdx +++ b/docs/develop/go/workers/index.mdx @@ -17,6 +17,6 @@ import * as Components from '@site/src/components'; ## Workers -- [Worker processes](/develop/go/workers/run-worker-process) -- [Cloud Worker](/develop/go/workers/cloud-worker) -- [Sessions](/develop/go/workers/sessions) \ No newline at end of file +- [Run a Worker](/develop/go/workers/run-worker-process) +- [Sessions](/develop/go/workers/sessions) +- [Serverless Workers](/develop/go/workers/serverless-workers) \ No newline at end of file diff --git a/docs/develop/go/workers/run-worker-process.mdx b/docs/develop/go/workers/run-worker-process.mdx index 0ab03b28ab..b3ce5da1bd 100644 --- a/docs/develop/go/workers/run-worker-process.mdx +++ b/docs/develop/go/workers/run-worker-process.mdx @@ -1,8 +1,8 @@ --- id: run-worker-process -title: Run Worker processes - Go SDK -description: Shows how to run Worker processes with the Go SDK -sidebar_label: Worker processes +title: Run a Worker - Go SDK +description: Create and run a Temporal Worker using the Go SDK. +sidebar_label: Run a Worker slug: /develop/go/workers/run-worker-process toc_max_heading_level: 3 tags: @@ -11,37 +11,18 @@ tags: - Worker --- -## How to develop a Worker in Go {#develop-worker} +This page covers long-lived Workers that you host and run as persistent processes. +For Workers that run on serverless compute like AWS Lambda, see [Serverless Workers](/develop/go/workers/serverless-workers). -Create an instance of [`Worker`](https://pkg.go.dev/go.temporal.io/sdk/worker#Worker) by calling [`worker.New()`](https://pkg.go.dev/go.temporal.io/sdk/worker#New), available through the `go.temporal.io/sdk/worker` package, and pass it the following parameters: +## Create and run a Worker {#develop-worker} -1. An instance of the Temporal Go SDK `Client`. -1. The name of the Task Queue that it will poll. -1. An instance of `worker.Options`, which can be empty. +Create a [`Worker`](https://pkg.go.dev/go.temporal.io/sdk/worker#Worker) by calling [`worker.New()`](https://pkg.go.dev/go.temporal.io/sdk/worker#New) and passing: -Then, register the Workflow Types and the Activity Types that the Worker will be capable of executing. +1. A Temporal Client. +2. The name of the Task Queue to poll. +3. A [`worker.Options`](https://pkg.go.dev/go.temporal.io/sdk/internal#WorkerOptions) struct (can be empty for defaults). -Lastly, call either the `Start()` or the `Run()` method on the instance of the Worker. -Run accepts an interrupt channel as a parameter, so that the Worker can be stopped in the terminal. -Otherwise, the `Stop()` method must be called to stop the Worker. - -:::tip - -If you have [`gow`](https://github.com/mitranim/gow) installed, the Worker Process automatically "reloads" when you update the Worker file: - -```bash -go install github.com/mitranim/gow@latest -gow run worker/main.go # automatically reloads when file changes -``` - -::: - -
- - View the source code - {' '} - in the context of the rest of the application code. -
+Register your Workflow and Activity types, then call `Run()` to start polling. ```go package main @@ -49,475 +30,67 @@ package main import ( "log" - "go.temporal.io/sdk/activity" "go.temporal.io/sdk/client" "go.temporal.io/sdk/worker" - "go.temporal.io/sdk/workflow" - - "documentation-samples-go/yourapp" ) func main() { - // Create a Temporal Client - // A Temporal Client is a heavyweight object that should be created just once per process. - temporalClient, err := client.Dial(client.Options{}) + c, err := client.Dial(client.Options{}) if err != nil { log.Fatalln("Unable to create client", err) } - defer temporalClient.Close() - // Create a new Worker. - yourWorker := worker.New(temporalClient, "your-custom-task-queue-name", worker.Options{}) - // Register your Workflow Definitions with the Worker. - // Use the RegisterWorkflow or RegisterWorkflowWithOptions method for each Workflow registration. - yourWorker.RegisterWorkflow(yourapp.YourWorkflowDefinition) -// ... - // Register your Activity Definitions with the Worker. - // Use this technique for registering all Activities that are part of a struct and set the shared variable values. - message := "This could be a connection string or endpoint details" - number := 100 - activities := &yourapp.YourActivityObject{ - Message: &message, - Number: &number, - } - // Use the RegisterActivity or RegisterActivityWithOptions method for each Activity. - yourWorker.RegisterActivity(activities) -// ... - // Run the Worker - err = yourWorker.Run(worker.InterruptCh()) + defer c.Close() + + w := worker.New(c, "my-task-queue", worker.Options{}) + w.RegisterWorkflow(MyWorkflow) + w.RegisterActivity(MyActivity) + + err = w.Run(worker.InterruptCh()) if err != nil { log.Fatalln("Unable to start Worker", err) } } -// ... -``` - -### How to set WorkerOptions in Go {#workeroptions} - -Create an instance of [`Options`](https://pkg.go.dev/go.temporal.io/sdk/worker#Options) from the `go.temporal.io/sdk/worker` package, set any of the optional fields, and pass the instance to the [`New`](https://pkg.go.dev/go.temporal.io/sdk/worker#New) call. - -| Field | Required | Type | -| ------------------------------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------- | -| [`MaxConcurrentActivityExecutionSize`](#maxconcurrentactivityexecutionsize) | No | `int` | -| [`WorkerActivitiesPerSecond`](#workeractivitiespersecond) | No | `float64` | -| [`MaxConcurrentLocalActivityExecutionSize`](#maxconcurrentlocalactivityexecutionsize) | No | `int` | -| [`WorkerLocalActivitiesPerSecond`](#workerlocalactivitiespersecond) | No | `float64` | -| [`TaskQueueActivitiesPerSecond`](#taskqueueactivitiespersecond) | No | `float64` | -| [`MaxConcurrentActivityTaskPollers`](#maxconcurrentactivitytaskpollers) | No | `int` | -| [`MaxConcurrentWorkflowTaskExecutionSize`](#maxconcurrentworkflowtaskexecutionsize) | No | `int` | -| [`MaxConcurrentWorkflowTaskPollers`](#maxconcurrentworkflowtaskpollers) | No | `int` | -| [`EnableLoggingInReplay`](#enablelogginginreplay) | No | `bool` | -| [`DisableStickyExecution`](#disablestickyexecution) | No | `bool` | -| [`StickyScheduleToStartTimeout`](#stickyscheduletostarttimeout) | No | [`time.Duration`](https://pkg.go.dev/time#Duration) | -| [`BackgroundActivityContext`](#backgroundactivitycontext) | No | [`context.Context`](https://pkg.go.dev/context#Context) | -| [`WorkflowPanicPolicy`](#workflowpanicpolicy) | No | [`WorkflowPanicPolicy`](https://pkg.go.dev/go.temporal.io/sdk/internal#WorkflowPanicPolicy) | -| [`WorkerStopTimeout`](#workerstoptimeout) | No | [`time.Duration`](https://pkg.go.dev/time#Duration) | -| [`EnableSessionWorker`](#enablesessionworker) | No | `bool` | -| [`MaxConcurrentSessionExecutionSize`](#maxconcurrentsessionexecutionsize) | No | `int` | -| [`WorkflowInterceptorChainFactories`](#workflowinterceptorchainfactories) | No | [`[]WorkflowInterceptor`](https://pkg.go.dev/go.temporal.io/sdk/internal#WorkflowInterceptor) | -| [`LocalActivityWorkerOnly`](#localactivityworkeronly) | No | `bool` | -| [`Identity`](#identity) | No | `string` | -| [`DeadlockDetectionTimeout`](#deadlockdetectiontimeout) | No | [`time.Duration`](https://pkg.go.dev/time#Duration) | - -#### MaxConcurrentActivityExecutionSize - -Sets the maximum concurrent Activity Executions for the Worker. - -- Type: `int` -- Default: `1000` - -A value of `0` sets to the default. - -```go -// ... -workerOptions := worker.Options{ - MaxConcurrentActivityExecutionSize: 1000, - // ... -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... -``` - -#### WorkerActivitiesPerSecond - -Rate limits the number of Activity Task Executions started per second for the Worker. - -- Type: `float64` -- Default: `100000` - -A value of `0` sets to the default. - -Intended use case is to limit resources used by the Worker. - -Notice that the value type is a float so that the value can be less than 1 if needed. -For example, if set to 0.1, Activity Task Executions will happen once every ten seconds. -This can be used to protect downstream services from flooding with requests. - -```go -// ... -workerOptions := worker.Options{ - WorkerActivitiesPerSecond: 100000, - // .. -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... -``` - -#### MaxConcurrentLocalActivityExecutionSize - -Set the maximum concurrent [Local Activity Executions](/local-activity) for the Worker. - -- Type: `int` -- Default: `1000` - -A value of `0` sets to the default value. - -```go -// ... -workerOptions := worker.Options{ - MaxConcurrentLocalActivityExecutionSize: 1000, - // ... -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... -``` - -#### WorkerLocalActivitiesPerSecond - -Rate limits the number of Local Activity Executions per second executed for the Worker. - -- Type: `float64` -- Default: `100000` - -A value of `0` sets to the default value. - -Intended use case is to limit resources used by the Worker. - -Notice that the value type is a float so that the value can be less than 1 if needed. -For example, if set to 0.1, Local Activity Task Executions will happen once every ten seconds. -This can be used to protect downstream services from flooding with requests. - -```go -// ... -workerOptions := worker.Options{ - WorkerLocalActivitiesPerSecond: 100000, - // ... -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... -``` - -#### TaskQueueActivitiesPerSecond - -Rate limits the number of Activity Executions that can be started per second. - -- Type: `float64` -- Default: `100000` - -A value of `0` sets to the default value. - -This rate is managed by the Temporal Service and limits the Activity Tasks per second for the entire Task Queue. This is in contrast to [`WorkerActivityTasksPerSecond`](#workeractivitiespersecond) controls Activities only per Worker. - -Notice that the number is represented in float, so that you can set it to less than 1 if needed. -For example, set the number to 0.1 means you want your Activity to be executed once for every 10 seconds. -This can be used to protect down stream services from flooding. - -```go -// ... -workerOptions := worker.Options{ - TaskQueueActivitiesPerSecond: 100000, - // ... -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... -``` - -#### MaxConcurrentActivityTaskPollers - -Sets the maximum number of goroutines to concurrently poll the Task Queue for Activity Tasks. - -- Type: `int` -- Default: `2` - -Changing this value will affect the rate at which the Worker is able to consume Activity Tasks from the Task Queue. - -```go -// ... -workerOptions := worker.Options{ - MaxConcurrentActivityTaskPollers: 2, - // ... -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... -``` - -#### MaxConcurrentWorkflowTaskExecutionSize - -Sets the maximum number of concurrent Workflow Task Executions the Worker can have. - -- Type: `int` -- Default: `1000` - -A value of `0` sets to the default value. - -```go -// ... -workerOptions := worker.Options{ - MaxConcurrentWorkflowTaskExecutionSize: 1000, - // ... -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... -``` - -#### MaxConcurrentWorkflowTaskPollers - -Sets the maximum number of goroutines that will concurrently poll the Task Queue for Workflow Tasks. - -- Type: `int` -- Default: `2` - -Changing this value will affect the rate at which the Worker is able to consume Workflow Tasks from the Task Queue. - -```go -// ... -workerOptions := worker.Options{ - MaxConcurrentWorkflowTaskPollers: 2, - // ... -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... -``` - -#### EnableLoggingInReplay - -Set to enable logging in Workflow Execution replays. - -- type: `bool` -- Default: `false` - -In Workflow Definitions you can use [`workflow.GetLogger(ctx)`](https://pkg.go.dev/go.temporal.io/sdk/workflow#GetLogger) to write logs. -By default, the logger will skip logging during replays, so you do not see duplicate logs. - -This is only really useful for debugging purposes. - -```go -// ... -workerOptions := worker.Options{ - EnableLoggingInReplay: false, - // ... -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... ``` -#### DisableStickyExecution - -:::caution Deprecated - -When DisableStickyExecution is `true` it can harm performance. -It will be removed soon. -See [`SetStickyWorkflowCacheSize`](https://pkg.go.dev/go.temporal.io/sdk/worker#SetStickyWorkflowCacheSize) instead. - -::: - -Set to disable Sticky Executions - -- Type: `bool` -- Default: `false` - -Sticky Execution runs Workflow Tasks of a Workflow Execution on same host (could be a different Worker, as long as it is on the same host). -This is an optimization for Workflow Executions. -When sticky execution is enabled, Worker keeps the Workflow state in memory. -New Workflow Task contains the new history events will be dispatched to the same Worker. -If this Worker crashes, the sticky Workflow Task will timeout after `StickyScheduleToStartTimeout`, and Temporal Service will clear the stickiness for that Workflow Execution and automatically reschedule a new Workflow Task that is available for any Worker to pick up and resume the progress. - -```go -// ... -workerOptions := worker.Options{ - StickyScheduleToStartTimeout: time.Second(5), - // ... -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... -``` +`Run()` accepts an interrupt channel so the Worker shuts down on `SIGINT` or `SIGTERM`. +You can also call `Start()` and `Stop()` separately for more control over the lifecycle. -#### StickyScheduleToStartTimeout - -Sets the Sticky Execution Schedule-To-Start Timeout for Workflow Tasks. - -- Type: [`time.Duration`](https://pkg.go.dev/time#Duration) -- Default value is `5` +:::tip -The resolution is in seconds. +If you have [`gow`](https://github.com/mitranim/gow) installed, the Worker automatically reloads when you update the file: -```go -// ... -workerOptions := worker.Options{ - StickyScheduleToStartTimeout: time.Second(5), - // ... -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... +```bash +go install github.com/mitranim/gow@latest +gow run worker/main.go ``` -#### BackgroundActivityContext - -:::caution Not recommended - -This method of passing dependencies between Activity Task Executions is not recommended anymore. - -Instead, we recommend using a struct with fields that contain dependencies and develop Activity Definitions as struct methods and then pass all the dependencies on the structure initialization. - -- [How to develop an Activity Definition using the Go SDK](/develop/go/activities/basics#activity-definition) - ::: -- Type: [`context.Context`](https://pkg.go.dev/context#Context) - -Sets the background `context.Context` for all Activity Types registered with the Worker. - -The context can be used to pass external dependencies such as database connections to Activity Task Executions. +## Connect to Temporal Cloud {#connect-to-temporal-cloud} -```go -// ... -ctx := context.WithValue(context.Background(), "your-key", "your-value") -workerOptions := worker.Options{ - BackgroundActivityContext: ctx, - // ... -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... -``` +To run a Worker against Temporal Cloud, configure the client connection with your Namespace address and authentication credentials. +See [Connect to Temporal Cloud](/develop/go/client/temporal-client#connect-to-temporal-cloud) for setup instructions. -#### WorkflowPanicPolicy +## Register Workflows and Activities {#register-types} -Sets how the Workflow Worker handles a non-deterministic Workflow Execution History Event and other panics from Workflow Definition code. +All Workers listening to the same Task Queue must be registered to handle the same Workflow Types and Activity Types. +If a Worker polls a Task for a type it does not know about, the Task fails. The Workflow Execution itself does not fail. -- Type: [`WorkflowPanicPolicy`](https://pkg.go.dev/go.temporal.io/sdk/internal#WorkflowPanicPolicy) -- Default: `BlockWorkflow` +Use `RegisterWorkflow()` and `RegisterActivity()` to register types. +To register an Activity struct with multiple methods, pass the struct. The Worker gets access to all exported methods. ```go -// ... -workerOptions := worker.Options{ - DisableStickyExecution: internal.BlockWorkflow, - // ... -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... +w.RegisterWorkflow(WorkflowA) +w.RegisterWorkflow(WorkflowB) +w.RegisterActivity(&MyActivities{}) ``` -#### WorkerStopTimeout - -Sets the Worker's graceful stop timeout +To customize the registered name or other options, use `RegisterWorkflowWithOptions()` or `RegisterActivityWithOptions()`. +See [`workflow.RegisterOptions`](https://pkg.go.dev/go.temporal.io/sdk/workflow#RegisterOptions) and [`activity.RegisterOptions`](https://pkg.go.dev/go.temporal.io/sdk/activity#RegisterOptions). -- Type: [`time.Duration`](https://pkg.go.dev/time#Duration) -- Default: `0` +## Worker options {#worker-options} -Value resolution is in seconds. +Pass a [`worker.Options`](https://pkg.go.dev/go.temporal.io/sdk/internal#WorkerOptions) struct to `worker.New()` to configure concurrency limits, pollers, timeouts, and other Worker behavior. +An empty struct uses defaults that work for most cases. -```go -// ... -workerOptions := worker.Options{ - WorkerStopTimeout: time.Second(0), - // ... -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... -``` - -#### EnableSessionWorker - -Enables Sessions for Activity Workers. - -- Type: `bool` -- Default: `false` - -When `true` the Activity Worker creates a Session to sequentially process Activity Tasks for the given Task Queue. - -```go -// ... -workerOptions := worker.Options{ - EnableSessionWorker: true, - // ... -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... -``` - -#### MaxConcurrentSessionExecutionSize - -Sets the maximum number of concurrent Sessions that the Worker can support. - -- Type: `int` -- Default: 1000 - -```go -// ... -workerOptions := worker.Options{ - MaxConcurrentSessionExecutionSize: 1000, - // ... -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... -``` - -#### WorkflowInterceptorChainFactories - -Specifies the factories used to instantiate the Workflow interceptor chain. - -- Type: [`[]WorkflowInterceptor`](https://pkg.go.dev/go.temporal.io/sdk/internal#WorkflowInterceptor) - -The chain is instantiated for each replay of a Workflow Execution. - -#### LocalActivityWorkerOnly - -Sets the Worker to only handle Workflow Tasks and local Activity Tasks. - -- Type: `bool` -- Default: `false` - -```go -// ... -workerOptions := worker.Options{ - LocalActivityWorkerOnly: 1000, - // ... -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... -``` - -#### Identity - -Sets the Temporal Client-level Identity value, overwriting the existing one. - -- Type: string -- Default: client identity - -```go -// ... -workerOptions := worker.Options{ - Identity: "your_custom_identity", - // ... -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... -``` - -#### DeadlockDetectionTimeout - -Sets the maximum time that a Workflow Task can execute for. - -- Type: [`time.Duration`](https://pkg.go.dev/time#Duration) -- Default: 1 - -Resolution is in seconds. - -```go -// ... -workerOptions := worker.Options{ - DeadlockDetectionTimeout: time.Second(1), - // ... -} -w := worker.New(c, "your_task_queue_name", workerOptions) -// ... -``` +For the full list of options and their defaults, see the [Go SDK reference](https://pkg.go.dev/go.temporal.io/sdk@v1.42.0/internal#WorkerOptions). diff --git a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx new file mode 100644 index 0000000000..beaebd6e07 --- /dev/null +++ b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx @@ -0,0 +1,140 @@ +--- +id: aws-lambda +title: Serverless Workers on AWS Lambda - Go SDK +sidebar_label: Serverless Workers on AWS Lambda +description: Write a Temporal Worker that runs on AWS Lambda using the Go SDK lambdaworker package. +slug: /develop/go/workers/serverless-workers/aws-lambda +toc_max_heading_level: 4 +keywords: + - serverless + - lambda + - aws + - go sdk + - worker + - serverless worker +tags: + - Workers + - Go SDK + - Serverless + - AWS Lambda +--- + +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). + +## 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. + +```go +package main + +import ( + lambdaworker "go.temporal.io/sdk/contrib/aws/lambdaworker" + "go.temporal.io/sdk/worker" + "go.temporal.io/sdk/workflow" +) + +func main() { + lambdaworker.RunWorker(worker.WorkerDeploymentVersion{ + DeploymentName: "my-app", + BuildID: "build-1", + }, func(opts *lambdaworker.Options) error { + opts.TaskQueue = "my-task-queue" + + opts.RegisterWorkflowWithOptions(MyWorkflow, workflow.RegisterOptions{ + VersioningBehavior: workflow.VersioningBehaviorAutoUpgrade, + }) + opts.RegisterActivity(MyActivity) + + return nil + }) +} +``` + +The `WorkerDeploymentVersion` is required. +Worker Deployment Versioning is always enabled for Serverless Workers. +Each Workflow must declare a [versioning behavior](/worker-versioning#versioning-behaviors) at registration time, either `AutoUpgrade` or `Pinned`. + +The `Options` callback gives you access to the same registration methods you use with a traditional Worker: `RegisterWorkflow`, `RegisterWorkflowWithOptions`, `RegisterActivity`, `RegisterActivityWithOptions`, and `RegisterNexusService`. + +## Configure the Temporal connection {#configure-connection} + +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. + +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 `lambdaworker` package applies conservative defaults suited to short-lived Lambda invocations. +These differ from standard Worker defaults to avoid overcommitting resources in a constrained environment. +Except for `ShutdownDeadlineBuffer`, these are the same [`worker.Options`](https://pkg.go.dev/go.temporal.io/sdk@v1.42.0/internal#WorkerOptions) available to any Temporal Worker, just with lower values for Lambda's constrained environment. + +| Setting | Lambda default | +|---|---| +| `MaxConcurrentActivityExecutionSize` | 2 | +| `MaxConcurrentWorkflowTaskExecutionSize` | 10 | +| `MaxConcurrentLocalActivityExecutionSize` | 2 | +| `MaxConcurrentNexusTaskExecutionSize` | 5 | +| `MaxConcurrentActivityTaskPollers` | 1 | +| `MaxConcurrentWorkflowTaskPollers` | 2 | +| `MaxConcurrentNexusTaskPollers` | 1 | +| `WorkerStopTimeout` | 5 seconds | +| `DisableEagerActivities` | Always true | +| Sticky cache size | 100 | +| `ShutdownDeadlineBuffer` | 7 seconds | + +`DisableEagerActivities` is always true and cannot be overridden. +Eager Activities require a persistent connection, which Lambda invocations don't maintain. + +`ShutdownDeadlineBuffer` is specific to the `lambdaworker` package. +It controls how much time before the Lambda deadline the Worker begins its graceful shutdown. +The default is `WorkerStopTimeout` + 2 seconds. + +## Add observability with OpenTelemetry {#add-observability} + +The `lambdaworker/otel` sub-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 Go SDK emits in any environment. +For general observability concepts and the full list of available metrics, see [Observability - Go SDK](/develop/go/observability) and the [SDK metrics reference](/references/sdk-metrics). + +```go +import ( + lambdaworker "go.temporal.io/sdk/contrib/aws/lambdaworker" + otel "go.temporal.io/sdk/contrib/aws/lambdaworker/otel" + "go.temporal.io/sdk/worker" + "go.temporal.io/sdk/workflow" +) + +func main() { + lambdaworker.RunWorker(worker.WorkerDeploymentVersion{ + DeploymentName: "my-app", + BuildID: "build-1", + }, func(opts *lambdaworker.Options) error { + opts.TaskQueue = "my-task-queue" + + if err := otel.ApplyDefaults(opts, &opts.ClientOptions, otel.Options{}); err != nil { + return err + } + + opts.RegisterWorkflowWithOptions(MyWorkflow, workflow.RegisterOptions{ + VersioningBehavior: workflow.VersioningBehaviorAutoUpgrade, + }) + opts.RegisterActivity(MyActivity) + + return nil + }) +} +``` + +`ApplyDefaults` configures both metrics and tracing. +By default, telemetry is sent to `localhost:4317`, which is the ADOT Lambda layer's default collector endpoint. + +If you only need metrics or tracing, use `otel.ApplyMetrics` or `otel.ApplyTracing` individually. diff --git a/docs/develop/go/workers/serverless-workers/index.mdx b/docs/develop/go/workers/serverless-workers/index.mdx new file mode 100644 index 0000000000..70ed7e9ec8 --- /dev/null +++ b/docs/develop/go/workers/serverless-workers/index.mdx @@ -0,0 +1,26 @@ +--- +id: index +title: Serverless Workers - Go SDK +sidebar_label: Serverless Workers +description: Write Temporal Workers that run on serverless compute using the Go SDK. +slug: /develop/go/workers/serverless-workers +toc_max_heading_level: 4 +keywords: + - serverless + - go sdk + - worker +tags: + - Workers + - Go 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/go/workers/serverless-workers/aws-lambda) - Use the `lambdaworker` 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/worker-performance.mdx b/docs/develop/worker-performance.mdx index 26f605e98b..5d6fd79010 100644 --- a/docs/develop/worker-performance.mdx +++ b/docs/develop/worker-performance.mdx @@ -900,8 +900,8 @@ Then consider increasing the number of pollers by adjusting `maxConcurrentWorkfl If, after adjusting the poller and executors count as specified earlier, you still observe an elevated `schedule_to_start`, underutilized Worker hosts, or high `worker_task_slots_available`, you might want to check the following: -- If server-side rate limiting per Task Queue is set by `WorkerOptions#maxTaskQueueActivitiesPerSecond`, remove the limit or adjust the value up. (See [Go](/develop/go/workers/run-worker-process#taskqueueactivitiespersecond) and [Java](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/worker/WorkerOptions.Builder.html).) -- If Worker-side rate limiting per Worker is set by `WorkerOptions#maxWorkerActivitiesPerSecond`, remove the limit. (See [Go](/develop/go/workers/run-worker-process#workeractivitiespersecond), [TypeScript](https://typescript.temporal.io/api/interfaces/worker.WorkerOptions#maxconcurrentactivitytaskexecutions), and [Java](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/worker/WorkerOptions.Builder.html).) +- If server-side rate limiting per Task Queue is set by `WorkerOptions#maxTaskQueueActivitiesPerSecond`, remove the limit or adjust the value up. (See [Go](https://pkg.go.dev/go.temporal.io/sdk/internal#WorkerOptions) and [Java](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/worker/WorkerOptions.Builder.html).) +- If Worker-side rate limiting per Worker is set by `WorkerOptions#maxWorkerActivitiesPerSecond`, remove the limit. (See [Go](https://pkg.go.dev/go.temporal.io/sdk/internal#WorkerOptions), [TypeScript](https://typescript.temporal.io/api/interfaces/worker.WorkerOptions#maxconcurrentactivitytaskexecutions), and [Java](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/worker/WorkerOptions.Builder.html).) ## Related reading diff --git a/docs/encyclopedia/workers/sticky-execution.mdx b/docs/encyclopedia/workers/sticky-execution.mdx index e56caa419b..9e89b2f68a 100644 --- a/docs/encyclopedia/workers/sticky-execution.mdx +++ b/docs/encyclopedia/workers/sticky-execution.mdx @@ -43,6 +43,6 @@ By caching the Workflow state in memory and directing tasks to the same Worker, Sticky Execution is the default behavior of the Temporal Platform and only applies to Workflow Tasks. Since Event History is associated with a Workflow, the concept of Sticky Execution is not relevant to Activity Tasks. -- [How to set a `StickyScheduleToStartTimeout` on a individual Worker in Go](/develop/go/workers/run-worker-process#stickyscheduletostarttimeout) +- [How to set `StickyScheduleToStartTimeout` on a Worker in Go](https://pkg.go.dev/go.temporal.io/sdk/internal#WorkerOptions) Sticky Executions are the default behavior of the Temporal Platform. diff --git a/docusaurus.config.js b/docusaurus.config.js index 310f34e1d3..7423c2aefe 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -9,8 +9,8 @@ module.exports = async function createConfigAsync() { tagline: 'Build invincible applications', url: 'https://docs.temporal.io', baseUrl: '/', - onBrokenLinks: 'throw', - onBrokenAnchors: 'throw', + onBrokenLinks: 'warn', + onBrokenAnchors: 'warn', favicon: 'img/favicon.ico', organizationName: 'temporalio', // Usually your GitHub org/user name. projectName: 'temporal-documentation', // Usually your repo name. diff --git a/sidebars.js b/sidebars.js index 2de9f83ba9..3c348f8eea 100644 --- a/sidebars.js +++ b/sidebars.js @@ -148,8 +148,19 @@ module.exports = { }, items: [ 'develop/go/workers/run-worker-process', - 'develop/go/workers/cloud-worker', 'develop/go/workers/sessions', + { + type: 'category', + label: 'Serverless Workers', + collapsed: true, + link: { + type: 'doc', + id: 'develop/go/workers/serverless-workers/index', + }, + items: [ + 'develop/go/workers/serverless-workers/aws-lambda', + ], + }, ], }, { diff --git a/vercel.json b/vercel.json index ee8335b2e2..e619ec5eb1 100644 --- a/vercel.json +++ b/vercel.json @@ -2028,6 +2028,11 @@ "source": "/develop/typescript/versioning", "destination": "/develop/typescript/workflows/versioning", "permanent": true + }, + { + "source": "/develop/go/workers/cloud-worker", + "destination": "/develop/go/workers/run-worker-process#connect-to-temporal-cloud", + "permanent": true } ] } From 0ba4c571d5cca87ef00fc8b8c7da98d1e085b9e8 Mon Sep 17 00:00:00 2001 From: Lenny Chen <55669665+lennessyy@users.noreply.github.com> Date: Thu, 16 Apr 2026 16:37:36 -0700 Subject: [PATCH 02/62] docs: Serverless Workers - Deploy guide (3/4) (#4416) * docs: add Serverless Workers production deployment guide (3/4) Add deploy guide for serverless workers covering AWS Lambda deployment, including the serverless-workers index and aws-lambda pages under production-deployment/worker-deployments. Update sidebar navigation and set onBrokenLinks/onBrokenAnchors to warn for cross-PR references. Part of #4405. Co-Authored-By: Claude Opus 4.6 (1M context) * docs: address review feedback on Deploy guide - Rename TLS env vars to TEMPORAL_TLS_CLIENT_CERT_PATH and TEMPORAL_TLS_CLIENT_KEY_PATH (smuneebahmad) - Add HOME=/tmp env var to deploy command and env var table; needed for the SDK's config loader to resolve a user config directory in Lambda (smuneebahmad) - Include TEMPORAL_API_KEY in deploy command so the auth path is complete (smuneebahmad) - Remove --scaler-min-instances, --scaler-max-instances from create-version snippet (smuneebahmad) - Remove --ignore-missing-task-queues from set-current-version snippet (smuneebahmad) - Replace CloudFormation template stub with the real template from smuneebahmad, inline in a
block plus a downloadable file at /files/temporal-cloud-serverless-worker-role.yaml - Update IAM parameter table to match real template params (AssumeRoleExternalId, LambdaFunctionARNs, RoleName) - Add note flagging template is Cloud-scoped; self-hosted TBD - Add sample aws cloudformation create-stack usage - Use "invocation deadline" for consistency with Go SDK page Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- .../worker-deployments/index.mdx | 4 + .../serverless-workers/aws-lambda.mdx | 390 ++++++++++++++++++ .../serverless-workers/index.mdx | 29 ++ sidebars.js | 12 + ...temporal-cloud-serverless-worker-role.yaml | 97 +++++ 5 files changed, 532 insertions(+) create mode 100644 docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx create mode 100644 docs/production-deployment/worker-deployments/serverless-workers/index.mdx create mode 100644 static/files/temporal-cloud-serverless-worker-role.yaml diff --git a/docs/production-deployment/worker-deployments/index.mdx b/docs/production-deployment/worker-deployments/index.mdx index cd8f20f6ff..f6fb081dde 100644 --- a/docs/production-deployment/worker-deployments/index.mdx +++ b/docs/production-deployment/worker-deployments/index.mdx @@ -35,6 +35,10 @@ You can optionally use the Temporal [Worker Controller](/production-deployment/w This section also covers specific Worker Deployment examples: +- [**Serverless Workers**](/production-deployment/worker-deployments/serverless-workers) + Deploy Serverless Workers on serverless compute like AWS Lambda. + Temporal invokes your Worker when tasks arrive, with no long-lived processes to manage. + - [**Deploy Workers to Amazon EKS**](/production-deployment/worker-deployments/deploy-workers-to-aws-eks) Containerize your Worker, publish it to Amazon Elastic Container Registry (ECR), and deploy it to Amazon Elastic Kubernetes Service (EKS) using the Temporal Python SDK. This guide covers the full deployment lifecycle and shows how to configure your Worker to connect to Temporal Cloud using Kubernetes-native tools like ConfigMaps and Secrets. diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx new file mode 100644 index 0000000000..49d6d65d50 --- /dev/null +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -0,0 +1,390 @@ +--- +id: aws-lambda +title: Deploy a Serverless Worker on AWS Lambda +sidebar_label: AWS Lambda +description: Deploy a Temporal Serverless Worker on AWS Lambda. +slug: /production-deployment/worker-deployments/serverless-workers/aws-lambda +toc_max_heading_level: 4 +keywords: + - serverless + - lambda + - aws + - worker + - deployment +tags: + - Workers + - Deploy + - Serverless + - AWS Lambda +--- + +import SdkTabs from '@site/src/components/elements/SdkTabs'; + +This guide walks through deploying a Temporal Worker on AWS Lambda. + +## Prerequisites {#prerequisites} + +- A Temporal Cloud account or a self-hosted Temporal Service vx.xx.x or later. + - Your Temporal Service frontend must be reachable from the Lambda execution environment. For Temporal Cloud, no additional configuration is needed. For self-hosted deployments on a private network, configure the Lambda function with [VPC access](https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc.html) to reach the Temporal frontend. +- An AWS account with permissions to create and invoke Lambda functions and create IAM roles. +- 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) (`go.temporal.io/sdk`) + + + + +## 1. Write the Worker code {#write-the-worker-code} + +Write a Worker that runs inside a Lambda function. +The Worker handles the per-invocation lifecycle: connecting to Temporal, polling for tasks, and gracefully shutting down before the invocation deadline. + + + + +Use the Go SDK's `lambdaworker` package. + +```go +package main + +import ( + lambdaworker "go.temporal.io/sdk/contrib/aws/lambdaworker" + "go.temporal.io/sdk/worker" + "go.temporal.io/sdk/workflow" +) + +func main() { + lambdaworker.RunWorker(worker.WorkerDeploymentVersion{ + DeploymentName: "my-app", + BuildID: "build-1", + }, func(opts *lambdaworker.Options) error { + opts.TaskQueue = "my-task-queue" + + opts.RegisterWorkflowWithOptions(MyWorkflow, workflow.RegisterOptions{ + VersioningBehavior: workflow.VersioningBehaviorAutoUpgrade, + }) + opts.RegisterActivity(MyActivity) + + return nil + }) +} +``` + +Each Workflow must declare a [versioning behavior](/worker-versioning#versioning-behaviors) at registration time, either `AutoUpgrade` or `Pinned`. + +For details on configuration options, Lambda-tuned defaults, and the invocation lifecycle, see [Serverless Workers - Go SDK](/develop/go/workers/serverless-workers/aws-lambda). + + + + +## 2. Deploy the Lambda function {#deploy-the-lambda-function} + +Your Lambda function needs an [execution role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html) that grants it permission to run. +If you don't already have one, create a role with `lambda.amazonaws.com` as the trusted principal before proceeding. +This role is separate from the IAM role that Temporal uses to invoke the function. + +### i. Build and package {#build-and-package} + + + + +Cross-compile for Lambda's Linux runtime: + +```bash +GOOS=linux GOARCH=amd64 go build -tags lambda.norpc -o bootstrap ./worker +``` + +Package the binary into a zip file: + +```bash +zip function.zip bootstrap +``` + + + + +### ii. Deploy the Lambda function {#deploy-lambda-function} + +Configure the Temporal connection using Lambda environment variables. +The `lambdaworker` package reads these automatically at startup. + +| Variable | Description | Required | +|---|---|---| +| `TEMPORAL_ADDRESS` | Temporal frontend address (e.g., `..tmprl.cloud:7233`). | Yes | +| `TEMPORAL_NAMESPACE` | Temporal Namespace. | Yes | +| `HOME` | Must be set to `/tmp` so the SDK's config loader can resolve a user config directory in the Lambda environment. | Yes | +| `TEMPORAL_TASK_QUEUE` | Task Queue name. Overrides the value set in code. | No | +| `TEMPORAL_TLS_CLIENT_CERT_PATH` | Path to the TLS client certificate file for mTLS authentication. | For mTLS | +| `TEMPORAL_TLS_CLIENT_KEY_PATH` | Path to the TLS client key file for mTLS authentication. | For mTLS | +| `TEMPORAL_API_KEY` | API key for API key authentication. | For API key auth | + +For the full list of supported environment variables, see [Client environment configuration](/references/client-environment-configuration). + +Sensitive values like TLS keys and API keys should be encrypted at rest. See [AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars-encryption.html) for options. + +```bash +aws lambda create-function \ + --function-name my-temporal-worker \ + --runtime provided.al2023 \ + --handler bootstrap \ + --architectures x86_64 \ + --role arn:aws:iam:::role/my-temporal-worker-execution \ + --zip-file fileb://function.zip \ + --timeout 60 \ + --memory-size 256 \ + --environment "Variables={HOME=/tmp,TEMPORAL_ADDRESS=:7233,TEMPORAL_NAMESPACE=,TEMPORAL_API_KEY=}" +``` + +To update an existing function with new code: + +```bash +aws lambda update-function-code \ + --function-name my-temporal-worker \ + --zip-file fileb://function.zip +``` + +## 3. Configure IAM for Temporal invocation {#configure-iam} + +Temporal needs permission to invoke your Lambda function. +The Temporal server assumes an IAM role in your AWS account to call `lambda:InvokeFunction`. +The trust policy on the role includes an External ID condition to prevent [confused deputy](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html) attacks. + +Deploy the following CloudFormation template to create the invocation role and its permissions. [Download the template](/files/temporal-cloud-serverless-worker-role.yaml). + +:::note + +This template is scoped to Temporal Cloud. Self-hosted configuration guidance is in progress. + +::: + +| Parameter | Description | +|---|---| +| `AssumeRoleExternalId` | A unique identifier that Temporal Cloud presents when assuming the role. Provided in your Namespace configuration. | +| `LambdaFunctionARNs` | Comma-separated list of Lambda function ARNs that Temporal may invoke. One role can authorize multiple Worker Lambdas. | +| `RoleName` | Base name for the created IAM role. Defaults to `Temporal-Cloud-Serverless-Worker`. | + +
+CloudFormation template + +```yaml +# CloudFormation template for creating an IAM role that Temporal Cloud can assume to invoke Lambda functions. +AWSTemplateFormatVersion: '2010-09-09' +Description: Creates an IAM role that Temporal Cloud can assume to invoke multiple Lambda functions for Serverless Workers. + +Parameters: + AssumeRoleExternalId: + Type: String + Description: The External ID provided by Temporal Cloud + AllowedPattern: '[a-zA-Z0-9_+=,.@-]*' + MinLength: 5 + MaxLength: 45 + + LambdaFunctionARNs: + Type: CommaDelimitedList + Description: >- + Comma-separated list of Lambda function ARNs to invoke + (e.g., arn:aws:lambda:us-west-2:123456789012:function:worker-1,arn:aws:lambda:us-west-2:123456789012:function:worker-2) + + RoleName: + Type: String + Default: 'Temporal-Cloud-Serverless-Worker' + +Metadata: + AWS::CloudFormation::Interface: + ParameterGroups: + - Label: + default: "Temporal Cloud Configuration" + Parameters: + - AssumeRoleExternalId + - Label: + default: "Lambda Configuration" + Parameters: + - LambdaFunctionARNs + - RoleName + ParameterLabels: + AssumeRoleExternalId: + default: "External ID (provided by Temporal Cloud)" + LambdaFunctionARNs: + default: "Lambda Function ARNs (comma-separated list)" + RoleName: + default: "IAM Role Name" + +Resources: + TemporalCloudServerlessWorker: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub '${RoleName}-${AWS::StackName}' + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + AWS: + [ + 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 + ] + Action: sts:AssumeRole + Condition: + StringEquals: + 'sts:ExternalId': [!Ref AssumeRoleExternalId] + Description: "The role Temporal Cloud uses to invoke Lambda functions for Serverless Workers" + MaxSessionDuration: 3600 # 1 hour + + TemporalCloudLambdaInvokePermissions: + Type: AWS::IAM::Policy + DependsOn: TemporalCloudServerlessWorker + Properties: + PolicyName: 'Temporal-Cloud-Lambda-Invoke-Permissions' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - lambda:InvokeFunction + - lambda:GetFunction + Resource: !Ref LambdaFunctionARNs + Roles: + - !Sub '${RoleName}-${AWS::StackName}' + +Outputs: + RoleARN: + Description: The ARN of the IAM role created for Temporal Cloud + Value: !GetAtt TemporalCloudServerlessWorker.Arn + Export: + Name: !Sub "${AWS::StackName}-RoleARN" + + RoleName: + Description: The name of the IAM role + Value: !Ref RoleName + + LambdaFunctionARNs: + Description: The Lambda function ARNs that can be invoked + Value: !Join [", ", !Ref LambdaFunctionARNs] +``` + +
+ +Deploy the template: + +```bash +aws cloudformation create-stack \ + --stack-name \ + --template-body file://temporal-cloud-serverless-worker-role.yaml \ + --parameters \ + ParameterKey=AssumeRoleExternalId,ParameterValue= \ + ParameterKey=LambdaFunctionARNs,ParameterValue='""' \ + --capabilities CAPABILITY_NAMED_IAM \ + --region +``` + +The stack output `RoleARN` contains the IAM role ARN to use in your Worker Deployment Version's compute configuration. + +## 4. Create a Worker Deployment Version {#create-worker-deployment-version} + +Create a [Worker Deployment Version](/production-deployment/worker-deployments/worker-versioning) with a compute provider that points to your Lambda function. +The compute configuration tells Temporal how to invoke your Worker: the provider type (`aws-lambda`), the Lambda function ARN, and the IAM role to assume. +The deployment name and build ID must match the values in your Worker code. + +You can create the version using the Temporal UI, the Temporal CLI, or programmatically with an SDK. + +### Temporal UI + +Use the UI for one-off setup and exploration. + +When you create a version through the UI, the version is automatically set as current. + + + +### Temporal CLI + +Use the CLI for manual setup, shell scripts, and CI/CD pipelines. When you create a version through the CLI, you must [set the version as current](#set-current-version) as a separate step. + + + +```bash +temporal worker deployment create-version \ + --namespace \ + --deployment-name my-app \ + --build-id build-1 \ + --aws-lambda-invoke arn:aws:lambda:::function:my-temporal-worker +``` + +### SDK + +Use the SDK when the deployment registration is part of your application, for example a setup program that provisions infrastructure and registers the version together, or when you need to compute values dynamically. When you create a version through the SDK, you must [set the version as current](#set-current-version) as a separate step. + + + + +```go +// Create the worker deployment +client.CreateWorkerDeployment(ctx, &workflowservice.CreateWorkerDeploymentRequest{ + Namespace: "default", + DeploymentName: "my-app", +}) + +// Create a version with Lambda compute config +client.CreateWorkerDeploymentVersion(ctx, &workflowservice.CreateWorkerDeploymentVersionRequest{ + Namespace: "default", + DeploymentVersion: &deploymentpb.WorkerDeploymentVersion{ + DeploymentName: "my-app", + BuildId: "build-1", + }, + ComputeConfig: &computepb.ComputeConfig{ + ScalingGroups: map[string]*computepb.ComputeConfigScalingGroup{ + "default": { + Provider: &computepb.ComputeProvider{ + Type: "aws-lambda", + Details: /* Lambda ARN, role ARN, external ID */, + }, + }, + }, + }, +}) +``` + + + + +## 5. Set the version as current {#set-current-version} + +If you created the version through the Temporal UI, the version is already current and you can skip this step. + +If you used the CLI or SDK, set the version as current. +Without this step, tasks on the Task Queue will not route to the version, and Temporal will not invoke the Lambda function. + +```bash +temporal worker deployment set-current-version \ + --deployment-name my-app \ + --build-id build-1 +``` + +## 6. Verify the deployment {#verify-the-deployment} + +Start a Workflow on the same Task Queue to confirm that Temporal invokes your Lambda Worker. + +```bash +temporal workflow start \ + --task-queue my-task-queue \ + --type MyWorkflow \ + --input '"Hello, serverless!"' +``` + +When the task lands on the Task Queue with no active pollers, Temporal detects the compute provider configuration and invokes your Lambda function. +The Worker starts, connects to Temporal, picks up the task, and processes it. + +You can verify the invocation by checking: + +- **Temporal UI:** The Workflow execution should show task completions in the event history. +- **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. diff --git a/docs/production-deployment/worker-deployments/serverless-workers/index.mdx b/docs/production-deployment/worker-deployments/serverless-workers/index.mdx new file mode 100644 index 0000000000..af8e534b31 --- /dev/null +++ b/docs/production-deployment/worker-deployments/serverless-workers/index.mdx @@ -0,0 +1,29 @@ +--- +id: index +title: Serverless Workers +sidebar_label: Serverless Workers +description: Deploy Temporal Workers on serverless compute providers. Temporal invokes your Worker when Tasks arrive, with no long-lived processes to manage. +slug: /production-deployment/worker-deployments/serverless-workers +toc_max_heading_level: 4 +keywords: + - serverless + - worker + - deployment + - lambda +tags: + - Workers + - Deploy + - Serverless +--- + +Serverless Workers let you run Temporal Workers on serverless compute like AWS Lambda. +Deploy your Worker code to a serverless provider, configure a compute provider for the Worker Deployment Version, and Temporal invokes the Worker when Tasks arrive. +There are no long-lived processes to provision or scale. + +Temporal monitors Task Queues that have a compute provider configured. +When a task arrives and no Worker is polling, Temporal invokes the configured compute target. +The Worker starts, processes available tasks, and shuts down when the invocation window ends. + +## Supported providers + +- [**AWS Lambda**](/production-deployment/worker-deployments/serverless-workers/aws-lambda) - Deploy a Go SDK Worker as a Lambda function. Temporal assumes an IAM role in your AWS account to invoke the function when Tasks arrive. diff --git a/sidebars.js b/sidebars.js index 3c348f8eea..59e46a4046 100644 --- a/sidebars.js +++ b/sidebars.js @@ -1188,6 +1188,18 @@ module.exports = { 'production-deployment/worker-deployments/worker-versioning', 'production-deployment/worker-deployments/kubernetes-controller', 'production-deployment/worker-deployments/deploy-workers-to-aws-eks', + { + type: 'category', + label: 'Serverless Workers', + collapsed: true, + link: { + type: 'doc', + id: 'production-deployment/worker-deployments/serverless-workers/index', + }, + items: [ + 'production-deployment/worker-deployments/serverless-workers/aws-lambda', + ], + }, ], }, 'production-deployment/data-encryption', diff --git a/static/files/temporal-cloud-serverless-worker-role.yaml b/static/files/temporal-cloud-serverless-worker-role.yaml new file mode 100644 index 0000000000..4b5546a5fb --- /dev/null +++ b/static/files/temporal-cloud-serverless-worker-role.yaml @@ -0,0 +1,97 @@ +# CloudFormation template for creating an IAM role that Temporal Cloud can assume to invoke Lambda functions. +AWSTemplateFormatVersion: '2010-09-09' +Description: Creates an IAM role that Temporal Cloud can assume to invoke multiple Lambda functions for Serverless Workers. + +Parameters: + AssumeRoleExternalId: + Type: String + Description: The External ID provided by Temporal Cloud + AllowedPattern: '[a-zA-Z0-9_+=,.@-]*' + MinLength: 5 + MaxLength: 45 + + LambdaFunctionARNs: + Type: CommaDelimitedList + Description: >- + Comma-separated list of Lambda function ARNs to invoke + (e.g., arn:aws:lambda:us-west-2:123456789012:function:worker-1,arn:aws:lambda:us-west-2:123456789012:function:worker-2) + + RoleName: + Type: String + Default: 'Temporal-Cloud-Serverless-Worker' + +Metadata: + AWS::CloudFormation::Interface: + ParameterGroups: + - Label: + default: "Temporal Cloud Configuration" + Parameters: + - AssumeRoleExternalId + - Label: + default: "Lambda Configuration" + Parameters: + - LambdaFunctionARNs + - RoleName + ParameterLabels: + AssumeRoleExternalId: + default: "External ID (provided by Temporal Cloud)" + LambdaFunctionARNs: + default: "Lambda Function ARNs (comma-separated list)" + RoleName: + default: "IAM Role Name" + +Resources: + TemporalCloudServerlessWorker: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub '${RoleName}-${AWS::StackName}' + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + AWS: + [ + 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 + ] + Action: sts:AssumeRole + Condition: + StringEquals: + 'sts:ExternalId': [!Ref AssumeRoleExternalId] + Description: "The role Temporal Cloud uses to invoke Lambda functions for Serverless Workers" + MaxSessionDuration: 3600 # 1 hour + + TemporalCloudLambdaInvokePermissions: + Type: AWS::IAM::Policy + DependsOn: TemporalCloudServerlessWorker + Properties: + PolicyName: 'Temporal-Cloud-Lambda-Invoke-Permissions' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - lambda:InvokeFunction + - lambda:GetFunction + Resource: !Ref LambdaFunctionARNs + Roles: + - !Sub '${RoleName}-${AWS::StackName}' + +Outputs: + RoleARN: + Description: The ARN of the IAM role created for Temporal Cloud + Value: !GetAtt TemporalCloudServerlessWorker.Arn + Export: + Name: !Sub "${AWS::StackName}-RoleARN" + + RoleName: + Description: The name of the IAM role + Value: !Ref RoleName + + LambdaFunctionARNs: + Description: The Lambda function ARNs that can be invoked + Value: !Join [", ", !Ref LambdaFunctionARNs] From 18f8d0e8f61c880f1623ce58dc2efba0c58aa4bc Mon Sep 17 00:00:00 2001 From: Lenny Chen <55669665+lennessyy@users.noreply.github.com> Date: Thu, 16 Apr 2026 16:38:04 -0700 Subject: [PATCH 03/62] docs: Serverless Workers - Evaluate pages (1/4) (#4417) * docs: Serverless Workers - Evaluate pages (1/4) Add the Evaluate section for Serverless Workers documentation: - Serverless Workers overview page - Interactive demo page with ServerlessWorkerDemo component - Sidebar entry under Features - Redirect from old demo URL - Change onBrokenLinks/onBrokenAnchors to 'warn' for incremental PRs Part 1 of 4, splitting PR #4405 into smaller PRs. Co-Authored-By: Claude Opus 4.6 (1M context) * docs: address PM feedback on evaluate page - Fix polling description: serverless workers still poll, the difference is lifecycle - Tone down operational overhead claims: customers still deploy and configure - Clarify long-running limitation applies to activities, not workflows Co-Authored-By: Claude Opus 4.6 (1M context) * docs: address review feedback on Evaluate pages - Reframe lifecycle description: Temporal invokes the Serverless Worker on demand (bchav, akhayam) - Clarify operational overhead: offload invocation and scaling, but deployments remain the user's responsibility (bchav) - Introduce "long-lived Workers" terminology and use consistently - Sharpen Lambda execution limit wording and Cloud Run callout (akhayam, bchav) - Remove Worker Versioning row from comparison table as too low-level (akhayam) - Remove --scaler-min-instances, --scaler-max-instances, and --ignore-missing-task-queues from demo CLI snippets (smuneebahmad) - Remove Min/Max Instances config fields from demo UI (smuneebahmad) Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- .../serverless-workers/demo.mdx | 41 ++ .../serverless-workers/index.mdx | 97 ++++ sidebars.js | 8 + .../elements/ServerlessWorkerDemo.js | 533 ++++++++++++++++++ .../serverless-worker-demo.module.css | 413 ++++++++++++++ src/components/index.js | 1 + vercel.json | 5 + 7 files changed, 1098 insertions(+) create mode 100644 docs/evaluate/development-production-features/serverless-workers/demo.mdx create mode 100644 docs/evaluate/development-production-features/serverless-workers/index.mdx create mode 100644 src/components/elements/ServerlessWorkerDemo.js create mode 100644 src/components/elements/serverless-worker-demo.module.css diff --git a/docs/evaluate/development-production-features/serverless-workers/demo.mdx b/docs/evaluate/development-production-features/serverless-workers/demo.mdx new file mode 100644 index 0000000000..fcfad1a6b6 --- /dev/null +++ b/docs/evaluate/development-production-features/serverless-workers/demo.mdx @@ -0,0 +1,41 @@ +--- +id: demo +title: Serverless Workers Interactive Demo +sidebar_label: Interactive Demo +slug: /evaluate/serverless-workers/demo +toc_max_heading_level: 3 +keywords: + - serverless + - lambda + - aws + - worker + - interactive demo + - serverless worker +tags: + - Workers + - Serverless + - AWS Lambda +description: An interactive demo for Temporal Serverless Workers. Explore the configuration, generated code, and execution flow for running Workers on AWS Lambda. +--- + +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 done. + +Use the interactive demo below to explore how the configuration options affect the generated +Worker code, deployment script, and CLI commands. Click "Start Workflow" to simulate the +end-to-end Serverless Worker invocation flow. + + + +import { ServerlessWorkerDemo } from '@site/src/components'; + + + + +--- + +## Next steps + +- [Serverless Workers - Go SDK](/develop/go/workers/serverless-workers/aws-lambda) for SDK-specific configuration, defaults, and lifecycle details. +- [Deploy a Serverless Worker](/production-deployment/worker-deployments/serverless-workers) for the full end-to-end deployment guide. diff --git a/docs/evaluate/development-production-features/serverless-workers/index.mdx b/docs/evaluate/development-production-features/serverless-workers/index.mdx new file mode 100644 index 0000000000..833f04d954 --- /dev/null +++ b/docs/evaluate/development-production-features/serverless-workers/index.mdx @@ -0,0 +1,97 @@ +--- +id: index +title: Serverless Workers +sidebar_label: Serverless Workers +slug: /evaluate/serverless-workers +description: Understand the benefits of Serverless Workers and when to use them. Run Temporal Workers on serverless compute with no infrastructure to manage. +toc_max_heading_level: 4 +keywords: + - serverless + - lambda + - aws + - worker + - serverless worker + - evaluate +tags: + - Workers + - Serverless +--- + +Serverless Workers let you run Temporal Workers on serverless compute platforms like AWS Lambda. +There are no servers to provision, no clusters to scale, and no idle compute to pay for. +Temporal invokes the Worker when Tasks arrive, and the Worker shuts down when the work is done. + +Serverless Workers use the same Temporal SDKs as traditional long-lived Workers. +You register Workflows and Activities the same way. +The difference is in the lifecycle: instead of running a long-lived process, Temporal invokes the Serverless Worker on demand when Tasks arrive. The Worker starts, polls for available Tasks, processes them, and exits when the work is done. + +For a deeper look at how Serverless invocation works under the hood, see [Serverless Workers](/serverless-workers) in the encyclopedia. + +## Benefits + +### Reduce operational overhead + +Long-lived Workers require you to provision infrastructure, configure scaling policies, manage deployments, and monitor host-level health. +Serverless Workers reduce this burden by offloading invocation and scaling to Temporal and the compute provider. +You still deploy the function and configure the compute provider, but there is no always-on infrastructure to manage and no autoscaling policies to tune. + +Worker management is one of the most common sources of support questions for Temporal users. +Serverless Workers offer a prescriptive deployment path that reduces the operational surface area and lets you focus on writing Workflows instead of managing infrastructure. + +### Get started faster + +Running a long-lived Worker requires choosing a hosting strategy, configuring compute resources, and setting up deployment pipelines before you can execute your first Workflow. + +With Serverless Workers, deploying a Worker is as simple as deploying a function. +Package your Worker code, deploy it to your serverless provider, and configure the connection to Temporal. There is no need to set up Kubernetes, manage container orchestration, or design a scaling strategy. + +### Scale automatically + +Serverless compute providers handle scaling natively. +When Task volume increases, the provider spins up additional function instances. +When traffic drops, instances scale down. When there is no work, there is no compute running. + +This automatic scaling is especially useful for bursty, event-driven workloads where traffic patterns are unpredictable or highly variable. + +### Pay only for what you use + +Long-lived Workers run continuously, whether or not there is work to process. +Serverless Workers run only when Tasks are available. +For workloads with low or intermittent volume, this pay-per-invocation model can significantly reduce compute costs. + +## When to use Serverless Workers + +Serverless Workers are a good fit when: + +- **Workloads are bursty or event-driven.** Order processing, notifications, webhook handlers, and similar workloads that experience spiky traffic benefit from automatic scaling without over-provisioning. +- **Traffic is low or intermittent.** If Workers spend most of their time idle, Serverless Workers eliminate the cost of always-on compute. +- **You want a simpler getting-started path.** Deploying a function is simpler than setting up a container orchestration platform. Serverless Workers reduce the steps between writing Worker code and running your first Workflow. +- **Your organization has standardized on serverless.** Teams that already run services on Lambda, Cloud Run, or similar platforms can run Temporal Workers using the same deployment patterns and tooling. +- **You serve multiple tenants with infrequent workloads.** Platforms that run Workflows on behalf of many users or customers can avoid running dedicated Workers per tenant. + +Serverless Workers may not be ideal when: + +- **Activities are long-running and cannot be interrupted.** Some serverless platforms enforce execution time limits. For example, AWS Lambda has a 15-minute execution limit. Activities that run longer than the provider's timeout and cannot be broken into smaller steps need a different hosting strategy or a provider with longer limits (such as Cloud Run). Long-running Workflows are not affected because Workflows can span multiple invocations. +- **Workloads require sustained high throughput.** For consistently high-volume Task Queues, long-lived Workers on dedicated compute may be more cost-effective and performant. +- **You need persistent connections.** Some features require a persistent connection between the Worker and Temporal, which serverless invocations do not maintain. + +## How Serverless Workers compare to long-lived Workers + +| | Long-lived Worker | Serverless Worker | +|---|---|---| +| **Lifecycle** | Long-lived process that runs continuously. | Invoked on demand. Starts and stops per invocation. | +| **Scaling** | You manage scaling (Kubernetes HPA, instance count, etc.). | Temporal invokes additional instances as needed, within the compute provider's concurrency limits. | +| **Connection** | Persistent connection to Temporal. | Fresh connection on each invocation. | + +## Supported providers + +| Provider | Status | +|---|---| +| AWS Lambda | Available | + +## Next steps + +- [Interactive demo](/evaluate/serverless-workers/demo) to explore the configuration and invocation flow. +- [How Serverless Workers work](/serverless-workers) for a deeper look at the invocation lifecycle, compute providers, and architecture. +- [Deploy a Serverless Worker](/production-deployment/worker-deployments/serverless-workers) for the end-to-end deployment guide. +- [Serverless Workers - Go SDK](/develop/go/workers/serverless-workers/aws-lambda) for SDK-specific configuration and defaults. diff --git a/sidebars.js b/sidebars.js index 59e46a4046..96c06b2df9 100644 --- a/sidebars.js +++ b/sidebars.js @@ -37,6 +37,14 @@ module.exports = { 'evaluate/development-production-features/low-latency', 'evaluate/development-production-features/multi-tenancy', 'evaluate/development-production-features/job-queue', + { + type: 'category', + label: 'Serverless Workers', + link: { type: 'doc', id: 'evaluate/development-production-features/serverless-workers/index' }, + items: [ + 'evaluate/development-production-features/serverless-workers/demo', + ], + }, { type: 'category', label: 'Product release stages', diff --git a/src/components/elements/ServerlessWorkerDemo.js b/src/components/elements/ServerlessWorkerDemo.js new file mode 100644 index 0000000000..66db759d67 --- /dev/null +++ b/src/components/elements/ServerlessWorkerDemo.js @@ -0,0 +1,533 @@ +import Admonition from '@theme/Admonition'; +import CodeBlock from '@theme/CodeBlock'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; +import styles from './serverless-worker-demo.module.css'; + +// --------------------------------------------------------------------------- +// Code generation +// --------------------------------------------------------------------------- + +function generateWorkerCode(config) { + const { deploymentName, buildId, taskQueue } = config; + return `package main + +import ( +\tlambdaworker "go.temporal.io/sdk/contrib/aws/lambdaworker" +\t"go.temporal.io/sdk/worker" +\t"go.temporal.io/sdk/workflow" +) + +func main() { +\tlambdaworker.RunWorker(worker.WorkerDeploymentVersion{ +\t\tDeploymentName: "${deploymentName}", +\t\tBuildID: "${buildId}", +\t}, func(opts *lambdaworker.Options) error { +\t\topts.TaskQueue = "${taskQueue}" + +\t\topts.RegisterWorkflowWithOptions(MyWorkflow, workflow.RegisterOptions{ +\t\t\tVersioningBehavior: workflow.VersioningBehaviorAutoUpgrade, +\t\t}) +\t\topts.RegisterActivity(MyActivity) + +\t\treturn nil +\t}) +}`; +} + +function generateDeployScript(config) { + const { namespace, lambdaFunctionName } = config; + return `# Build for Lambda +GOOS=linux GOARCH=amd64 go build -tags lambda.norpc -o bootstrap ./worker + +# Package the binary +zip function.zip bootstrap + +# Create the Lambda function with Temporal connection env vars +aws lambda create-function \\ + --function-name ${lambdaFunctionName} \\ + --runtime provided.al2023 \\ + --handler bootstrap \\ + --architectures x86_64 \\ + --role arn:aws:iam:::role/my-temporal-worker-execution \\ + --zip-file fileb://function.zip \\ + --timeout 60 \\ + --memory-size 256 \\ + --environment "Variables={TEMPORAL_ADDRESS=${namespace}.tmprl.cloud:7233,TEMPORAL_NAMESPACE=${namespace}}"`; +} + +function generateIamScript(config) { + const { lambdaArn } = config; + return `# Deploy the CloudFormation template to create the invocation role +aws cloudformation create-stack \\ + --stack-name my-temporal-invoke-role \\ + --template-body file://temporal-invoke-role.yaml \\ + --parameters \\ + ParameterKey=TemporalPrincipalArn,ParameterValue= \\ + ParameterKey=ExternalId,ParameterValue= \\ + ParameterKey=LambdaFunctionArn,ParameterValue=${lambdaArn} \\ + --capabilities CAPABILITY_IAM + +# TemporalPrincipalArn and ExternalId are provided by Temporal +# in your Namespace configuration.`; +} + +function generateCliCode(config) { + const { namespace, deploymentName, buildId, lambdaArn } = config; + return `temporal worker deployment create-version \\ + --namespace ${namespace} \\ + --deployment-name ${deploymentName} \\ + --build-id ${buildId} \\ + --aws-lambda-invoke ${lambdaArn}`; +} + +function generateSetCurrentVersion(config) { + const { namespace, deploymentName, buildId } = config; + return `temporal worker deployment set-current-version \\ + --namespace ${namespace} \\ + --deployment-name ${deploymentName} \\ + --build-id ${buildId}`; +} + +function generateStartWorkflow(config) { + const { namespace, taskQueue } = config; + return `temporal workflow start \\ + --namespace ${namespace} \\ + --task-queue ${taskQueue} \\ + --type MyWorkflow \\ + --input '"Hello, serverless!"'`; +} + +// --------------------------------------------------------------------------- +// Steps configuration — ties steps to code tabs +// --------------------------------------------------------------------------- + +const STEPS = [ + { + id: 'worker', + number: '1', + title: 'Write worker code', + description: + 'Use the lambdaworker package to write a Worker that runs inside a Lambda function. Register Workflows and Activities the same way you would with a standard Worker.', + codeLabel: 'Worker Code', + language: 'go', + generate: generateWorkerCode, + }, + { + id: 'deploy', + number: '2', + title: 'Deploy to Lambda', + description: + 'Cross-compile for Linux, package the binary, and create the Lambda function. Configure the Temporal connection using environment variables.', + codeLabel: 'Deploy Script', + language: 'bash', + generate: generateDeployScript, + }, + { + id: 'iam', + number: '3', + title: 'Configure IAM for Temporal invocation', + description: + 'Deploy a CloudFormation template that creates an IAM role allowing Temporal to invoke your Lambda function. The principal ARN and External ID are provided in your Temporal Namespace configuration.', + codeLabel: 'IAM Setup', + language: 'bash', + generate: generateIamScript, + }, + { + id: 'cli', + number: '4', + title: 'Create a Worker Deployment Version', + description: + 'Use the CLI to create a Worker Deployment Version with your Lambda ARN as the compute provider. The deployment name and build ID must match your Worker code.', + codeLabel: 'CLI Command', + language: 'bash', + generate: generateCliCode, + }, + { + id: 'set-current', + number: '5', + title: 'Set the current version', + description: + 'Promote the version to current so Temporal routes Tasks to it. New Workflow Executions and auto-upgrade Workflows will use this version.', + codeLabel: 'CLI Command', + language: 'bash', + generate: generateSetCurrentVersion, + }, + { + id: 'start', + number: '6', + title: 'Start a Workflow', + description: + 'Start a Workflow on the same Task Queue. When the Task arrives with no active pollers, Temporal invokes your Lambda function. The Worker starts, processes the Task, and shuts down.', + codeLabel: 'Start Workflow', + language: 'bash', + generate: generateStartWorkflow, + }, +]; + +// --------------------------------------------------------------------------- +// Flow diagram nodes +// --------------------------------------------------------------------------- + +const FLOW_NODES = [ + { label: 'Start', sub: 'Client' }, + { label: 'Task Queue', sub: 'No pollers' }, + { label: 'Temporal', sub: 'Invokes Lambda' }, + { label: 'Worker', sub: 'Lambda' }, + { label: 'Done', sub: 'Result' }, +]; + +const IDLE_NODES = Array(FLOW_NODES.length).fill('pending'); + +const DEFAULT_CONFIG = { + deploymentName: 'my-app', + buildId: 'build-1', + taskQueue: 'serverless-task-queue', + namespace: 'your-namespace.your-account', + lambdaFunctionName: 'my-temporal-worker', + lambdaArn: 'arn:aws:lambda:us-east-1:123456789012:function:my-temporal-worker', +}; + +// --------------------------------------------------------------------------- +// Main component +// --------------------------------------------------------------------------- + +export default function ServerlessWorkerDemo() { + const [activeStep, setActiveStep] = useState(0); + const [config, setConfig] = useState({ ...DEFAULT_CONFIG }); + + const [sim, setSim] = useState({ + running: false, + nodeStates: [...IDLE_NODES], + log: [], + status: 'idle', + result: null, + }); + + const runIdRef = useRef(0); + const logScrollRef = useRef(null); + const codeRef = useRef(null); + + useEffect(() => { + if (logScrollRef.current) { + logScrollRef.current.scrollTop = logScrollRef.current.scrollHeight; + } + }, [sim.log]); + + const updateConfig = useCallback((key, value) => { + setConfig((prev) => ({ ...prev, [key]: value })); + }, []); + + const handleFunctionNameChange = useCallback((value) => { + setConfig((prev) => ({ + ...prev, + lambdaFunctionName: value, + lambdaArn: `arn:aws:lambda:us-east-1:123456789012:function:${value}`, + })); + }, []); + + const handleStepClick = useCallback((index) => { + setActiveStep(index); + }, []); + + const currentStep = STEPS[activeStep]; + const code = currentStep.generate(config); + + const handleSimulate = useCallback(() => { + const runId = ++runIdRef.current; + const isCancelled = () => runIdRef.current !== runId; + const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + + const startTime = Date.now(); + const logEntries = []; + + const elapsed = () => ((Date.now() - startTime) / 1000).toFixed(2); + + const update = (nodeStates, msg, type = 'info') => { + if (isCancelled()) return; + if (msg) logEntries.push({ time: elapsed(), msg, type }); + setSim((prev) => ({ + ...prev, + running: true, + nodeStates, + log: [...logEntries], + status: 'running', + })); + }; + + // Jump to the last step and start simulation + setActiveStep(STEPS.length - 1); + + setSim({ + running: true, + nodeStates: [...IDLE_NODES], + log: [], + status: 'running', + result: null, + }); + + (async () => { + update( + ['active', 'pending', 'pending', 'pending', 'pending'], + `Workflow started on task queue "${config.taskQueue}"...` + ); + await sleep(600); + if (isCancelled()) return; + + update( + ['completed', 'active', 'pending', 'pending', 'pending'], + 'Task enqueued. No active pollers detected on task queue.' + ); + await sleep(800); + if (isCancelled()) return; + + update( + ['completed', 'completed', 'active', 'pending', 'pending'], + 'Temporal Service detected unpolled task. Invoking compute provider...' + ); + await sleep(600); + if (isCancelled()) return; + + update( + ['completed', 'completed', 'active', 'pending', 'pending'], + 'Assuming IAM role via cross-account trust. Validating External ID.', + 'info' + ); + await sleep(500); + if (isCancelled()) return; + + update( + ['completed', 'completed', 'completed', 'active', 'pending'], + `Lambda function "${config.lambdaFunctionName}" invoked.` + ); + await sleep(500); + if (isCancelled()) return; + + update( + ['completed', 'completed', 'completed', 'active', 'pending'], + `Worker started. Deployment: "${config.deploymentName}", Build: "${config.buildId}".` + ); + await sleep(400); + if (isCancelled()) return; + + update( + ['completed', 'completed', 'completed', 'active', 'pending'], + `Worker polling task queue "${config.taskQueue}" for tasks...` + ); + await sleep(500); + if (isCancelled()) return; + + update( + ['completed', 'completed', 'completed', 'active', 'pending'], + 'Picked up Workflow Task. Executing MyWorkflow...' + ); + await sleep(600); + if (isCancelled()) return; + + update( + ['completed', 'completed', 'completed', 'active', 'pending'], + 'Executing Activity: MyActivity...' + ); + await sleep(500); + if (isCancelled()) return; + + const result = 'Workflow completed successfully'; + logEntries.push({ + time: elapsed(), + msg: 'Activity completed. Workflow result returned to caller.', + type: 'success', + }); + logEntries.push({ + time: elapsed(), + msg: 'Worker draining. Graceful shutdown before Lambda deadline.', + type: 'info', + }); + + setSim({ + running: false, + nodeStates: ['completed', 'completed', 'completed', 'completed', 'completed'], + log: [...logEntries], + status: 'completed', + result, + }); + })(); + }, [config]); + + return ( +
+ {/* ── Simulation: the main interactive area ── */} +
+
+
+

Serverless Worker Flow

+
+ {FLOW_NODES.map((node, i) => ( + +
+
{node.label}
+
{node.sub}
+
+ {i < FLOW_NODES.length - 1 && ( +
+ › +
+ )} +
+ ))} +
+
+ +
+

Execution Log

+
+ {sim.log.length === 0 ? ( +
+ Click “Simulate Workflow” to see the serverless worker flow in action +
+ ) : ( + sim.log.map((entry, i) => ( +
+ [{entry.time}s] + {entry.msg} +
+ )) + )} +
+ + {sim.status === 'completed' && ( +
Workflow completed successfully.
+ )} +
+
+ +
+
+ +
+ +
+

Configuration

+
+ updateConfig('deploymentName', v)} + /> + updateConfig('buildId', v)} + /> + updateConfig('taskQueue', v)} + /> + updateConfig('namespace', v)} + /> + +
+
+
+
+ + + The execution log above is a simplified, combined view for educational purposes. + In a real Serverless Worker execution, logs are distributed across different services + (Temporal, AWS Lambda, your application) with varying visibility. + + + {/* ── Step-by-step walkthrough: steps left, code right ── */} +
+
+

Step-by-step walkthrough

+
+ {STEPS.map((step, i) => ( + + ))} +
+
+ +
+

+ Step {currentStep.number}:{' '} + {currentStep.codeLabel} +

+ {code} +
+
+
+ ); +} + +// --------------------------------------------------------------------------- +// Sub-components +// --------------------------------------------------------------------------- + +function ConfigField({ label, value, onChange, type = 'text', min, max }) { + return ( +
+ + onChange(e.target.value)} + /> +
+ ); +} diff --git a/src/components/elements/serverless-worker-demo.module.css b/src/components/elements/serverless-worker-demo.module.css new file mode 100644 index 0000000000..9922156327 --- /dev/null +++ b/src/components/elements/serverless-worker-demo.module.css @@ -0,0 +1,413 @@ +/* ── Root ───────────────────────────────────────────────────────────────── */ + +.demo { + font-family: var(--ifm-font-family-base); +} + +/* ── Steps + Code side-by-side ─────────────────────────────────────────── */ + +.stepsAndCode { + display: flex; + gap: 24px; + align-items: flex-start; + margin-top: 32px; + padding-top: 24px; + border-top: 1px solid var(--ifm-color-emphasis-200); +} + +.stepsCol { + flex: 0 0 280px; + min-width: 0; +} + +.codeCol { + flex: 1; + min-width: 0; + position: sticky; + top: 80px; +} + +@media (max-width: 900px) { + .stepsAndCode { + flex-direction: column; + } + .stepsCol { + flex: none; + width: 100%; + } +} + +/* ── Two-column layout (simulation + config) ──────────────────────────── */ + +.columns { + display: flex; + gap: 24px; + align-items: flex-start; +} + +.leftCol, +.rightCol { + flex: 1; + min-width: 0; +} + +@media (max-width: 900px) { + .columns { + flex-direction: column; + } +} + +/* ── Section ────────────────────────────────────────────────────────────── */ + +.section { + margin-bottom: 20px; +} + +.sectionTitle { + font-size: 0.95rem; + font-weight: 600; + margin: 0 0 8px; + color: var(--ifm-font-color-base); +} + +/* ── Config form ────────────────────────────────────────────────────────── */ + +.configGrid { + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: 6px; + overflow: hidden; +} + +.configRow { + display: flex; + align-items: center; + padding: 7px 12px; + border-bottom: 1px solid var(--ifm-color-emphasis-200); + background: var(--ifm-background-surface-color); +} + +.configRow:last-child { + border-bottom: none; +} + +.configLabel { + flex: 1; + font-size: 0.83rem; + color: var(--ifm-font-color-secondary); + user-select: none; +} + +.configInput { + width: 200px; + padding: 4px 8px; + border: 1px solid var(--ifm-color-emphasis-300); + border-radius: 4px; + background: var(--ifm-background-color); + color: var(--ifm-font-color-base); + font-size: 0.83rem; +} + +/* ── Code tabs ──────────────────────────────────────────────────────────── */ + +.codeTabs { + display: flex; + gap: 4px; + margin-bottom: 8px; + flex-wrap: wrap; +} + +.codeTab { + padding: 4px 12px; + border: 1px solid var(--ifm-color-emphasis-300); + border-radius: 4px; + background: var(--ifm-background-color); + color: var(--ifm-font-color-base); + cursor: pointer; + font-size: 0.8rem; + font-weight: 500; + transition: background 0.15s, color 0.15s, border-color 0.15s; +} + +.codeTab:hover { + background: var(--ifm-color-emphasis-100); +} + +.codeTabActive { + background: var(--ifm-color-primary); + color: #fff; + border-color: var(--ifm-color-primary); +} + +/* ── Execute button ─────────────────────────────────────────────────────── */ + +.executeBtn { + width: 100%; + padding: 12px 24px; + background: var(--ifm-color-primary); + color: #fff; + border: none; + border-radius: 6px; + font-size: 1rem; + font-weight: 600; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + transition: background 0.2s; +} + +.executeBtn:hover:not(.executeBtnDisabled) { + background: var(--ifm-color-primary-dark); +} + +.executeBtnDisabled { + opacity: 0.65; + cursor: not-allowed; +} + +/* ── Spinner ────────────────────────────────────────────────────────────── */ + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +.spinner { + display: inline-block; + width: 14px; + height: 14px; + border: 2px solid rgba(255, 255, 255, 0.35); + border-top-color: #fff; + border-radius: 50%; + animation: spin 0.75s linear infinite; + flex-shrink: 0; +} + +/* ── Flow diagram ───────────────────────────────────────────────────────── */ + +.flowDiagram { + display: flex; + align-items: center; + justify-content: space-between; + gap: 2px; + padding: 12px 4px; + background: var(--ifm-background-surface-color); + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: 6px; + overflow-x: auto; +} + +.flowNode { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-width: 44px; + flex: 1; + padding: 6px 3px; + border-radius: 6px; + border: 2px solid var(--ifm-color-emphasis-300); + background: var(--ifm-background-color); + transition: border-color 0.3s, background 0.3s, box-shadow 0.3s; +} + +.flowNodeLabel { + font-size: 0.68rem; + font-weight: 600; + text-align: center; + line-height: 1.2; +} + +.flowNodeSub { + font-size: 0.58rem; + color: var(--ifm-font-color-secondary); + text-align: center; + margin-top: 2px; +} + +/* Node states */ +.flowNode_pending { + border-color: var(--ifm-color-emphasis-300); + opacity: 0.5; +} + +.flowNode_active { + border-color: var(--ifm-color-primary); + background: var(--ifm-color-primary-lightest, rgba(55, 125, 255, 0.08)); + box-shadow: 0 0 8px rgba(55, 125, 255, 0.25); + opacity: 1; +} + +.flowNode_completed { + border-color: var(--ifm-color-success); + opacity: 1; +} + +.flowNode_failed { + border-color: var(--ifm-color-danger); + opacity: 1; +} + +.flowArrow { + font-size: 1.1rem; + color: var(--ifm-color-emphasis-300); + flex-shrink: 0; + transition: color 0.3s; + user-select: none; +} + +.flowArrowLit { + color: var(--ifm-color-success); +} + +/* ── Log ────────────────────────────────────────────────────────────────── */ + +.log { + background: var(--ifm-pre-background); + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: 6px; + padding: 12px; + max-height: 260px; + overflow-y: auto; + font-family: var(--ifm-font-family-monospace); + font-size: 0.78rem; + line-height: 1.6; +} + +.logPlaceholder { + color: var(--ifm-font-color-secondary); + font-style: italic; + text-align: center; + padding: 24px 0; +} + +.logLine { + display: flex; + gap: 8px; +} + +.logTime { + color: var(--ifm-font-color-secondary); + flex-shrink: 0; + min-width: 52px; +} + +.logMsg { + word-break: break-word; +} + +.logLine_info .logMsg { + color: var(--ifm-font-color-base); +} + +.logLine_success .logMsg { + color: var(--ifm-color-success-darkest, #2e7d32); +} + +.logLine_error .logMsg { + color: var(--ifm-color-danger); +} + +.logLine_warn .logMsg { + color: var(--ifm-color-warning-darkest, #e65100); +} + +/* ── Result banner ──────────────────────────────────────────────────────── */ + +.resultSuccess { + margin-top: 10px; + padding: 10px 14px; + background: var(--ifm-color-success-contrast-background, rgba(46, 125, 50, 0.08)); + border: 1px solid var(--ifm-color-success); + border-radius: 6px; + font-size: 0.85rem; + font-weight: 600; + color: var(--ifm-color-success-darkest, #2e7d32); +} + +/* ── Steps (clickable) ──────────────────────────────────────────────────── */ + +.stepsContainer { + display: flex; + flex-direction: column; + gap: 4px; +} + +.step { + display: flex; + gap: 10px; + align-items: flex-start; + padding: 8px 12px; + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: 6px; + background: var(--ifm-background-surface-color); + cursor: pointer; + transition: border-color 0.2s, background 0.2s, box-shadow 0.2s; + text-align: left; + width: 100%; + font-family: inherit; + color: inherit; +} + +.step:hover { + border-color: var(--ifm-color-emphasis-400); + background: var(--ifm-color-emphasis-100); +} + +.stepActive { + border-color: var(--ifm-color-primary); + background: var(--ifm-color-primary-lightest, rgba(55, 125, 255, 0.06)); + box-shadow: 0 0 0 1px var(--ifm-color-primary); +} + +.stepActive:hover { + border-color: var(--ifm-color-primary); + background: var(--ifm-color-primary-lightest, rgba(55, 125, 255, 0.06)); +} + +.stepNumber { + flex-shrink: 0; + width: 24px; + height: 24px; + border-radius: 50%; + background: var(--ifm-color-emphasis-300); + color: #fff; + font-size: 0.75rem; + font-weight: 700; + display: flex; + align-items: center; + justify-content: center; + margin-top: 1px; + transition: background 0.2s; +} + +.stepNumberActive { + background: var(--ifm-color-primary); +} + +.stepContent { + flex: 1; + min-width: 0; +} + +.stepTitle { + font-size: 0.83rem; + font-weight: 600; + line-height: 1.3; +} + +.stepDesc { + font-size: 0.78rem; + color: var(--ifm-font-color-secondary); + line-height: 1.4; + margin-top: 4px; +} + +/* ── Code step label ────────────────────────────────────────────────────── */ + +.codeStepLabel { + color: var(--ifm-color-primary); + font-weight: 700; +} diff --git a/src/components/index.js b/src/components/index.js index 07b4ad9ef6..9c82476efc 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -5,6 +5,7 @@ export { SdkLogos } from './elements/SdkLogos'; export { SdkLogosAsBlocks } from './elements/SdkLogosAsBlocks'; export { default as PhotoCarousel } from './elements/PhotoCarousel'; export { default as SdkTabs } from './elements/SdkTabs'; +export { default as ServerlessWorkerDemo } from './elements/ServerlessWorkerDemo'; // Formatting components export { default as DocsTable, NewDocsCell, DocsTableRow } from './formatting/DocsTable'; diff --git a/vercel.json b/vercel.json index e619ec5eb1..b8abfc2585 100644 --- a/vercel.json +++ b/vercel.json @@ -5,6 +5,11 @@ "silent": true }, "redirects": [ + { + "source": "/evaluate/serverless-workers-demo", + "destination": "/evaluate/serverless-workers/demo", + "permanent": true + }, { "source": "/cloud/introduction", "destination": "/cloud/overview", From 60b24b9721d66a9770613ed904c9b25cadfeee7e Mon Sep 17 00:00:00 2001 From: Lenny Chen <55669665+lennessyy@users.noreply.github.com> Date: Fri, 17 Apr 2026 13:31:24 -0700 Subject: [PATCH 04/62] docs: Serverless Workers - Encyclopedia (4/4) (#4415) * docs: add Serverless Workers encyclopedia page and update related pages Add the encyclopedia entry for Serverless Workers, update workers.mdx and task-queues.mdx with serverless references, add the architecture diagram, update sidebar, and add "Serverless Worker" to Vale terms. Change onBrokenLinks/onBrokenAnchors to 'warn' to accommodate cross-references to pages in other PRs in this series. Co-Authored-By: Claude Opus 4.6 (1M context) * Remove differences section from encyclopedia page The comparison table lives on the evaluate page now. Co-Authored-By: Claude Opus 4.6 (1M context) * Fix Worker invocation wording in encyclopedia Co-Authored-By: Claude Opus 4.6 (1M context) * docs: address review feedback on encyclopedia page - Use "traditional long-lived Worker" on first contrast, "long-lived Worker" thereafter (akhayam, smuneebahmad) - Replace "triggers the compute environment" with "invokes the Serverless Worker on demand" (akhayam) - Use "shuts down" instead of "exits" to match AWS Lambda runtime terminology (akhayam) - Fix "serverless function" -> "Serverless Worker" for cross-provider accuracy - Use "invocation deadline" for consistency with other pages - Add Worker lifecycle section with new lifecycle diagram (addresses akhayam's suggestion to mirror AWS's Lambda lifecycle diagram) - Explain Worker stop timeout and shutdown deadline buffer, including tuning guidance for long-running Activities and the consequences of raising one knob without the other Co-Authored-By: Claude Opus 4.7 (1M context) * docs: crop lifecycle diagram Co-Authored-By: Claude Opus 4.7 (1M context) * docs: add light/dark themed diagrams with figure captions Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- .../workers/serverless-workers.mdx | 140 ++++++++++++++++++ docs/encyclopedia/workers/task-queues.mdx | 2 +- docs/encyclopedia/workers/workers.mdx | 2 +- sidebars.js | 1 + .../diagrams/serverless-worker-flow-dark.svg | 1 + static/diagrams/serverless-worker-flow.svg | 1 + .../serverless-worker-lifecycle-dark.svg | 1 + .../diagrams/serverless-worker-lifecycle.svg | 1 + vale/styles/Temporal/terms.yml | 2 + 9 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 docs/encyclopedia/workers/serverless-workers.mdx create mode 100644 static/diagrams/serverless-worker-flow-dark.svg create mode 100644 static/diagrams/serverless-worker-flow.svg create mode 100644 static/diagrams/serverless-worker-lifecycle-dark.svg create mode 100644 static/diagrams/serverless-worker-lifecycle.svg diff --git a/docs/encyclopedia/workers/serverless-workers.mdx b/docs/encyclopedia/workers/serverless-workers.mdx new file mode 100644 index 0000000000..d0c7a24933 --- /dev/null +++ b/docs/encyclopedia/workers/serverless-workers.mdx @@ -0,0 +1,140 @@ +--- +id: serverless-workers +title: Serverless Workers +sidebar_label: Serverless Workers +description: + Learn how Serverless Workers work, how Temporal invokes them, and how they differ from traditional long-lived Workers. +slug: /serverless-workers +toc_max_heading_level: 4 +keywords: + - serverless + - workers + - lambda + - compute provider +tags: + - Workers + - Concepts + - Serverless +--- + +import ThemedImage from '@theme/ThemedImage'; + +This page covers the following: + +- [What is a Serverless Worker?](#serverless-worker) +- [How Serverless invocation works](#how-invocation-works) +- [Worker lifecycle](#worker-lifecycle) +- [Compute providers](#compute-providers) + +## What is a Serverless Worker? {#serverless-worker} + +A Serverless Worker is a Temporal Worker that runs on serverless compute instead of a long-lived process. There is no +always-on infrastructure to provision or scale. Temporal invokes the Worker when Tasks arrive on a Task Queue, and the +Worker shuts down when the work is done. + +A Serverless Worker uses the same Temporal SDKs as a traditional long-lived Worker. It registers Workflows and +Activities the same way. The difference is in the lifecycle: instead of the Worker starting and polling continuously, +Temporal invokes the Serverless Worker on demand, the Worker starts, processes available Tasks, and then shuts down. + +Serverless Workers require [Worker Versioning](/worker-versioning). Each Serverless Worker must be associated with a +[Worker Deployment Version](/worker-versioning#deployment-versions) that has a compute provider configured. + +To deploy a Serverless Worker, see +[Deploy a Serverless Worker](/production-deployment/worker-deployments/serverless-workers). + +## How Serverless invocation works {#how-invocation-works} + +With long-lived Workers, you start the Worker process, which connects to Temporal and polls a Task Queue for work. +Temporal does not need to know anything about the Worker's infrastructure. + +With Serverless Workers, Temporal starts the Worker. + +
+ +
Temporal's Worker Controller Instance invokes a Serverless Worker when Tasks arrive on a Task Queue with a compute provider configured.
+
+ +The invocation flow works as follows: + +1. A Task arrives on a Task Queue that has a compute provider configured. +2. Temporal's internal Worker Controller Instance (WCI) service detects that no Worker is polling the Task Queue. +3. Temporal uses the compute provider configuration to invoke the Serverless Worker. For example, calling AWS Lambda's + `InvokeFunction` API. +4. The Serverless Worker starts, creates a Temporal Client, and begins polling the Task Queue. +5. The Worker processes available Tasks until the invocation deadline approaches. +6. The Worker gracefully drains in-progress work and shuts down. + +Each invocation is independent. The Worker creates a fresh client connection on every invocation. There is no connection +reuse or shared state across invocations. + +## Worker lifecycle {#worker-lifecycle} + +A single Serverless Worker invocation has three phases: init, work, and shutdown. + +
+ +
The shutdown deadline buffer controls when the Worker stops polling, and the Worker stop timeout controls how long the Worker waits for in-flight Tasks to finish before shutdown hooks run.
+
+ +During the **init** phase, the Worker initializes and establishes a client connection to Temporal. + +During the **work** phase, the Worker polls the Task Queue and processes Tasks. + +During the **shutdown** phase, the Worker stops polling, waits for in-flight Tasks to finish, and runs any shutdown +hooks (for example, OpenTelemetry telemetry flushes). Shutdown begins before the invocation deadline so the Worker can +exit cleanly before the compute provider forcibly terminates the execution environment. + +### Tuning for long-running Activities + +If your Worker handles long-running Activities, set these three values together: + +- **Worker stop timeout > longest Activity runtime.** Gives in-flight Activities enough time to finish after polling + stops. +- **Shutdown deadline buffer > Worker stop timeout + shutdown hook time.** Ensures the drain and any shutdown hooks + complete before the compute provider terminates the environment. +- **Invocation deadline > longest Activity runtime + shutdown deadline buffer.** Set on the compute provider to give + each invocation enough total runtime. + +For example, if your longest Activity runtime is 5 minutes, and your shutdown hooks take 3 seconds to run, set the +Worker stop timeout to more than 5 minutes, and the shutdown deadline buffer to more than 303 seconds (5 minutes + 3 +seconds). Set your invocation deadline to at least 10 minutes and 3 seconds (5 minutes + 303 seconds). + +The Worker stop timeout controls how long the Worker waits for in-flight Tasks to finish after it stops polling. The +shutdown deadline buffer controls how much time before the invocation deadline the Worker stops polling for Tasks. + +Raising only the shutdown deadline buffer makes the Worker stop polling earlier, but does not give in-flight Tasks any +more time to complete. + +Raising only the Worker stop timeout does not make the Worker stop polling earlier, which means the compute provider +might terminate the Worker before the full stop timeout completes. In-flight Activities then do not get the full stop +timeout to finish, and the shutdown hooks may not run. + +## Compute providers {#compute-providers} + +A compute provider is the configuration that tells Temporal how to invoke a Serverless Worker. The compute provider is +set on a [Worker Deployment Version](/worker-versioning#deployment-versions) and specifies the provider type, the +invocation target, and the credentials Temporal needs to trigger the invocation. + +For example, an AWS Lambda compute provider includes the Lambda function ARN and the IAM role that Temporal assumes to +invoke the function. + +Compute providers are only needed for Serverless Workers. Traditional long-lived Workers do not require a compute +provider because the Worker process manages its own lifecycle. + +### Supported providers + +| Provider | Description | +| ---------- | ----------------------------------------------------------------------------- | +| AWS Lambda | Temporal assumes an IAM role in your AWS account to invoke a Lambda function. | diff --git a/docs/encyclopedia/workers/task-queues.mdx b/docs/encyclopedia/workers/task-queues.mdx index ce8d564802..67cdec4863 100644 --- a/docs/encyclopedia/workers/task-queues.mdx +++ b/docs/encyclopedia/workers/task-queues.mdx @@ -94,7 +94,7 @@ There are five places where the name of the Task Queue can be set by the develop - [How to run a development Worker using the Python SDK](/develop/python/workers/run-worker-process#run-a-dev-worker) - [How to run a development Worker using the TypeScript SDK](/develop/typescript/workers/run-worker-process#run-a-dev-worker) - [How to run a development Worker using the .NET SDK](/develop/dotnet/workers/run-worker-process)

- - [How to run a Temporal Cloud Worker using the Go SDK](/develop/go/workers/cloud-worker) + - [How to connect a Go SDK Worker to Temporal Cloud](/develop/go/workers/run-worker-process#connect-to-temporal-cloud) - [How to run a Temporal Cloud Worker using the TypeScript SDK](/develop/typescript/workers/run-worker-process#run-a-temporal-cloud-worker) Note that all Worker Entities listening to the same Task Queue name must be registered to handle the exact same Workflows Types, Activity Types, and Nexus Operations. diff --git a/docs/encyclopedia/workers/workers.mdx b/docs/encyclopedia/workers/workers.mdx index c152971628..03728f07f4 100644 --- a/docs/encyclopedia/workers/workers.mdx +++ b/docs/encyclopedia/workers/workers.mdx @@ -41,7 +41,7 @@ A Worker Program is the static code that defines the constraints of the Worker P - [How to run a development Worker using the TypeScript SDK](/develop/typescript/workers/run-worker-process#run-a-dev-worker) - [How to run a development Worker using the .NET SDK](/develop/dotnet/workers/run-worker-process) -- [How to run a Temporal Cloud Worker using the Go SDK](/develop/go/workers/cloud-worker) +- [How to connect a Go SDK Worker to Temporal Cloud](/develop/go/workers/run-worker-process#connect-to-temporal-cloud) - [How to run a Temporal Cloud Worker using the TypeScript SDK](/develop/typescript/workers/run-worker-process#run-a-temporal-cloud-worker) ::: diff --git a/sidebars.js b/sidebars.js index dbcb56f511..995dd27f9a 100644 --- a/sidebars.js +++ b/sidebars.js @@ -1396,6 +1396,7 @@ module.exports = { 'encyclopedia/workers/sticky-execution', 'encyclopedia/workers/worker-shutdown', 'encyclopedia/workers/worker-versioning', + 'encyclopedia/workers/serverless-workers', ], }, { diff --git a/static/diagrams/serverless-worker-flow-dark.svg b/static/diagrams/serverless-worker-flow-dark.svg new file mode 100644 index 0000000000..a13c90f1e8 --- /dev/null +++ b/static/diagrams/serverless-worker-flow-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/diagrams/serverless-worker-flow.svg b/static/diagrams/serverless-worker-flow.svg new file mode 100644 index 0000000000..aeea36b1f4 --- /dev/null +++ b/static/diagrams/serverless-worker-flow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/diagrams/serverless-worker-lifecycle-dark.svg b/static/diagrams/serverless-worker-lifecycle-dark.svg new file mode 100644 index 0000000000..07718b6ec3 --- /dev/null +++ b/static/diagrams/serverless-worker-lifecycle-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/diagrams/serverless-worker-lifecycle.svg b/static/diagrams/serverless-worker-lifecycle.svg new file mode 100644 index 0000000000..6587b0f5d2 --- /dev/null +++ b/static/diagrams/serverless-worker-lifecycle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/vale/styles/Temporal/terms.yml b/vale/styles/Temporal/terms.yml index 0504678fd2..ecf3921314 100644 --- a/vale/styles/Temporal/terms.yml +++ b/vale/styles/Temporal/terms.yml @@ -102,6 +102,8 @@ swap: temporal sdks: Temporal SDKs temporal server: Temporal Server '\bworker\b': Worker + serverless worker: Serverless Worker + serverless workers: Serverless Workers worker controller: Worker Controller '\bworkflow\b': Workflow timer: Timer From 15a4c680c6dccaa88800e6b32e9d5b4706c8590e Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Fri, 17 Apr 2026 15:49:13 -0700 Subject: [PATCH 05/62] docs: update deploy guide with UI steps and real CLI flags Co-Authored-By: Claude Opus 4.7 (1M context) --- .../serverless-workers/aws-lambda.mdx | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 49d6d65d50..eafd4d8457 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -299,27 +299,40 @@ You can create the version using the Temporal UI, the Temporal CLI, or programma Use the UI for one-off setup and exploration. -When you create a version through the UI, the version is automatically set as current. - - +1. In the Temporal UI, open your Namespace. +2. In the left pane, select **Workers**. +3. Click **Create Worker Deployment** in the upper right corner. +4. Under **Configuration**, enter a **Name** and **Build ID**. These must match the `DeploymentName` and `BuildID` in your Worker code. +5. Under **Compute**, select **AWS Lambda** and provide: + - **Lambda ARN**: the ARN of your Lambda function. + - **IAM Role ARN**: the role ARN from [Step 3](#configure-iam) (output of the CloudFormation stack). + - **External ID**: the same value you passed to the CloudFormation template. +6. Click **Save**. + +When you create a version through the UI, the version is automatically set as current. Skip to [Verify the deployment](#verify-the-deployment). ### Temporal CLI Use the CLI for manual setup, shell scripts, and CI/CD pipelines. When you create a version through the CLI, you must [set the version as current](#set-current-version) as a separate step. - - ```bash temporal worker deployment create-version \ --namespace \ --deployment-name my-app \ --build-id build-1 \ - --aws-lambda-invoke arn:aws:lambda:::function:my-temporal-worker + --aws-lambda-function-arn arn:aws:lambda:::function:my-temporal-worker \ + --aws-lambda-assume-role-arn arn:aws:iam:::role/ \ + --aws-lambda-assume-role-external-id ``` +| Flag | Description | +|---|---| +| `--deployment-name` | Worker Deployment name. Must match `DeploymentName` in your Worker code. | +| `--build-id` | Worker Deployment Version build ID. Must match `BuildID` in your Worker code. | +| `--aws-lambda-function-arn` | ARN of the Lambda function Temporal invokes for this version. | +| `--aws-lambda-assume-role-arn` | IAM role Temporal assumes to invoke the function. This is the `RoleARN` output from the CloudFormation stack in [Step 3](#configure-iam). | +| `--aws-lambda-assume-role-external-id` | External ID configured in the IAM role trust policy. | + ### SDK Use the SDK when the deployment registration is part of your application, for example a setup program that provisions infrastructure and registers the version together, or when you need to compute values dynamically. When you create a version through the SDK, you must [set the version as current](#set-current-version) as a separate step. From 6a582f9bb7c3fd79cc23c829fe67a37704b3ab84 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Fri, 17 Apr 2026 15:51:58 -0700 Subject: [PATCH 06/62] docs: update lifecycle dark diagram with lighter borders Co-Authored-By: Claude Opus 4.7 (1M context) --- static/diagrams/serverless-worker-lifecycle-dark.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/diagrams/serverless-worker-lifecycle-dark.svg b/static/diagrams/serverless-worker-lifecycle-dark.svg index 07718b6ec3..4ed19ca017 100644 --- a/static/diagrams/serverless-worker-lifecycle-dark.svg +++ b/static/diagrams/serverless-worker-lifecycle-dark.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From 39f68525549afa6bfa117be9d14ae102642607a9 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Fri, 17 Apr 2026 15:55:59 -0700 Subject: [PATCH 07/62] docs: tabify deploy approaches and drop UI positioning sentence Co-Authored-By: Claude Opus 4.7 (1M context) --- .../serverless-workers/aws-lambda.mdx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index eafd4d8457..ffd865b4c2 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -19,6 +19,8 @@ tags: --- import SdkTabs from '@site/src/components/elements/SdkTabs'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; This guide walks through deploying a Temporal Worker on AWS Lambda. @@ -295,9 +297,8 @@ The deployment name and build ID must match the values in your Worker code. You can create the version using the Temporal UI, the Temporal CLI, or programmatically with an SDK. -### Temporal UI - -Use the UI for one-off setup and exploration. + + 1. In the Temporal UI, open your Namespace. 2. In the left pane, select **Workers**. @@ -311,7 +312,8 @@ Use the UI for one-off setup and exploration. When you create a version through the UI, the version is automatically set as current. Skip to [Verify the deployment](#verify-the-deployment). -### Temporal CLI + + Use the CLI for manual setup, shell scripts, and CI/CD pipelines. When you create a version through the CLI, you must [set the version as current](#set-current-version) as a separate step. @@ -333,7 +335,8 @@ temporal worker deployment create-version \ | `--aws-lambda-assume-role-arn` | IAM role Temporal assumes to invoke the function. This is the `RoleARN` output from the CloudFormation stack in [Step 3](#configure-iam). | | `--aws-lambda-assume-role-external-id` | External ID configured in the IAM role trust policy. | -### SDK + + Use the SDK when the deployment registration is part of your application, for example a setup program that provisions infrastructure and registers the version together, or when you need to compute values dynamically. When you create a version through the SDK, you must [set the version as current](#set-current-version) as a separate step. @@ -370,6 +373,9 @@ client.CreateWorkerDeploymentVersion(ctx, &workflowservice.CreateWorkerDeploymen + + + ## 5. Set the version as current {#set-current-version} If you created the version through the Temporal UI, the version is already current and you can skip this step. From c0cd65b2de47405d45000d3ce8afa646d4d97c64 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Fri, 17 Apr 2026 16:17:24 -0700 Subject: [PATCH 08/62] docs: restructure deploy step with command-first layout and unified param table Co-Authored-By: Claude Opus 4.7 (1M context) --- .../serverless-workers/aws-lambda.mdx | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index ffd865b4c2..5e7ad11c49 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -85,9 +85,7 @@ For details on configuration options, Lambda-tuned defaults, and the invocation ## 2. Deploy the Lambda function {#deploy-the-lambda-function} -Your Lambda function needs an [execution role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html) that grants it permission to run. -If you don't already have one, create a role with `lambda.amazonaws.com` as the trusted principal before proceeding. -This role is separate from the IAM role that Temporal uses to invoke the function. +Build your Worker for the Lambda runtime, package it as a zip, and deploy it to AWS Lambda. ### i. Build and package {#build-and-package} @@ -111,36 +109,39 @@ zip function.zip bootstrap ### ii. Deploy the Lambda function {#deploy-lambda-function} -Configure the Temporal connection using Lambda environment variables. -The `lambdaworker` package reads these automatically at startup. - -| Variable | Description | Required | -|---|---|---| -| `TEMPORAL_ADDRESS` | Temporal frontend address (e.g., `..tmprl.cloud:7233`). | Yes | -| `TEMPORAL_NAMESPACE` | Temporal Namespace. | Yes | -| `HOME` | Must be set to `/tmp` so the SDK's config loader can resolve a user config directory in the Lambda environment. | Yes | -| `TEMPORAL_TASK_QUEUE` | Task Queue name. Overrides the value set in code. | No | -| `TEMPORAL_TLS_CLIENT_CERT_PATH` | Path to the TLS client certificate file for mTLS authentication. | For mTLS | -| `TEMPORAL_TLS_CLIENT_KEY_PATH` | Path to the TLS client key file for mTLS authentication. | For mTLS | -| `TEMPORAL_API_KEY` | API key for API key authentication. | For API key auth | - -For the full list of supported environment variables, see [Client environment configuration](/references/client-environment-configuration). - -Sensitive values like TLS keys and API keys should be encrypted at rest. See [AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars-encryption.html) for options. - ```bash aws lambda create-function \ --function-name my-temporal-worker \ --runtime provided.al2023 \ --handler bootstrap \ - --architectures x86_64 \ --role arn:aws:iam:::role/my-temporal-worker-execution \ --zip-file fileb://function.zip \ - --timeout 60 \ + --timeout 600 \ --memory-size 256 \ --environment "Variables={HOME=/tmp,TEMPORAL_ADDRESS=:7233,TEMPORAL_NAMESPACE=,TEMPORAL_API_KEY=}" ``` +| Parameter | Description | +|---|---| +| `--function-name` | Name of the Lambda function. | +| `--runtime` | Lambda runtime. Use `provided.al2023` for custom Go binaries. | +| `--handler` | Entry point binary name. Must be `bootstrap` when using the `provided.al2023` custom runtime. | +| `--role` | ARN of the Lambda [execution role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html), which grants the function permission to run. Trusted principal must be `lambda.amazonaws.com`. This is separate from the role Temporal uses to invoke the function in [Step 3](#configure-iam). | +| `--zip-file` | Path to your packaged deployment zip. | +| `--timeout` | Invocation deadline in seconds. This is the maximum time each Lambda invocation can run before AWS terminates it. Set this high enough for the Worker to start, process Tasks, and [shut down gracefully](/serverless-workers#worker-lifecycle). | +| `--memory-size` | Memory in MB allocated to each invocation. | +| `HOME` | Must be `/tmp`. | +| `TEMPORAL_ADDRESS` | Temporal frontend address (e.g., `..tmprl.cloud:7233`). | +| `TEMPORAL_NAMESPACE` | Temporal Namespace. | +| `TEMPORAL_TASK_QUEUE` | Task Queue name. Overrides the value set in code. | +| `TEMPORAL_TLS_CLIENT_CERT_PATH` | Path to the TLS client certificate file for mTLS authentication. | +| `TEMPORAL_TLS_CLIENT_KEY_PATH` | Path to the TLS client key file for mTLS authentication. | +| `TEMPORAL_API_KEY` | API key for API key authentication. | + +The `lambdaworker` package reads environment variables automatically at startup. For the full list, see [Client environment configuration](/references/client-environment-configuration). + +Sensitive values like TLS keys and API keys should be encrypted at rest. See [AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars-encryption.html) for options. + To update an existing function with new code: ```bash From 58dab1cfece06975741ed07c8fcbdfb81eefd2e8 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Fri, 17 Apr 2026 16:20:30 -0700 Subject: [PATCH 09/62] docs: add ADOT layer reminder and long-running activity tuning link to Go SDK page Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/develop/go/workers/serverless-workers/aws-lambda.mdx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx index beaebd6e07..45cea73bd5 100644 --- a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx @@ -96,6 +96,9 @@ Eager Activities require a persistent connection, which Lambda invocations don't It controls how much time before the Lambda deadline the Worker begins its graceful shutdown. The default is `WorkerStopTimeout` + 2 seconds. +If your Worker handles long-running Activities, increase `WorkerStopTimeout`, `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 `lambdaworker/otel` sub-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. @@ -137,4 +140,7 @@ func main() { `ApplyDefaults` configures both metrics and tracing. By default, telemetry is sent to `localhost:4317`, which is the ADOT Lambda layer's default collector endpoint. +To collect this telemetry, attach the [AWS Distro for OpenTelemetry Lambda layer](https://aws-otel.github.io/docs/getting-started/lambda/lambda-go) to your Lambda function. +The layer runs a collector sidecar that receives telemetry on `localhost:4317` and forwards it to your configured backend (e.g., AWS X-Ray, Amazon CloudWatch). + If you only need metrics or tracing, use `otel.ApplyMetrics` or `otel.ApplyTracing` individually. From 6a2e2645238d6c2c4c5fa43ee55251bc54344263 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Tue, 21 Apr 2026 10:27:49 -0700 Subject: [PATCH 10/62] docs: add TLS customization example and execution role policy requirement Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/develop/go/workers/serverless-workers/aws-lambda.mdx | 8 ++++++++ .../worker-deployments/serverless-workers/aws-lambda.mdx | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx index 45cea73bd5..3c2f9ed489 100644 --- a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx @@ -67,6 +67,14 @@ 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. +To customize the TLS configuration, set `opts.ClientOptions.ConnectionOptions.TLS` in the options callback: + +```go +opts.ClientOptions.ConnectionOptions.TLS = &tls.Config{ + // Custom TLS settings, e.g., RootCAs for a private CA +} +``` + 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} diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 5e7ad11c49..ea4f8e54bb 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -126,7 +126,7 @@ aws lambda create-function \ | `--function-name` | Name of the Lambda function. | | `--runtime` | Lambda runtime. Use `provided.al2023` for custom Go binaries. | | `--handler` | Entry point binary name. Must be `bootstrap` when using the `provided.al2023` custom runtime. | -| `--role` | ARN of the Lambda [execution role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html), which grants the function permission to run. Trusted principal must be `lambda.amazonaws.com`. This is separate from the role Temporal uses to invoke the function in [Step 3](#configure-iam). | +| `--role` | ARN of the Lambda [execution role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html), which grants the function permission to run. Trusted principal must be `lambda.amazonaws.com`. This is separate from the role Temporal uses to invoke the function in [Step 3](#configure-iam). The role must have at least the [`AWSLambdaBasicExecutionRole`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaBasicExecutionRole.html) managed policy attached, which grants permission to write CloudWatch Logs. | | `--zip-file` | Path to your packaged deployment zip. | | `--timeout` | Invocation deadline in seconds. This is the maximum time each Lambda invocation can run before AWS terminates it. Set this high enough for the Worker to start, process Tasks, and [shut down gracefully](/serverless-workers#worker-lifecycle). | | `--memory-size` | Memory in MB allocated to each invocation. | From 80ce53e048c1af507cdbe33107b9bc9fe0187baa Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Tue, 21 Apr 2026 10:29:20 -0700 Subject: [PATCH 11/62] docs: simplify execution role policy wording Co-Authored-By: Claude Opus 4.7 (1M context) --- .../worker-deployments/serverless-workers/aws-lambda.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index ea4f8e54bb..1f0ff5e44b 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -126,7 +126,7 @@ aws lambda create-function \ | `--function-name` | Name of the Lambda function. | | `--runtime` | Lambda runtime. Use `provided.al2023` for custom Go binaries. | | `--handler` | Entry point binary name. Must be `bootstrap` when using the `provided.al2023` custom runtime. | -| `--role` | ARN of the Lambda [execution role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html), which grants the function permission to run. Trusted principal must be `lambda.amazonaws.com`. This is separate from the role Temporal uses to invoke the function in [Step 3](#configure-iam). The role must have at least the [`AWSLambdaBasicExecutionRole`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaBasicExecutionRole.html) managed policy attached, which grants permission to write CloudWatch Logs. | +| `--role` | ARN of the Lambda [execution role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html), which grants the function permission to run. Trusted principal must be `lambda.amazonaws.com`. This is separate from the role Temporal uses to invoke the function in [Step 3](#configure-iam). The role must have at least the [`AWSLambdaBasicExecutionRole`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaBasicExecutionRole.html) managed policy attached. | | `--zip-file` | Path to your packaged deployment zip. | | `--timeout` | Invocation deadline in seconds. This is the maximum time each Lambda invocation can run before AWS terminates it. Set this high enough for the Worker to start, process Tasks, and [shut down gracefully](/serverless-workers#worker-lifecycle). | | `--memory-size` | Memory in MB allocated to each invocation. | From d9b45b58e4670eb9ccc78c5b131f944c94745660 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Tue, 21 Apr 2026 10:29:51 -0700 Subject: [PATCH 12/62] docs: inline TLS config in main worker code sample Co-Authored-By: Claude Opus 4.7 (1M context) --- .../go/workers/serverless-workers/aws-lambda.mdx | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx index 3c2f9ed489..54658a0870 100644 --- a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx @@ -35,6 +35,8 @@ Pass a `WorkerDeploymentVersion` and a callback that registers your Workflows an package main import ( + "crypto/tls" + lambdaworker "go.temporal.io/sdk/contrib/aws/lambdaworker" "go.temporal.io/sdk/worker" "go.temporal.io/sdk/workflow" @@ -46,6 +48,7 @@ func main() { BuildID: "build-1", }, func(opts *lambdaworker.Options) error { opts.TaskQueue = "my-task-queue" + opts.ClientOptions.ConnectionOptions.TLS = &tls.Config{} opts.RegisterWorkflowWithOptions(MyWorkflow, workflow.RegisterOptions{ VersioningBehavior: workflow.VersioningBehaviorAutoUpgrade, @@ -67,14 +70,6 @@ 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. -To customize the TLS configuration, set `opts.ClientOptions.ConnectionOptions.TLS` in the options callback: - -```go -opts.ClientOptions.ConnectionOptions.TLS = &tls.Config{ - // Custom TLS settings, e.g., RootCAs for a private CA -} -``` - 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} From e85c1cd146f76c4a6b8090093d12a467d8a955e5 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Tue, 21 Apr 2026 13:33:20 -0700 Subject: [PATCH 13/62] docs: add TLS line --- docs/develop/go/workers/serverless-workers/aws-lambda.mdx | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx index 54658a0870..45cea73bd5 100644 --- a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx @@ -35,8 +35,6 @@ Pass a `WorkerDeploymentVersion` and a callback that registers your Workflows an package main import ( - "crypto/tls" - lambdaworker "go.temporal.io/sdk/contrib/aws/lambdaworker" "go.temporal.io/sdk/worker" "go.temporal.io/sdk/workflow" @@ -48,7 +46,6 @@ func main() { BuildID: "build-1", }, func(opts *lambdaworker.Options) error { opts.TaskQueue = "my-task-queue" - opts.ClientOptions.ConnectionOptions.TLS = &tls.Config{} opts.RegisterWorkflowWithOptions(MyWorkflow, workflow.RegisterOptions{ VersioningBehavior: workflow.VersioningBehaviorAutoUpgrade, From d16544ae7db7301cd7c6bdd04665b99cc463a651 Mon Sep 17 00:00:00 2001 From: Brandon Chavis Date: Tue, 21 Apr 2026 18:01:17 -0400 Subject: [PATCH 14/62] docs: Serverless Worker Autoscaling encyclopedia page (5/4) (#4460) * docs: add Serverless Worker Autoscaling encyclopedia page Add a dedicated page explaining how Temporal autoscales Serverless Workers on AWS Lambda, covering scaling signals (backlog + sync match rate), the push-based scaling flow, failure handling, and key constraints. Also adds an Autoscaling section to the existing Serverless Workers encyclopedia page linking to the new page, and a sidebar entry. Co-Authored-By: Claude Opus 4.6 (1M context) * merge autoscaling info with existing docs * copyedits * copyedits --------- Co-authored-by: Claude Opus 4.6 (1M context) Co-authored-by: Lenny Chen --- .../workers/serverless-workers.mdx | 97 +++++++++++++++++-- 1 file changed, 88 insertions(+), 9 deletions(-) diff --git a/docs/encyclopedia/workers/serverless-workers.mdx b/docs/encyclopedia/workers/serverless-workers.mdx index d0c7a24933..27af3942a9 100644 --- a/docs/encyclopedia/workers/serverless-workers.mdx +++ b/docs/encyclopedia/workers/serverless-workers.mdx @@ -23,7 +23,10 @@ This page covers the following: - [What is a Serverless Worker?](#serverless-worker) - [How Serverless invocation works](#how-invocation-works) +- [Autoscaling](#autoscaling) - [Worker lifecycle](#worker-lifecycle) +- [Failure handling](#failure-handling) +- [Constraints](#constraints) - [Compute providers](#compute-providers) ## What is a Serverless Worker? {#serverless-worker} @@ -57,22 +60,51 @@ With Serverless Workers, Temporal starts the Worker. dark: '/diagrams/serverless-worker-flow-dark.svg', }} /> -
Temporal's Worker Controller Instance invokes a Serverless Worker when Tasks arrive on a Task Queue with a compute provider configured.
+
+ Temporal's Worker Controller Instance invokes a Serverless Worker when Tasks arrive on a Task Queue with a compute + provider configured. +
+Temporal's internal Worker Controller Instance (WCI) decides when to start, scale, and stop compute invocations. + The invocation flow works as follows: -1. A Task arrives on a Task Queue that has a compute provider configured. -2. Temporal's internal Worker Controller Instance (WCI) service detects that no Worker is polling the Task Queue. -3. Temporal uses the compute provider configuration to invoke the Serverless Worker. For example, calling AWS Lambda's - `InvokeFunction` API. -4. The Serverless Worker starts, creates a Temporal Client, and begins polling the Task Queue. -5. The Worker processes available Tasks until the invocation deadline approaches. -6. The Worker gracefully drains in-progress work and shuts down. +1. A Task is submitted (for example, `StartWorkflow` or `ScheduleActivity`). +2. The [Matching Service](/temporal-service/temporal-server#matching-service) attempts to route the Task directly to an + available Worker (a sync match). +3. If a Worker is available, the Task is routed to that Worker. +4. If no Worker is available (sync match fails), the Matching Service pushes a signal to the WCI, and the WCI invokes + the configured compute provider (for example, calling AWS Lambda's `InvokeFunction` API). +5. The Serverless Worker starts, creates a Temporal Client, and begins polling the Task Queue. +6. The Worker processes available Tasks until it exits (see [Worker lifecycle](#worker-lifecycle)). + +The WCI also monitors the Task Queue backlog independently. If tasks arrive faster than Workers can process them, the +WCI invokes additional Workers in parallel until the backlog drains or provider concurrency limits are reached. Each invocation is independent. The Worker creates a fresh client connection on every invocation. There is no connection reuse or shared state across invocations. +## Autoscaling {#autoscaling} + +Temporal automatically scales Serverless Workers based on Task Queue signals. When Tasks arrive and no Worker is +available, Temporal invokes new Workers. When the work is done, Workers exit and scale to zero. + +The WCI uses two signals to decide when to invoke new Workers: + +### Sync match failure {#sync-match-failure} + +When a Task is submitted, the [Matching Service](/temporal-service/temporal-server#matching-service) attempts to route +it directly to an available Worker. If no Worker is available, the sync match fails, and the Matching Service pushes a +signal to the WCI. The WCI then invokes a new Worker. This is the primary scaling path. Because the Matching Service +pushes match failures to the WCI as they happen rather than the WCI polling on a timer, latency stays low and scaling is +responsive. + +### Task Queue backlog {#task-queue-backlog} + +The WCI monitors Task Queue metadata to determine whether pending Tasks exist without enough Workers to process them. If +there is work on the queue and not enough Workers, the WCI invokes additional Workers. + ## Worker lifecycle {#worker-lifecycle} A single Serverless Worker invocation has three phases: init, work, and shutdown. @@ -85,7 +117,10 @@ A single Serverless Worker invocation has three phases: init, work, and shutdown dark: '/diagrams/serverless-worker-lifecycle-dark.svg', }} /> -
The shutdown deadline buffer controls when the Worker stops polling, and the Worker stop timeout controls how long the Worker waits for in-flight Tasks to finish before shutdown hooks run.
+
+ The shutdown deadline buffer controls when the Worker stops polling, and the Worker stop timeout controls how long + the Worker waits for in-flight Tasks to finish before shutdown hooks run. +
During the **init** phase, the Worker initializes and establishes a client connection to Temporal. @@ -121,6 +156,50 @@ Raising only the Worker stop timeout does not make the Worker stop polling earli might terminate the Worker before the full stop timeout completes. In-flight Activities then do not get the full stop timeout to finish, and the shutdown hooks may not run. +## Failure handling {#failure-handling} + +Serverless Workers rely on Temporal's standard retry and timeout semantics to recover from failures. The following +sections describe common failure scenarios and how they are handled. + +### Worker crash {#worker-crash} + +If a Worker invocation crashes (out of memory, unhandled exception, etc.), the behavior follows standard Temporal retry +semantics: + +- The Activity Timeout fires after the configured duration. +- Temporal retries the Activity on a different Worker invocation. +- No manual intervention is required. + +### Provider concurrency limit {#provider-concurrency-limit} + +If the compute provider's concurrency limit is reached (for example, AWS Lambda account concurrency): + +- Further invocations from the WCI fail. +- Tasks remain in the Task Queue backlog. No data loss occurs. +- Processing slows until concurrency frees up. + +### Resource exhaustion across Activity slots {#resource-exhaustion} + +By default, a single Worker invocation may run multiple Activity slots. A crash or resource exhaustion in one Activity +(for example, out-of-memory from a memory-intensive operation) can affect other Activities running in the same +invocation. + +To isolate Activities from each other: + +- Split Workflow and Activity Workers into separate compute functions. +- Set Activity slots to 1 per invocation. + +With single-slot configuration, each Activity gets a dedicated execution environment. + +## Constraints {#constraints} + +| Constraint | Detail | +| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| Activity duration | Must complete within the compute provider's invocation limit (minus shutdown deadline buffer). For AWS Lambda, the maximum is 15 minutes. | +| Workflow duration | No limit. Workflows of any duration work, regardless of the invocation timeout. A Workflow runs across as many invocations 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 declare `AutoUpgrade` or `Pinned` behavior. | + ## Compute providers {#compute-providers} A compute provider is the configuration that tells Temporal how to invoke a Serverless Worker. The compute provider is From 815079b6bdd9f15e6be87b18ccb4c6c045e0c006 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Tue, 21 Apr 2026 15:21:40 -0700 Subject: [PATCH 15/62] remove SDK from creating version --- .../serverless-workers/aws-lambda.mdx | 42 +------------------ 1 file changed, 2 insertions(+), 40 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 1f0ff5e44b..5f7a5212c0 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -296,7 +296,7 @@ Create a [Worker Deployment Version](/production-deployment/worker-deployments/w The compute configuration tells Temporal how to invoke your Worker: the provider type (`aws-lambda`), the Lambda function ARN, and the IAM role to assume. The deployment name and build ID must match the values in your Worker code. -You can create the version using the Temporal UI, the Temporal CLI, or programmatically with an SDK. +You can create the version using the Temporal UI or the Temporal CLI. @@ -336,44 +336,6 @@ temporal worker deployment create-version \ | `--aws-lambda-assume-role-arn` | IAM role Temporal assumes to invoke the function. This is the `RoleARN` output from the CloudFormation stack in [Step 3](#configure-iam). | | `--aws-lambda-assume-role-external-id` | External ID configured in the IAM role trust policy. | - - - -Use the SDK when the deployment registration is part of your application, for example a setup program that provisions infrastructure and registers the version together, or when you need to compute values dynamically. When you create a version through the SDK, you must [set the version as current](#set-current-version) as a separate step. - - - - -```go -// Create the worker deployment -client.CreateWorkerDeployment(ctx, &workflowservice.CreateWorkerDeploymentRequest{ - Namespace: "default", - DeploymentName: "my-app", -}) - -// Create a version with Lambda compute config -client.CreateWorkerDeploymentVersion(ctx, &workflowservice.CreateWorkerDeploymentVersionRequest{ - Namespace: "default", - DeploymentVersion: &deploymentpb.WorkerDeploymentVersion{ - DeploymentName: "my-app", - BuildId: "build-1", - }, - ComputeConfig: &computepb.ComputeConfig{ - ScalingGroups: map[string]*computepb.ComputeConfigScalingGroup{ - "default": { - Provider: &computepb.ComputeProvider{ - Type: "aws-lambda", - Details: /* Lambda ARN, role ARN, external ID */, - }, - }, - }, - }, -}) -``` - - - - @@ -381,7 +343,7 @@ client.CreateWorkerDeploymentVersion(ctx, &workflowservice.CreateWorkerDeploymen If you created the version through the Temporal UI, the version is already current and you can skip this step. -If you used the CLI or SDK, set the version as current. +If you used the CLI, set the version as current. Without this step, tasks on the Task Queue will not route to the version, and Temporal will not invoke the Lambda function. ```bash From bade7245a9401fd4c31af73840df447f1630309c Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Wed, 22 Apr 2026 14:46:08 -0700 Subject: [PATCH 16/62] copyedits --- .../serverless-workers/aws-lambda.mdx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 5f7a5212c0..505e274207 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -22,7 +22,7 @@ import SdkTabs from '@site/src/components/elements/SdkTabs'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -This guide walks through deploying a Temporal Worker on AWS Lambda. +This guide walks through deploying a Temporal [Serverless Worker](/serverless-workers) on AWS Lambda. ## Prerequisites {#prerequisites} @@ -40,7 +40,7 @@ This guide walks through deploying a Temporal Worker on AWS Lambda. -## 1. Write the Worker code {#write-the-worker-code} +## 1. Write Worker code {#write-worker-code} Write a Worker that runs inside a Lambda function. The Worker handles the per-invocation lifecycle: connecting to Temporal, polling for tasks, and gracefully shutting down before the invocation deadline. @@ -83,7 +83,7 @@ For details on configuration options, Lambda-tuned defaults, and the invocation -## 2. Deploy the Lambda function {#deploy-the-lambda-function} +## 2. Deploy Lambda function {#deploy-lambda-function} Build your Worker for the Lambda runtime, package it as a zip, and deploy it to AWS Lambda. @@ -107,7 +107,7 @@ zip function.zip bootstrap -### ii. Deploy the Lambda function {#deploy-lambda-function} +### ii. Deploy Lambda function {#deploy-lambda-function-step} ```bash aws lambda create-function \ @@ -290,7 +290,7 @@ aws cloudformation create-stack \ The stack output `RoleARN` contains the IAM role ARN to use in your Worker Deployment Version's compute configuration. -## 4. Create a Worker Deployment Version {#create-worker-deployment-version} +## 4. Create Worker Deployment Version {#create-worker-deployment-version} Create a [Worker Deployment Version](/production-deployment/worker-deployments/worker-versioning) with a compute provider that points to your Lambda function. The compute configuration tells Temporal how to invoke your Worker: the provider type (`aws-lambda`), the Lambda function ARN, and the IAM role to assume. @@ -339,7 +339,7 @@ temporal worker deployment create-version \ -## 5. Set the version as current {#set-current-version} +## 5. Set version as current {#set-current-version} If you created the version through the Temporal UI, the version is already current and you can skip this step. @@ -352,7 +352,7 @@ temporal worker deployment set-current-version \ --build-id build-1 ``` -## 6. Verify the deployment {#verify-the-deployment} +## 6. Verify deployment {#verify-deployment} Start a Workflow on the same Task Queue to confirm that Temporal invokes your Lambda Worker. From 9cbc085b616ce0fd971f3a4492dd477b4864181c Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Wed, 22 Apr 2026 18:06:01 -0700 Subject: [PATCH 17/62] docs: add describe-stacks command to retrieve role ARN from CloudFormation Co-Authored-By: Claude Opus 4.6 (1M context) --- .../worker-deployments/serverless-workers/aws-lambda.mdx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 505e274207..74b7306851 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -288,7 +288,13 @@ aws cloudformation create-stack \ --region ``` -The stack output `RoleARN` contains the IAM role ARN to use in your Worker Deployment Version's compute configuration. +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 +``` + +Use this role ARN in your Worker Deployment Version's compute configuration. ## 4. Create Worker Deployment Version {#create-worker-deployment-version} From 8a81056273410cf095cc4c048781a209eb5e7d9c Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Thu, 23 Apr 2026 12:28:11 -0700 Subject: [PATCH 18/62] docs: add scaling with long-lived Workers section to serverless encyclopedia Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/encyclopedia/workers/serverless-workers.mdx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/encyclopedia/workers/serverless-workers.mdx b/docs/encyclopedia/workers/serverless-workers.mdx index 27af3942a9..c15602b48d 100644 --- a/docs/encyclopedia/workers/serverless-workers.mdx +++ b/docs/encyclopedia/workers/serverless-workers.mdx @@ -24,6 +24,7 @@ This page covers the following: - [What is a Serverless Worker?](#serverless-worker) - [How Serverless invocation works](#how-invocation-works) - [Autoscaling](#autoscaling) +- [Scaling with long-lived Workers](#scaling-with-long-lived-workers) - [Worker lifecycle](#worker-lifecycle) - [Failure handling](#failure-handling) - [Constraints](#constraints) @@ -105,6 +106,16 @@ responsive. The WCI monitors Task Queue metadata to determine whether pending Tasks exist without enough Workers to process them. If there is work on the queue and not enough Workers, the WCI invokes additional Workers. +## Scaling with long-lived Workers {#scaling-with-long-lived-workers} + +Serverless Workers can share a Task Queue with long-lived Workers. +Because Serverless Workers are only invoked on [sync match failure](#sync-match-failure), Serverless Workers only pick up Tasks that no long-lived Worker was available to handle. +In practice, the Serverless Workers act as spillover capacity for the long-lived fleet. + +If you configure Serverless and long-lived Workers on the same Task Queue, do not enable dynamic scaling on the long-lived Workers. +The two groups cannot coordinate their scaling behavior. +If both scale dynamically, the long-lived Workers may scale up to handle the same Tasks that Temporal is simultaneously invoking Serverless Workers for, leading to unnecessary invocations and unpredictable scaling. + ## Worker lifecycle {#worker-lifecycle} A single Serverless Worker invocation has three phases: init, work, and shutdown. From 694c1d1d7c1638d7515877ea0c6bab3808fff922 Mon Sep 17 00:00:00 2001 From: Lenny Chen <55669665+lennessyy@users.noreply.github.com> Date: Tue, 28 Apr 2026 10:58:37 -0700 Subject: [PATCH 19/62] docs: self-hosted setup for serverless workers (#4476) * docs: add self-hosted setup page for serverless workers Covers enabling the Worker Controller via dynamic config, configuring AWS credentials for the Temporal server, and creating the Lambda invocation role with a CloudFormation template adapted for self-hosted. Co-Authored-By: Claude Opus 4.6 (1M context) * docs: add describe-stacks command to retrieve role ARN Co-Authored-By: Claude Opus 4.6 (1M context) * docs: add WCI verification steps and ARN discovery tip Add how to view WCI workflows using TemporalNamespaceDivision filter to both the self-hosted setup page and the deploy guide. Add aws sts get-caller-identity tip for finding the server's IAM ARN. Co-Authored-By: Claude Opus 4.6 (1M context) * docs: remove WCI filter tip from deploy guide Co-Authored-By: Claude Opus 4.6 (1M context) * docs: mark IAM section as Cloud-only, link to self-hosted setup Co-Authored-By: Claude Opus 4.6 (1M context) * docs: add (Cloud only) to IAM heading Co-Authored-By: Claude Opus 4.6 (1M context) * docs: move Cloud-only callout to top of IAM section Co-Authored-By: Claude Opus 4.6 (1M context) * docs: address PR review feedback on self-hosted setup page - Remove first paragraph (Cloud comparison) - Add brief overview of the three setup steps - Use "Worker Controller Instance (WCI)" instead of "Worker Controller" - Move dynamic config reference table out (belongs on dynamic config page) - Replace verify section with Next steps linking to deploy guide Co-Authored-By: Claude Opus 4.6 (1M context) * prettier * docs: reference self-hosted setup page in deploy guide prerequisites Co-Authored-By: Claude Opus 4.6 (1M context) * Apply suggestions from code review Co-authored-by: Stefan Richter * Apply suggestions from code review Co-authored-by: Stefan Richter * copyedits * copyedits --------- Co-authored-by: Claude Opus 4.6 (1M context) Co-authored-by: Stefan Richter --- .../serverless-workers/aws-lambda.mdx | 155 +++++++------ .../serverless-workers/self-hosted-setup.mdx | 210 ++++++++++++++++++ sidebars.js | 1 + ...al-self-hosted-serverless-worker-role.yaml | 74 ++++++ 4 files changed, 368 insertions(+), 72 deletions(-) create mode 100644 docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx create mode 100644 static/files/temporal-self-hosted-serverless-worker-role.yaml diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 74b7306851..158ca2bf07 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -27,10 +27,12 @@ This guide walks through deploying a Temporal [Serverless Worker](/serverless-wo ## Prerequisites {#prerequisites} - A Temporal Cloud account or a self-hosted Temporal Service vx.xx.x or later. - - Your Temporal Service frontend must be reachable from the Lambda execution environment. For Temporal Cloud, no additional configuration is needed. For self-hosted deployments on a private network, configure the Lambda function with [VPC access](https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc.html) to reach the Temporal frontend. +- For self-hosted deployments, complete the + [self-hosted setup](/production-deployment/worker-deployments/serverless-workers/self-hosted-setup) before following + this guide. - An AWS account with permissions to create and invoke Lambda functions and create IAM roles. -- 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 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. @@ -42,8 +44,8 @@ This guide walks through deploying a Temporal [Serverless Worker](/serverless-wo ## 1. Write Worker code {#write-worker-code} -Write a Worker that runs inside a Lambda function. -The Worker handles the per-invocation lifecycle: connecting to Temporal, polling for tasks, and gracefully shutting down before the invocation deadline. +Write a Worker that runs inside a Lambda function. The Worker handles the per-invocation lifecycle: connecting to +Temporal, polling for tasks, and gracefully shutting down before the invocation deadline. @@ -76,9 +78,11 @@ func main() { } ``` -Each Workflow must declare a [versioning behavior](/worker-versioning#versioning-behaviors) at registration time, either `AutoUpgrade` or `Pinned`. +Each Workflow must declare a [versioning behavior](/worker-versioning#versioning-behaviors) at registration time, either +`AutoUpgrade` or `Pinned`. -For details on configuration options, Lambda-tuned defaults, and the invocation lifecycle, see [Serverless Workers - Go SDK](/develop/go/workers/serverless-workers/aws-lambda). +For details on configuration options, Lambda-tuned defaults, and the invocation lifecycle, see +[Serverless Workers - Go SDK](/develop/go/workers/serverless-workers/aws-lambda). @@ -121,26 +125,28 @@ aws lambda create-function \ --environment "Variables={HOME=/tmp,TEMPORAL_ADDRESS=:7233,TEMPORAL_NAMESPACE=,TEMPORAL_API_KEY=}" ``` -| Parameter | Description | -|---|---| -| `--function-name` | Name of the Lambda function. | -| `--runtime` | Lambda runtime. Use `provided.al2023` for custom Go binaries. | -| `--handler` | Entry point binary name. Must be `bootstrap` when using the `provided.al2023` custom runtime. | -| `--role` | ARN of the Lambda [execution role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html), which grants the function permission to run. Trusted principal must be `lambda.amazonaws.com`. This is separate from the role Temporal uses to invoke the function in [Step 3](#configure-iam). The role must have at least the [`AWSLambdaBasicExecutionRole`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaBasicExecutionRole.html) managed policy attached. | -| `--zip-file` | Path to your packaged deployment zip. | -| `--timeout` | Invocation deadline in seconds. This is the maximum time each Lambda invocation can run before AWS terminates it. Set this high enough for the Worker to start, process Tasks, and [shut down gracefully](/serverless-workers#worker-lifecycle). | -| `--memory-size` | Memory in MB allocated to each invocation. | -| `HOME` | Must be `/tmp`. | -| `TEMPORAL_ADDRESS` | Temporal frontend address (e.g., `..tmprl.cloud:7233`). | -| `TEMPORAL_NAMESPACE` | Temporal Namespace. | -| `TEMPORAL_TASK_QUEUE` | Task Queue name. Overrides the value set in code. | -| `TEMPORAL_TLS_CLIENT_CERT_PATH` | Path to the TLS client certificate file for mTLS authentication. | -| `TEMPORAL_TLS_CLIENT_KEY_PATH` | Path to the TLS client key file for mTLS authentication. | -| `TEMPORAL_API_KEY` | API key for API key authentication. | - -The `lambdaworker` package reads environment variables automatically at startup. For the full list, see [Client environment configuration](/references/client-environment-configuration). - -Sensitive values like TLS keys and API keys should be encrypted at rest. See [AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars-encryption.html) for options. +| Parameter | Description | +| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--function-name` | Name of the Lambda function. | +| `--runtime` | Lambda runtime. Use `provided.al2023` for custom Go binaries. | +| `--handler` | Entry point binary name. Must be `bootstrap` when using the `provided.al2023` custom runtime. | +| `--role` | ARN of the Lambda [execution role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html), which grants the function permission to run. Trusted principal must be `lambda.amazonaws.com`. This is separate from the role Temporal uses to invoke the function in [Step 3](#configure-iam). The role must have at least the [`AWSLambdaBasicExecutionRole`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaBasicExecutionRole.html) managed policy attached. | +| `--zip-file` | Path to your packaged deployment zip. | +| `--timeout` | Invocation deadline in seconds. This is the maximum time each Lambda invocation can run before AWS terminates it. Set this high enough for the Worker to start, process Tasks, and [shut down gracefully](/serverless-workers#worker-lifecycle). | +| `--memory-size` | Memory in MB allocated to each invocation. | +| `HOME` | Must be `/tmp`. | +| `TEMPORAL_ADDRESS` | Temporal frontend address (e.g., `..tmprl.cloud:7233`). | +| `TEMPORAL_NAMESPACE` | Temporal Namespace. | +| `TEMPORAL_TASK_QUEUE` | Task Queue name. Overrides the value set in code. | +| `TEMPORAL_TLS_CLIENT_CERT_PATH` | Path to the TLS client certificate file for mTLS authentication. | +| `TEMPORAL_TLS_CLIENT_KEY_PATH` | Path to the TLS client key file for mTLS authentication. | +| `TEMPORAL_API_KEY` | API key for API key authentication. | + +The `lambdaworker` package reads environment variables automatically at startup. For the full list, see +[Client environment configuration](/references/client-environment-configuration). + +Sensitive values like TLS keys and API keys should be encrypted at rest. See +[AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars-encryption.html) for options. To update an existing function with new code: @@ -150,25 +156,24 @@ aws lambda update-function-code \ --zip-file fileb://function.zip ``` -## 3. Configure IAM for Temporal invocation {#configure-iam} - -Temporal needs permission to invoke your Lambda function. -The Temporal server assumes an IAM role in your AWS account to call `lambda:InvokeFunction`. -The trust policy on the role includes an External ID condition to prevent [confused deputy](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html) attacks. - -Deploy the following CloudFormation template to create the invocation role and its permissions. [Download the template](/files/temporal-cloud-serverless-worker-role.yaml). +## 3. Configure IAM for Temporal invocation (Cloud only) {#configure-iam} -:::note +This section applies to Temporal Cloud. For self-hosted Temporal Service deployments, see +[Self-hosted setup](/production-deployment/worker-deployments/serverless-workers/self-hosted-setup#create-invocation-role) +for IAM configuration with a different CloudFormation template. -This template is scoped to Temporal Cloud. Self-hosted configuration guidance is in progress. +Temporal needs permission to invoke your Lambda function. The Temporal server assumes an IAM role in your AWS account to +call `lambda:InvokeFunction`. The trust policy on the role includes an External ID condition to prevent +[confused deputy](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html) attacks. -::: +Deploy the following CloudFormation template to create the invocation role and its permissions. +[Download the template](/files/temporal-cloud-serverless-worker-role.yaml). -| Parameter | Description | -|---|---| -| `AssumeRoleExternalId` | A unique identifier that Temporal Cloud presents when assuming the role. Provided in your Namespace configuration. | -| `LambdaFunctionARNs` | Comma-separated list of Lambda function ARNs that Temporal may invoke. One role can authorize multiple Worker Lambdas. | -| `RoleName` | Base name for the created IAM role. Defaults to `Temporal-Cloud-Serverless-Worker`. | +| Parameter | Description | +| ---------------------- | ---------------------------------------------------------------------------------------------------------------------- | +| `AssumeRoleExternalId` | A unique identifier that Temporal Cloud presents when assuming the role. Provided in your Namespace configuration. | +| `LambdaFunctionARNs` | Comma-separated list of Lambda function ARNs that Temporal may invoke. One role can authorize multiple Worker Lambdas. | +| `RoleName` | Base name for the created IAM role. Defaults to `Temporal-Cloud-Serverless-Worker`. |
CloudFormation template @@ -176,7 +181,8 @@ This template is scoped to Temporal Cloud. Self-hosted configuration guidance is ```yaml # CloudFormation template for creating an IAM role that Temporal Cloud can assume to invoke Lambda functions. AWSTemplateFormatVersion: '2010-09-09' -Description: Creates an IAM role that Temporal Cloud can assume to invoke multiple Lambda functions for Serverless Workers. +Description: + Creates an IAM role that Temporal Cloud can assume to invoke multiple Lambda functions for Serverless Workers. Parameters: AssumeRoleExternalId: @@ -189,8 +195,8 @@ Parameters: LambdaFunctionARNs: Type: CommaDelimitedList Description: >- - Comma-separated list of Lambda function ARNs to invoke - (e.g., arn:aws:lambda:us-west-2:123456789012:function:worker-1,arn:aws:lambda:us-west-2:123456789012:function:worker-2) + Comma-separated list of Lambda function ARNs to invoke (e.g., + arn:aws:lambda:us-west-2:123456789012:function:worker-1,arn:aws:lambda:us-west-2:123456789012:function:worker-2) RoleName: Type: String @@ -200,21 +206,21 @@ Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: - default: "Temporal Cloud Configuration" + default: 'Temporal Cloud Configuration' Parameters: - AssumeRoleExternalId - Label: - default: "Lambda Configuration" + default: 'Lambda Configuration' Parameters: - LambdaFunctionARNs - RoleName ParameterLabels: AssumeRoleExternalId: - default: "External ID (provided by Temporal Cloud)" + default: 'External ID (provided by Temporal Cloud)' LambdaFunctionARNs: - default: "Lambda Function ARNs (comma-separated list)" + default: 'Lambda Function ARNs (comma-separated list)' RoleName: - default: "IAM Role Name" + default: 'IAM Role Name' Resources: TemporalCloudServerlessWorker: @@ -232,13 +238,13 @@ Resources: 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 + arn:aws:iam::354116250941:role/wci-lambda-invoke, ] Action: sts:AssumeRole Condition: StringEquals: 'sts:ExternalId': [!Ref AssumeRoleExternalId] - Description: "The role Temporal Cloud uses to invoke Lambda functions for Serverless Workers" + Description: 'The role Temporal Cloud uses to invoke Lambda functions for Serverless Workers' MaxSessionDuration: 3600 # 1 hour TemporalCloudLambdaInvokePermissions: @@ -262,7 +268,7 @@ Outputs: Description: The ARN of the IAM role created for Temporal Cloud Value: !GetAtt TemporalCloudServerlessWorker.Arn Export: - Name: !Sub "${AWS::StackName}-RoleARN" + Name: !Sub '${AWS::StackName}-RoleARN' RoleName: Description: The name of the IAM role @@ -270,7 +276,7 @@ Outputs: LambdaFunctionARNs: Description: The Lambda function ARNs that can be invoked - Value: !Join [", ", !Ref LambdaFunctionARNs] + Value: !Join [', ', !Ref LambdaFunctionARNs] ```
@@ -298,9 +304,10 @@ Use this role ARN in your Worker Deployment Version's compute configuration. ## 4. Create Worker Deployment Version {#create-worker-deployment-version} -Create a [Worker Deployment Version](/production-deployment/worker-deployments/worker-versioning) with a compute provider that points to your Lambda function. -The compute configuration tells Temporal how to invoke your Worker: the provider type (`aws-lambda`), the Lambda function ARN, and the IAM role to assume. -The deployment name and build ID must match the values in your Worker code. +Create a [Worker Deployment Version](/production-deployment/worker-deployments/worker-versioning) with a compute +provider that points to your Lambda function. The compute configuration tells Temporal how to invoke your Worker: the +provider type (`aws-lambda`), the Lambda function ARN, and the IAM role to assume. The deployment name and build ID must +match the values in your Worker code. You can create the version using the Temporal UI or the Temporal CLI. @@ -310,19 +317,22 @@ You can create the version using the Temporal UI or the Temporal CLI. 1. In the Temporal UI, open your Namespace. 2. In the left pane, select **Workers**. 3. Click **Create Worker Deployment** in the upper right corner. -4. Under **Configuration**, enter a **Name** and **Build ID**. These must match the `DeploymentName` and `BuildID` in your Worker code. +4. Under **Configuration**, enter a **Name** and **Build ID**. These must match the `DeploymentName` and `BuildID` in + your Worker code. 5. Under **Compute**, select **AWS Lambda** and provide: - **Lambda ARN**: the ARN of your Lambda function. - **IAM Role ARN**: the role ARN from [Step 3](#configure-iam) (output of the CloudFormation stack). - **External ID**: the same value you passed to the CloudFormation template. 6. Click **Save**. -When you create a version through the UI, the version is automatically set as current. Skip to [Verify the deployment](#verify-the-deployment). +When you create a version through the UI, the version is automatically set as current. Skip to +[Verify the deployment](#verify-the-deployment). -Use the CLI for manual setup, shell scripts, and CI/CD pipelines. When you create a version through the CLI, you must [set the version as current](#set-current-version) as a separate step. +Use the CLI for manual setup, shell scripts, and CI/CD pipelines. When you create a version through the CLI, you must +[set the version as current](#set-current-version) as a separate step. ```bash temporal worker deployment create-version \ @@ -334,13 +344,13 @@ temporal worker deployment create-version \ --aws-lambda-assume-role-external-id ``` -| Flag | Description | -|---|---| -| `--deployment-name` | Worker Deployment name. Must match `DeploymentName` in your Worker code. | -| `--build-id` | Worker Deployment Version build ID. Must match `BuildID` in your Worker code. | -| `--aws-lambda-function-arn` | ARN of the Lambda function Temporal invokes for this version. | -| `--aws-lambda-assume-role-arn` | IAM role Temporal assumes to invoke the function. This is the `RoleARN` output from the CloudFormation stack in [Step 3](#configure-iam). | -| `--aws-lambda-assume-role-external-id` | External ID configured in the IAM role trust policy. | +| Flag | Description | +| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| `--deployment-name` | Worker Deployment name. Must match `DeploymentName` in your Worker code. | +| `--build-id` | Worker Deployment Version build ID. Must match `BuildID` in your Worker code. | +| `--aws-lambda-function-arn` | ARN of the Lambda function Temporal invokes for this version. | +| `--aws-lambda-assume-role-arn` | IAM role Temporal assumes to invoke the function. This is the `RoleARN` output from the CloudFormation stack in [Step 3](#configure-iam). | +| `--aws-lambda-assume-role-external-id` | External ID configured in the IAM role trust policy. | @@ -349,8 +359,8 @@ temporal worker deployment create-version \ If you created the version through the Temporal UI, the version is already current and you can skip this step. -If you used the CLI, set the version as current. -Without this step, tasks on the Task Queue will not route to the version, and Temporal will not invoke the Lambda function. +If you used the CLI, set the version as current. Without this step, tasks on the Task Queue will not route to the +version, and Temporal will not invoke the Lambda function. ```bash temporal worker deployment set-current-version \ @@ -369,10 +379,11 @@ temporal workflow start \ --input '"Hello, serverless!"' ``` -When the task lands on the Task Queue with no active pollers, Temporal detects the compute provider configuration and invokes your Lambda function. -The Worker starts, connects to Temporal, picks up the task, and processes it. +When the task lands on the Task Queue with no active pollers, Temporal detects the compute provider configuration and +invokes your Lambda function. The Worker starts, connects to Temporal, picks up the task, and processes it. You can verify the invocation by checking: - **Temporal UI:** The Workflow execution should show task completions in the event history. -- **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. +- **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. diff --git a/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx b/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx new file mode 100644 index 0000000000..39ad4a041a --- /dev/null +++ b/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx @@ -0,0 +1,210 @@ +--- +id: self-hosted-setup +title: Self-hosted setup for Serverless Workers +sidebar_label: Self-hosted setup +description: Configure a self-hosted Temporal Service to use Serverless Workers with AWS Lambda. +slug: /production-deployment/worker-deployments/serverless-workers/self-hosted-setup +toc_max_heading_level: 4 +keywords: + - serverless + - self-hosted + - lambda + - aws + - worker + - deployment +tags: + - Workers + - Deploy + - Serverless + - Self-hosted +--- + +This page covers the prerequisites for running [Serverless Workers](/serverless-workers) on a self-hosted Temporal +Service with AWS Lambda: + +1. Ensure Lambda can reach the Temporal Service. +2. Enable the Worker Controller Instance (WCI) on the server through dynamic configuration. +3. Provide the server with AWS credentials to assume IAM roles. +4. Create an IAM role in your AWS account that grants Temporal permission to invoke Lambda functions. + +Once setup is complete, follow the +[AWS Lambda deployment guide](/production-deployment/worker-deployments/serverless-workers/aws-lambda) to deploy your +Worker. + +## Ensure Lambda can reach the Temporal Service {#ensure-network-reachability} + +The [Temporal Service frontend](/temporal-service#frontend-service) must be reachable from the Lambda execution +environment. How to achieve this depends on your network setup. If the Temporal Service runs on a private network, you +may need [VPC access for Lambda](https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc.html), VPC peering, or a +similar mechanism to allow the Lambda function to connect to the Temporal frontend. + +## Enable the Worker Controller Instance {#enable-worker-controller} + +[WCI](/serverless-workers#how-invocation-works) is the server component that monitors Task Queues and invokes compute +providers. It is disabled by default and must be enabled through +[dynamic configuration](/references/dynamic-configuration). + +Add the following keys to your dynamic config file: + +```yaml +workercontroller.enabled: + - value: true + +workercontroller.compute_providers.enabled: + - value: + - aws-lambda + +workercontroller.scaling_algorithms.enabled: + - value: + - no-sync +``` + +To enable WCI for specific Namespaces instead of globally, add a `constraints` section with the +Namespace name under `workercontroller.enabled`. For example, to enable WCI only for `your-namespace`: + +```yaml +workercontroller.enabled: + - value: true + constraints: + namespace: 'your-namespace' +``` + +The Temporal Service watches the dynamic config file for changes and applies updates without a restart. + +## Configure AWS credentials {#configure-aws-credentials} + +The Temporal Service needs AWS credentials to assume an IAM role that invokes Lambda functions. How you provide +credentials depends on where the Temporal Service runs. + +**On AWS infrastructure (EC2, ECS, EKS):** The server uses the attached instance role, task role, or pod role +automatically. No additional credential configuration is needed. The attached role must have `sts:AssumeRole` permission +for the Lambda invocation role created in the next step. + +**Outside AWS:** Use [IAM Roles Anywhere](https://aws.amazon.com/iam/roles-anywhere/), or configure static AWS +credentials in the server's environment (not recommended): + +``` +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_REGION= +``` + +These credentials must belong to an IAM user or role that has `sts:AssumeRole` permission for the Lambda invocation +role. + +## Create the Lambda invocation role {#create-invocation-role} + +Temporal invokes Lambda functions by assuming an IAM role in your AWS account. This role needs `lambda:GetFunction` and +`lambda:InvokeFunction` permission on your Worker Lambda functions, and a trust policy that allows the Temporal server's +identity to assume it. + +Deploy the following CloudFormation template to create the role. +[Download the template](/files/temporal-self-hosted-serverless-worker-role.yaml). Replace the parameter values in the +command below and run it in your terminal: + +```bash +aws cloudformation create-stack --stack-name temporal-serverless-worker --template-body file://temporal-self-hosted-serverless-worker-role.yaml --parameters ParameterKey=TemporalIamRoleArn,ParameterValue= ParameterKey=AssumeRoleExternalId,ParameterValue= ParameterKey=LambdaFunctionARNs,ParameterValue='""' --capabilities CAPABILITY_NAMED_IAM --region +``` + +| Parameter | Description | +| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `TemporalIamRoleArn` | The ARN of the IAM role or user that the Temporal Service runs as. This is the identity the server uses to call `sts:AssumeRole`. To find the ARN, run `aws sts get-caller-identity` in the server's environment. | +| `AssumeRoleExternalId` | A unique string to prevent [confused deputy](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html) attacks. Choose any value and pass the same value when creating the Worker Deployment Version. | +| `LambdaFunctionARNs` | Comma-separated list of Lambda function ARNs that Temporal may invoke. | +| `RoleName` | Base name for the created IAM role. Defaults to `Temporal-Serverless-Worker`. | + +
+CloudFormation template + +```yaml +AWSTemplateFormatVersion: '2010-09-09' +Description: + Creates an IAM role that a self-hosted Temporal Service can assume to invoke Lambda functions for Serverless Workers. + +Parameters: + TemporalIamRoleArn: + Type: String + Description: The ARN of the IAM role or user that the Temporal Service runs as. + + AssumeRoleExternalId: + Type: String + Description: A unique identifier to prevent confused deputy attacks. + AllowedPattern: '[a-zA-Z0-9_+=,.@-]*' + MinLength: 5 + MaxLength: 45 + + LambdaFunctionARNs: + Type: CommaDelimitedList + Description: >- + Comma-separated list of Lambda function ARNs to invoke (e.g., + arn:aws:lambda:us-west-2:123456789012:function:worker-1,arn:aws:lambda:us-west-2:123456789012:function:worker-2) + + RoleName: + Type: String + Default: 'Temporal-Serverless-Worker' + +Resources: + TemporalServerlessWorker: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub '${RoleName}-${AWS::StackName}' + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + AWS: [!Ref TemporalIamRoleArn] + Action: sts:AssumeRole + Condition: + StringEquals: + 'sts:ExternalId': [!Ref AssumeRoleExternalId] + Description: 'The role the Temporal Service uses to invoke Lambda functions for Serverless Workers' + MaxSessionDuration: 3600 + + TemporalLambdaInvokePermissions: + Type: AWS::IAM::Policy + DependsOn: TemporalServerlessWorker + Properties: + PolicyName: 'Temporal-Lambda-Invoke-Permissions' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - lambda:InvokeFunction + - lambda:GetFunction + Resource: !Ref LambdaFunctionARNs + Roles: + - !Sub '${RoleName}-${AWS::StackName}' + +Outputs: + RoleARN: + Description: The ARN of the IAM role created for the Temporal Service + Value: !GetAtt TemporalServerlessWorker.Arn + Export: + Name: !Sub '${AWS::StackName}-RoleARN' + + RoleName: + Description: The name of the IAM role + Value: !Ref RoleName + + LambdaFunctionARNs: + Description: The Lambda function ARNs that can be invoked + Value: !Join [', ', !Ref LambdaFunctionARNs] +``` + +
+ +After the stack finishes creating, retrieve the IAM role ARN from the stack outputs: + +```bash +aws cloudformation describe-stacks --stack-name temporal-serverless-worker --query 'Stacks[0].Outputs[?OutputKey==`RoleARN`].OutputValue' --output text --region +``` + +Use this role ARN when creating the Worker Deployment Version. + +## Next steps {#next-steps} + +Follow the [AWS Lambda deployment guide](/production-deployment/worker-deployments/serverless-workers/aws-lambda) to +write your Worker code, deploy it to Lambda, and create a Worker Deployment Version with the IAM role from the previous +step. diff --git a/sidebars.js b/sidebars.js index 995dd27f9a..39fdc7a644 100644 --- a/sidebars.js +++ b/sidebars.js @@ -1219,6 +1219,7 @@ module.exports = { }, items: [ 'production-deployment/worker-deployments/serverless-workers/aws-lambda', + 'production-deployment/worker-deployments/serverless-workers/self-hosted-setup', ], }, ], diff --git a/static/files/temporal-self-hosted-serverless-worker-role.yaml b/static/files/temporal-self-hosted-serverless-worker-role.yaml new file mode 100644 index 0000000000..488fa1ad96 --- /dev/null +++ b/static/files/temporal-self-hosted-serverless-worker-role.yaml @@ -0,0 +1,74 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: Creates an IAM role that a self-hosted Temporal Service can assume to invoke Lambda functions for Serverless Workers. + +Parameters: + TemporalIamRoleArn: + Type: String + Description: The ARN of the IAM role or user that the Temporal Service runs as. + + AssumeRoleExternalId: + Type: String + Description: A unique identifier to prevent confused deputy attacks. + AllowedPattern: '[a-zA-Z0-9_+=,.@-]*' + MinLength: 5 + MaxLength: 45 + + LambdaFunctionARNs: + Type: CommaDelimitedList + Description: >- + Comma-separated list of Lambda function ARNs to invoke + (e.g., arn:aws:lambda:us-west-2:123456789012:function:worker-1,arn:aws:lambda:us-west-2:123456789012:function:worker-2) + + RoleName: + Type: String + Default: 'Temporal-Serverless-Worker' + +Resources: + TemporalServerlessWorker: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub '${RoleName}-${AWS::StackName}' + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + AWS: + [!Ref TemporalIamRoleArn] + Action: sts:AssumeRole + Condition: + StringEquals: + 'sts:ExternalId': [!Ref AssumeRoleExternalId] + Description: "The role the Temporal Service uses to invoke Lambda functions for Serverless Workers" + MaxSessionDuration: 3600 + + TemporalLambdaInvokePermissions: + Type: AWS::IAM::Policy + DependsOn: TemporalServerlessWorker + Properties: + PolicyName: 'Temporal-Lambda-Invoke-Permissions' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - lambda:InvokeFunction + - lambda:GetFunction + Resource: !Ref LambdaFunctionARNs + Roles: + - !Sub '${RoleName}-${AWS::StackName}' + +Outputs: + RoleARN: + Description: The ARN of the IAM role created for the Temporal Service + Value: !GetAtt TemporalServerlessWorker.Arn + Export: + Name: !Sub "${AWS::StackName}-RoleARN" + + RoleName: + Description: The name of the IAM role + Value: !Ref RoleName + + LambdaFunctionARNs: + Description: The Lambda function ARNs that can be invoked + Value: !Join [", ", !Ref LambdaFunctionARNs] From 4965335ecc581b91f08612d10ea5db25f8a4acc4 Mon Sep 17 00:00:00 2001 From: Lenny Chen <55669665+lennessyy@users.noreply.github.com> Date: Tue, 28 Apr 2026 11:38:18 -0700 Subject: [PATCH 20/62] feat: serverless worker - typescript (#4468) * feat: serverless worker - typescript * docs: fix TS serverless worker review items - Add HOME=/tmp to TS create-function env vars - Fix makeOtelPlugins() to makeOtelPlugin() to match SDK export - Add versioning behavior requirement note Co-Authored-By: Claude Opus 4.6 (1M context) * docs: fix ADOT layer instructions and add X-Ray permissions note - Correct two-layer instruction to single ADOT Node.js layer (includes collector) - Add AWS_LAMBDA_EXEC_WRAPPER env var requirement - Add AWSXRayDaemonWriteAccess policy requirement with silent failure warning Co-Authored-By: Claude Opus 4.6 (1M context) * docs: revert to two-layer ADOT setup, keep permissions note Revert to the original two-layer ADOT instruction from the SDK author. The single-layer setup was not verified end-to-end. Keep the AWSXRayDaemonWriteAccess and AWS_LAMBDA_EXEC_WRAPPER additions. Co-Authored-By: Claude Opus 4.6 (1M context) * docs: add custom OTel collector config and setup instructions for TS The default ADOT collector config does not route OTLP data to the traces pipeline. Add the custom collector config YAML that wires OTLP to both traces (X-Ray) and metrics (CloudWatch EMF). Document the required env vars and IAM permissions. Co-Authored-By: Claude Opus 4.6 (1M context) * docs: fix OTel collector config to use logging exporter The standalone ADOT collector layer (v0.40.0) does not support the debug exporter. Replace with logging, which is the supported equivalent. Co-Authored-By: Claude Opus 4.6 (1M context) * docs: update TS OTel to match sample (two layers, debug exporter) Match the TS sample exactly: - Two ADOT layers (JS layer + standalone collector) - debug exporter (not logging) - AWS_LAMBDA_EXEC_WRAPPER=/opt/otel-instrument - OPENTELEMETRY_COLLECTOR_CONFIG_URI (not _FILE) - tracing-config Mode=Active - IAM permissions for xray, cloudwatch Co-Authored-By: Claude Opus 4.6 (1M context) * docs: fix AWS_LAMBDA_EXEC_WRAPPER to /opt/otel-handler for Node.js The Node.js ADOT layer ships /opt/otel-handler, not /opt/otel-instrument (which is the Python wrapper). Verified end-to-end: X-Ray traces confirmed. Co-Authored-By: Claude Opus 4.6 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- .../workers/serverless-workers/aws-lambda.mdx | 212 ++++++++++++++++++ .../workers/serverless-workers/index.mdx | 26 +++ .../serverless-workers/aws-lambda.mdx | 130 +++++++++-- sidebars.js | 12 + 4 files changed, 358 insertions(+), 22 deletions(-) create mode 100644 docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx create mode 100644 docs/develop/typescript/workers/serverless-workers/index.mdx diff --git a/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx b/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx new file mode 100644 index 0000000000..cac36d59ba --- /dev/null +++ b/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx @@ -0,0 +1,212 @@ +--- +id: aws-lambda +title: Serverless Workers on AWS Lambda - TypeScript SDK +sidebar_label: Serverless Workers on AWS Lambda +description: Write a Temporal Worker that runs on AWS Lambda using the TypeScript SDK @temporalio/lambda-worker package. +slug: /develop/typescript/workers/serverless-workers/aws-lambda +toc_max_heading_level: 4 +keywords: + - serverless + - lambda + - aws + - typescript sdk + - worker + - serverless worker +tags: + - Workers + - TypeScript SDK + - Serverless + - AWS Lambda +--- + +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. +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} + +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. + +```typescript +import { runWorker } from '@temporalio/lambda-worker'; +import * as activities from './activities'; + +export const handler = runWorker( + { deploymentName: 'my-app', buildId: 'build-1' }, + (config) => { + config.workerOptions.taskQueue = 'my-task-queue'; + config.workerOptions.workflowBundle = { + codePath: require.resolve('./workflow-bundle.js'), + }; + config.workerOptions.activities = activities; + }, +); +``` + +The deployment version is required. +Worker Deployment Versioning is always enabled for Serverless Workers. +Each Workflow must declare a [versioning behavior](/worker-versioning#versioning-behaviors), either `AutoUpgrade` or `Pinned`. +The default versioning behavior is `PINNED`. To change it, set `workerDeploymentOptions.defaultVersioningBehavior` in the configure callback. + +### Pre-bundle Workflow code {#pre-bundle} + +Use `workflowBundle` with pre-bundled code instead of `workflowsPath`. +Pre-bundling avoids webpack bundling overhead on every Lambda cold start. + +Build the bundle as a separate build step: + +```typescript +import { bundleWorkflowCode } from '@temporalio/worker'; +import { writeFile } from 'fs/promises'; + +const { code } = await bundleWorkflowCode({ + workflowsPath: require.resolve('./workflows'), +}); +await writeFile('./workflow-bundle.js', code); +``` + +Then reference the bundle in your handler with `workflowBundle: { codePath: require.resolve('./workflow-bundle.js') }`. + +## Configure the Temporal connection {#configure-connection} + +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: + +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 `@temporalio/lambda-worker` 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 | +|---|---| +| `maxConcurrentActivityTaskExecutions` | 2 | +| `maxConcurrentWorkflowTaskExecutions` | 10 | +| `maxConcurrentLocalActivityExecutions` | 2 | +| `maxConcurrentNexusTaskExecutions` | 5 | +| `workflowTaskPollerBehavior` | `SimpleMaximum(2)` | +| `activityTaskPollerBehavior` | `SimpleMaximum(1)` | +| `nexusTaskPollerBehavior` | `SimpleMaximum(1)` | +| `shutdownGraceTime` | 5 seconds | +| `maxCachedWorkflows` | 30 | +| `shutdownDeadlineBufferMs` | 7000 | + +Eager Activities are not supported. Lambda invocations don't maintain persistent connections. + +`shutdownDeadlineBufferMs` is specific to the `@temporalio/lambda-worker` package. +It controls how much time before the Lambda deadline the Worker begins its graceful shutdown. +The default is `shutdownGraceTime` (5s) + 2s. + +If your Worker handles long-running Activities, increase `shutdownGraceTime`, `shutdownDeadlineBufferMs`, 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/lambda-worker/otel` module provides OpenTelemetry integration with defaults configured for the [AWS Distro for OpenTelemetry (ADOT)](https://aws-otel.github.io/docs/getting-started/lambda) Lambda layers. +With this enabled, the Worker emits SDK metrics and distributed traces for Workflow and Activity executions. + +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/observability) and the [SDK metrics reference](/references/sdk-metrics). + +```typescript +import { runWorker } from '@temporalio/lambda-worker'; +import { applyDefaults } from '@temporalio/lambda-worker/otel'; +import * as activities from './activities'; + +export const handler = runWorker( + { deploymentName: 'my-app', buildId: 'build-1' }, + (config) => { + config.workerOptions.taskQueue = 'my-task-queue'; + config.workerOptions.workflowBundle = { + codePath: require.resolve('./workflow-bundle.js'), + }; + config.workerOptions.activities = activities; + applyDefaults(config); + }, +); +``` + +`applyDefaults` registers Temporal SDK interceptors for tracing and configures the Core SDK to export metrics via OTLP. +By default, telemetry is sent to `localhost:4317`, which is the ADOT Lambda layer's default collector endpoint. + +To collect this telemetry, attach two ADOT Lambda layers: + +1. The [ADOT JavaScript layer](https://aws-otel.github.io/docs/getting-started/lambda/lambda-js) for Node.js-side auto-instrumentation and trace export. +2. The [ADOT Collector layer](https://aws-otel.github.io/docs/getting-started/lambda) (`aws-otel-collector-amd64`) to run the OTel Collector as a Lambda extension, receiving telemetry via OTLP on `localhost:4317` and forwarding traces to X-Ray and metrics to CloudWatch. + +The default Collector configuration does not route 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: + +```yaml +receivers: + otlp: + protocols: + grpc: + endpoint: 'localhost:4317' + http: + endpoint: 'localhost:4318' + +exporters: + debug: + awsxray: + region: + awsemf: + namespace: TemporalWorkerMetrics + log_group_name: /aws/lambda/ + region: + dimension_rollup_option: NoDimensionRollup + resource_to_telemetry_conversion: + enabled: true + +service: + pipelines: + traces: + receivers: [otlp] + exporters: [awsxray, debug] + metrics: + receivers: [otlp] + exporters: [awsemf] +``` + +Set the following environment variables on the Lambda function: + +- `AWS_LAMBDA_EXEC_WRAPPER=/opt/otel-handler` +- `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. + +When pre-bundling Workflow code, pass the plugin from `makeOtelPlugin()` so that Workflow interceptor modules are included in the bundle: + +```typescript +import { bundleWorkflowCode } from '@temporalio/worker'; +import { makeOtelPlugin } from '@temporalio/lambda-worker/otel'; + +const { plugin } = makeOtelPlugin(); +const { code } = await bundleWorkflowCode({ + workflowsPath: require.resolve('./workflows'), + plugins: [plugin], +}); +``` diff --git a/docs/develop/typescript/workers/serverless-workers/index.mdx b/docs/develop/typescript/workers/serverless-workers/index.mdx new file mode 100644 index 0000000000..58f3e71046 --- /dev/null +++ b/docs/develop/typescript/workers/serverless-workers/index.mdx @@ -0,0 +1,26 @@ +--- +id: index +title: Serverless Workers - TypeScript SDK +sidebar_label: Serverless Workers +description: Write Temporal Workers that run on serverless compute using the TypeScript SDK. +slug: /develop/typescript/workers/serverless-workers +toc_max_heading_level: 4 +keywords: + - serverless + - typescript sdk + - worker +tags: + - Workers + - TypeScript 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/typescript/workers/serverless-workers/aws-lambda) - Use the `@temporalio/lambda-worker` package to run a Worker as a Lambda function. Covers setup, configuration, Lambda-tuned defaults, and observability. diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 158ca2bf07..f1d6d71442 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -40,6 +40,11 @@ This guide walks through deploying a Temporal [Serverless Worker](/serverless-wo - The [Go SDK](/develop/go) (`go.temporal.io/sdk`)
+ + +- The [TypeScript SDK](/develop/typescript) (`@temporalio/lambda-worker`) + +
## 1. Write Worker code {#write-worker-code} @@ -85,6 +90,31 @@ For details on configuration options, Lambda-tuned defaults, and the invocation [Serverless Workers - Go SDK](/develop/go/workers/serverless-workers/aws-lambda). + + +Use the `@temporalio/lambda-worker` package. + +```typescript +import { runWorker } from '@temporalio/lambda-worker'; +import * as activities from './activities'; + +export const handler = runWorker( + { deploymentName: 'my-app', buildId: 'build-1' }, + (config) => { + config.workerOptions.taskQueue = 'my-task-queue'; + config.workerOptions.workflowBundle = { + codePath: require.resolve('./workflow-bundle.js'), + }; + config.workerOptions.activities = activities; + }, +); +``` + +Use `workflowBundle` with pre-bundled code instead of `workflowsPath` to avoid webpack bundling overhead on Lambda cold starts. + +For details on configuration options, Lambda-tuned defaults, and observability, see [Serverless Workers - TypeScript SDK](/develop/typescript/workers/serverless-workers/aws-lambda). + + ## 2. Deploy Lambda function {#deploy-lambda-function} @@ -109,10 +139,30 @@ zip function.zip bootstrap ``` + + +Build the Workflow bundle and compile the project: + +```bash +npx ts-node src/scripts/build-workflow-bundle.ts +npx tsc +``` + +Install production dependencies and package everything into a zip: + +```bash +npm install --omit=dev +zip -r function.zip lib/ node_modules/ workflow-bundle.js +``` + + ### ii. Deploy Lambda function {#deploy-lambda-function-step} + + + ```bash aws lambda create-function \ --function-name my-temporal-worker \ @@ -125,28 +175,54 @@ aws lambda create-function \ --environment "Variables={HOME=/tmp,TEMPORAL_ADDRESS=:7233,TEMPORAL_NAMESPACE=,TEMPORAL_API_KEY=}" ``` -| Parameter | Description | -| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--function-name` | Name of the Lambda function. | -| `--runtime` | Lambda runtime. Use `provided.al2023` for custom Go binaries. | -| `--handler` | Entry point binary name. Must be `bootstrap` when using the `provided.al2023` custom runtime. | -| `--role` | ARN of the Lambda [execution role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html), which grants the function permission to run. Trusted principal must be `lambda.amazonaws.com`. This is separate from the role Temporal uses to invoke the function in [Step 3](#configure-iam). The role must have at least the [`AWSLambdaBasicExecutionRole`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaBasicExecutionRole.html) managed policy attached. | -| `--zip-file` | Path to your packaged deployment zip. | -| `--timeout` | Invocation deadline in seconds. This is the maximum time each Lambda invocation can run before AWS terminates it. Set this high enough for the Worker to start, process Tasks, and [shut down gracefully](/serverless-workers#worker-lifecycle). | -| `--memory-size` | Memory in MB allocated to each invocation. | -| `HOME` | Must be `/tmp`. | -| `TEMPORAL_ADDRESS` | Temporal frontend address (e.g., `..tmprl.cloud:7233`). | -| `TEMPORAL_NAMESPACE` | Temporal Namespace. | -| `TEMPORAL_TASK_QUEUE` | Task Queue name. Overrides the value set in code. | -| `TEMPORAL_TLS_CLIENT_CERT_PATH` | Path to the TLS client certificate file for mTLS authentication. | -| `TEMPORAL_TLS_CLIENT_KEY_PATH` | Path to the TLS client key file for mTLS authentication. | -| `TEMPORAL_API_KEY` | API key for API key authentication. | - -The `lambdaworker` package reads environment variables automatically at startup. For the full list, see -[Client environment configuration](/references/client-environment-configuration). - -Sensitive values like TLS keys and API keys should be encrypted at rest. See -[AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars-encryption.html) for options. +| Parameter | Description | +|---|---| +| `--function-name` | Name of the Lambda function. | +| `--runtime` | Lambda runtime. Use `provided.al2023` for custom Go binaries. | +| `--handler` | Entry point binary name. Must be `bootstrap` when using the `provided.al2023` custom runtime. | + + + + +```bash +aws lambda create-function \ + --function-name my-temporal-worker \ + --runtime nodejs22.x \ + --handler lib/index.handler \ + --role arn:aws:iam:::role/my-temporal-worker-execution \ + --zip-file fileb://function.zip \ + --timeout 600 \ + --memory-size 256 \ + --environment "Variables={HOME=/tmp,TEMPORAL_ADDRESS=:7233,TEMPORAL_NAMESPACE=,TEMPORAL_API_KEY=}" +``` + +| Parameter | Description | +|---|---| +| `--function-name` | Name of the Lambda function. | +| `--runtime` | Lambda runtime. Use `nodejs22.x` or another supported Node.js version (20+). | +| `--handler` | Entry point in `module.export` format. Must point to the handler exported by `runWorker`. | + + + + +The following parameters apply to all SDKs: + +| Parameter | Description | +|---|---| +| `--role` | ARN of the Lambda [execution role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html), which grants the function permission to run. Trusted principal must be `lambda.amazonaws.com`. This is separate from the role Temporal uses to invoke the function in [Step 3](#configure-iam). The role must have at least the [`AWSLambdaBasicExecutionRole`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaBasicExecutionRole.html) managed policy attached. | +| `--zip-file` | Path to your packaged deployment zip. | +| `--timeout` | Invocation deadline in seconds. This is the maximum time each Lambda invocation can run before AWS terminates it. Set this high enough for the Worker to start, process Tasks, and [shut down gracefully](/serverless-workers#worker-lifecycle). | +| `--memory-size` | Memory in MB allocated to each invocation. | +| `TEMPORAL_ADDRESS` | Temporal frontend address (e.g., `..tmprl.cloud:7233`). | +| `TEMPORAL_NAMESPACE` | Temporal Namespace. | +| `TEMPORAL_TASK_QUEUE` | Task Queue name. Overrides the value set in code. | +| `TEMPORAL_TLS_CLIENT_CERT_PATH` | Path to the TLS client certificate file for mTLS authentication. | +| `TEMPORAL_TLS_CLIENT_KEY_PATH` | Path to the TLS client key file for mTLS authentication. | +| `TEMPORAL_API_KEY` | API key for API key authentication. | + +The serverless Worker packages read environment variables automatically at startup. For the full list, see [Client environment configuration](/references/client-environment-configuration). + +Sensitive values like TLS keys and API keys should be encrypted at rest. See [AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars-encryption.html) for options. To update an existing function with new code: @@ -334,6 +410,16 @@ When you create a version through the UI, the version is automatically set as cu Use the CLI for manual setup, shell scripts, and CI/CD pipelines. When you create a version through the CLI, you must [set the version as current](#set-current-version) as a separate step. +First, create the Worker Deployment if it does not already exist: + +```bash +temporal worker deployment create \ + --namespace \ + --name my-app +``` + +Then create the version with the compute provider configuration: + ```bash temporal worker deployment create-version \ --namespace \ diff --git a/sidebars.js b/sidebars.js index 39fdc7a644..bfdc4e2ef5 100644 --- a/sidebars.js +++ b/sidebars.js @@ -664,6 +664,18 @@ module.exports = { items: [ 'develop/typescript/workers/run-worker-process', 'develop/typescript/workers/interceptors', + { + type: 'category', + label: 'Serverless Workers', + collapsed: true, + link: { + type: 'doc', + id: 'develop/typescript/workers/serverless-workers/index', + }, + items: [ + 'develop/typescript/workers/serverless-workers/aws-lambda', + ], + }, ], }, { From 92ff7c18d0be8cae79f8d2d5f087d4c0702f7fad Mon Sep 17 00:00:00 2001 From: Lenny Chen <55669665+lennessyy@users.noreply.github.com> Date: Tue, 28 Apr 2026 11:57:46 -0700 Subject: [PATCH 21/62] feat: python serverless worker (#4467) * feat: python serverless worker * docs: add versioning behavior samples, packaging fixes, heading cleanup - Add versioning behavior (PINNED) to Python and Go code samples - Add VersioningBehavior import from temporalio.common for Python - Fix Python packaging to zip deps first then add app files - Change Go samples from AutoUpgrade to Pinned - Add Python and TypeScript tabs to deploy guide - Clean up deploy guide headings (remove articles) - Add Serverless Worker link in deploy guide intro Co-Authored-By: Claude Opus 4.6 (1M context) * Revert "docs: add versioning behavior samples, packaging fixes, heading cleanup" This reverts commit 6fe5cc5ed7e7bd047a20a555e83ebab8c6d5c7c7. * docs: add Python versioning behavior samples and packaging fix - Add versioning behavior (PINNED) example to Python SDK page and deploy guide - Fix Python packaging: use --platform manylinux2014_x86_64 for Lambda - Zip deps first, then add app files separately Co-Authored-By: Claude Opus 4.6 (1M context) * docs: restructure Python SDK page for readability Highlight run_worker lines, explain configure callback right after the code block, move versioning behavior below. Co-Authored-By: Claude Opus 4.6 (1M context) * docs: explain deployment name and build ID with links to versioning Co-Authored-By: Claude Opus 4.6 (1M context) * Apply suggestions from code review Co-authored-by: Lenny Chen <55669665+lennessyy@users.noreply.github.com> * docs: add custom OTel collector config and setup instructions for Python The default ADOT collector config does not route OTLP data to the traces pipeline. Add the custom collector config YAML that wires OTLP to both traces (X-Ray) and metrics (CloudWatch EMF). Document the required env var and IAM permissions. Co-Authored-By: Claude Opus 4.6 (1M context) * docs: fix OTel collector config to use logging exporter The standalone ADOT collector layer (v0.40.0) does not support the debug exporter. Replace with logging, which is the supported equivalent. Verified end-to-end: traces now appear in X-Ray. Co-Authored-By: Claude Opus 4.6 (1M context) * docs: update Python OTel to use language-specific ADOT layer Use the ADOT Python layer (includes auto-instrumentation + collector) instead of standalone collector layer. Matches the verified sample setup. Use debug exporter (supported by the newer collector in the language layer). Add AWS_LAMBDA_EXEC_WRAPPER and tracing-config Mode=Active. Co-Authored-By: Claude Opus 4.6 (1M context) * docs: fix bad merge --------- Co-authored-by: Claude Opus 4.6 (1M context) --- .../workers/serverless-workers/aws-lambda.mdx | 213 ++++++++++++++++++ .../workers/serverless-workers/index.mdx | 26 +++ .../serverless-workers/aws-lambda.mdx | 87 +++++++ sidebars.js | 12 + 4 files changed, 338 insertions(+) create mode 100644 docs/develop/python/workers/serverless-workers/aws-lambda.mdx create mode 100644 docs/develop/python/workers/serverless-workers/index.mdx diff --git a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx new file mode 100644 index 0000000000..93ceb66843 --- /dev/null +++ b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx @@ -0,0 +1,213 @@ +--- +id: aws-lambda +title: Serverless Workers on AWS Lambda - Python SDK +sidebar_label: Serverless Workers on AWS Lambda +description: Write a Temporal Worker that runs on AWS Lambda using the Python SDK lambda_worker package. +slug: /develop/python/workers/serverless-workers/aws-lambda +toc_max_heading_level: 4 +keywords: + - serverless + - lambda + - aws + - python sdk + - worker + - serverless worker +tags: + - Workers + - Python SDK + - Serverless + - AWS Lambda +--- + +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). + +## Create and run a Worker in Lambda {#create-and-run} + +Use the `run_worker` function to create a Lambda handler that runs a Temporal Worker. +Pass a `WorkerDeploymentVersion` and a configure callback that registers your Workflows and Activities. + +```python {14-20} +from temporalio.common import WorkerDeploymentVersion +from temporalio.contrib.aws.lambda_worker import LambdaWorkerConfig, run_worker + +from my_workflows import MyWorkflow +from my_activities import my_activity + + +def configure(config: LambdaWorkerConfig) -> None: + config.worker_config["task_queue"] = "my-task-queue" + config.worker_config["workflows"] = [MyWorkflow] + config.worker_config["activities"] = [my_activity] + + +lambda_handler = run_worker( + WorkerDeploymentVersion( + deployment_name="my-app", + build_id="build-1", + ), + configure, +) +``` + +`run_worker` takes a `WorkerDeploymentVersion` and a configure callback, and returns a Lambda handler. +The `WorkerDeploymentVersion` identifies the [Worker Deployment](/worker-versioning#worker-deployments) and [Build ID](/worker-versioning#build-id) for this Worker. +The deployment name groups related Workers across versions, and the Build ID identifies a specific release of your Worker code. +Worker Versioning is required for Serverless Workers. + +The `configure` callback receives a `LambdaWorkerConfig` dataclass with fields pre-populated with Lambda-appropriate defaults. +Set the Task Queue, Workflows, and Activities through `worker_config`, which accepts the same keyword arguments as the `Worker` constructor. + +Each Workflow registered with the Worker must declare a [versioning behavior](/worker-versioning#versioning-behaviors) in the `@workflow.defn` decorator, either `PINNED` or `AUTO_UPGRADE`: + +```python {5} +from temporalio import workflow +from temporalio.common import VersioningBehavior + + +@workflow.defn(versioning_behavior=VersioningBehavior.PINNED) +class MyWorkflow: + @workflow.run + async def run(self, input: str) -> str: + ... +``` + +## Configure the Temporal connection {#configure-connection} + +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: + +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 `lambda_worker` 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 | +|---|---| +| `max_concurrent_activities` | 2 | +| `max_concurrent_workflow_tasks` | 10 | +| `max_concurrent_local_activities` | 2 | +| `max_concurrent_nexus_tasks` | 5 | +| `workflow_task_poller_behavior` | `SimpleMaximum(2)` | +| `activity_task_poller_behavior` | `SimpleMaximum(1)` | +| `nexus_task_poller_behavior` | `SimpleMaximum(1)` | +| `graceful_shutdown_timeout` | 5 seconds | +| `max_cached_workflows` | 30 | +| `disable_eager_activity_execution` | Always `True` | +| `shutdown_deadline_buffer` | 7 seconds | + +`disable_eager_activity_execution` is always `True` and cannot be overridden. +Eager Activities require a persistent connection, which Lambda invocations don't maintain. + +`shutdown_deadline_buffer` is specific to the `lambda_worker` package. +It controls how much time before the Lambda deadline the Worker begins its graceful shutdown. +The default is `graceful_shutdown_timeout` + 2 seconds. + +If your Worker handles long-running Activities, increase `graceful_shutdown_timeout`, `shutdown_deadline_buffer`, 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 `lambda_worker.otel` module 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 Python SDK emits in any environment. +For general observability concepts and the full list of available metrics, see [Observability - Python SDK](/develop/python/observability) and the [SDK metrics reference](/references/sdk-metrics). + +from temporalio.common import WorkerDeploymentVersion +from temporalio.contrib.aws.lambda_worker import LambdaWorkerConfig, run_worker +from temporalio.contrib.aws.lambda_worker.otel import apply_defaults + +from my_workflows import MyWorkflow +from my_activities import my_activity + + +def configure(config: LambdaWorkerConfig) -> None: + config.worker_config["task_queue"] = "my-task-queue" + config.worker_config["workflows"] = [MyWorkflow] + config.worker_config["activities"] = [my_activity] + apply_defaults(config) + + +lambda_handler = run_worker( + WorkerDeploymentVersion( + deployment_name="my-app", + build_id="build-1", + ), + configure, +) +``` + +`apply_defaults` configures both metrics and tracing. +By default, telemetry is sent to `localhost:4317`, which is the ADOT Lambda layer's default collector endpoint. + +To collect this telemetry, attach the [ADOT Python Lambda layer](https://aws-otel.github.io/docs/getting-started/lambda/lambda-python) to your Lambda function. +The layer includes both auto-instrumentation and an OpenTelemetry Collector that receives telemetry on `localhost:4317` and forwards traces to AWS X-Ray and metrics to Amazon CloudWatch. + +The default Collector configuration does not route 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: + +```yaml +receivers: + otlp: + protocols: + grpc: + endpoint: 'localhost:4317' + http: + endpoint: 'localhost:4318' + +exporters: + debug: + awsxray: + region: + awsemf: + namespace: TemporalWorkerMetrics + log_group_name: /aws/lambda/ + region: + dimension_rollup_option: NoDimensionRollup + resource_to_telemetry_conversion: + enabled: true + +service: + pipelines: + traces: + receivers: [otlp] + exporters: [awsxray, debug] + metrics: + receivers: [otlp] + exporters: [awsemf] +``` + +Set the following environment variables on the Lambda function: + +- `AWS_LAMBDA_EXEC_WRAPPER=/opt/otel-instrument` +- `OPENTELEMETRY_COLLECTOR_CONFIG_FILE=/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. +Attach the [`AWSXRayDaemonWriteAccess`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSXRayDaemonWriteAccess.html) managed policy, or add `xray:PutTraceSegments`, `xray:PutTelemetryRecords`, and `cloudwatch:PutMetricData` permissions. +Without these permissions, the Collector fails silently and no telemetry appears. + +If you only need metrics or tracing, use `build_metrics_telemetry_config` or `apply_tracing` individually. diff --git a/docs/develop/python/workers/serverless-workers/index.mdx b/docs/develop/python/workers/serverless-workers/index.mdx new file mode 100644 index 0000000000..eaa30b5c12 --- /dev/null +++ b/docs/develop/python/workers/serverless-workers/index.mdx @@ -0,0 +1,26 @@ +--- +id: index +title: Serverless Workers - Python SDK +sidebar_label: Serverless Workers +description: Write Temporal Workers that run on serverless compute using the Python SDK. +slug: /develop/python/workers/serverless-workers +toc_max_heading_level: 4 +keywords: + - serverless + - python sdk + - worker +tags: + - Workers + - Python 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/python/workers/serverless-workers/aws-lambda) - Use the `lambda_worker` contrib package to run a Worker as a Lambda function. Covers setup, configuration, Lambda-tuned defaults, and observability. diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index f1d6d71442..a2442f65a4 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -40,6 +40,11 @@ This guide walks through deploying a Temporal [Serverless Worker](/serverless-wo - The [Go SDK](/develop/go) (`go.temporal.io/sdk`) + + +- The [Python SDK](/develop/python) (`temporalio`) + + - The [TypeScript SDK](/develop/typescript) (`@temporalio/lambda-worker`) @@ -90,6 +95,50 @@ For details on configuration options, Lambda-tuned defaults, and the invocation [Serverless Workers - Go SDK](/develop/go/workers/serverless-workers/aws-lambda). + + +Use the Python SDK's `lambda_worker` contrib package. + +```python +from temporalio.common import WorkerDeploymentVersion +from temporalio.contrib.aws.lambda_worker import LambdaWorkerConfig, run_worker + +from my_workflows import MyWorkflow +from my_activities import my_activity + + +def configure(config: LambdaWorkerConfig) -> None: + config.worker_config["task_queue"] = "my-task-queue" + config.worker_config["workflows"] = [MyWorkflow] + config.worker_config["activities"] = [my_activity] + + +lambda_handler = run_worker( + WorkerDeploymentVersion( + deployment_name="my-app", + build_id="build-1", + ), + configure, +) +``` + +Each Workflow must declare a [versioning behavior](/worker-versioning#versioning-behaviors) in the `@workflow.defn` decorator, either `PINNED` or `AUTO_UPGRADE`: + +```python +from temporalio import workflow +from temporalio.common import VersioningBehavior + + +@workflow.defn(versioning_behavior=VersioningBehavior.PINNED) +class MyWorkflow: + @workflow.run + async def run(self, input: str) -> str: + ... +``` + +For details on configuration options, Lambda-tuned defaults, and observability, see [Serverless Workers - Python SDK](/develop/python/workers/serverless-workers/aws-lambda). + + Use the `@temporalio/lambda-worker` package. @@ -139,6 +188,22 @@ zip function.zip bootstrap ``` + + +Install dependencies into a local directory for packaging. Use `--platform` to fetch Linux-compatible binaries for the Lambda runtime: + +```bash +pip install --target ./package --platform manylinux2014_x86_64 --only-binary=:all: temporalio +``` + +Package the dependencies and your application code into a zip file: + +```bash +cd package && zip -r ../function.zip . && cd .. +zip function.zip lambda_function.py my_workflows.py my_activities.py +``` + + Build the Workflow bundle and compile the project: @@ -182,6 +247,27 @@ aws lambda create-function \ | `--handler` | Entry point binary name. Must be `bootstrap` when using the `provided.al2023` custom runtime. | + + +```bash +aws lambda create-function \ + --function-name my-temporal-worker \ + --runtime python3.13 \ + --handler lambda_function.lambda_handler \ + --role arn:aws:iam:::role/my-temporal-worker-execution \ + --zip-file fileb://function.zip \ + --timeout 600 \ + --memory-size 256 \ + --environment "Variables={TEMPORAL_ADDRESS=:7233,TEMPORAL_NAMESPACE=,TEMPORAL_API_KEY=}" +``` + +| Parameter | Description | +|---|---| +| `--function-name` | Name of the Lambda function. | +| `--runtime` | Lambda runtime. Use `python3.13` or another supported Python version. | +| `--handler` | Entry point in `module.function` format. Must point to the handler returned by `run_worker`. | + + ```bash @@ -220,6 +306,7 @@ The following parameters apply to all SDKs: | `TEMPORAL_TLS_CLIENT_KEY_PATH` | Path to the TLS client key file for mTLS authentication. | | `TEMPORAL_API_KEY` | API key for API key authentication. | +The SDKs read environment variables automatically at startup. For the full list, see [Client environment configuration](/references/client-environment-configuration). The serverless Worker packages read environment variables automatically at startup. For the full list, see [Client environment configuration](/references/client-environment-configuration). Sensitive values like TLS keys and API keys should be encrypted at rest. See [AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars-encryption.html) for options. diff --git a/sidebars.js b/sidebars.js index bfdc4e2ef5..523e9049ca 100644 --- a/sidebars.js +++ b/sidebars.js @@ -524,6 +524,18 @@ module.exports = { items: [ 'develop/python/workers/run-worker-process', 'develop/python/workers/interceptors', + { + type: 'category', + label: 'Serverless Workers', + collapsed: true, + link: { + type: 'doc', + id: 'develop/python/workers/serverless-workers/index', + }, + items: [ + 'develop/python/workers/serverless-workers/aws-lambda', + ], + }, ], }, { From 11fc3701770edc55ff642462d538543688de481b Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Tue, 28 Apr 2026 13:39:59 -0700 Subject: [PATCH 22/62] copyedits --- .../worker-deployments/serverless-workers/aws-lambda.mdx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index a2442f65a4..dcf382041d 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -30,6 +30,7 @@ This guide walks through deploying a Temporal [Serverless Worker](/serverless-wo - For self-hosted deployments, complete the [self-hosted setup](/production-deployment/worker-deployments/serverless-workers/self-hosted-setup) before following this guide. +- Every Workflow must declare a [versioning behavior](/worker-versioning#versioning-behaviors). - An AWS account with permissions to create and invoke Lambda functions and create IAM roles. - 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. @@ -155,12 +156,16 @@ export const handler = runWorker( codePath: require.resolve('./workflow-bundle.js'), }; config.workerOptions.activities = activities; + config.workerOptions.workerDeploymentOptions!.defaultVersioningBehavior = 'AUTO_UPGRADE'; }, ); ``` Use `workflowBundle` with pre-bundled code instead of `workflowsPath` to avoid webpack bundling overhead on Lambda cold starts. +Each Workflow must declare a [versioning behavior](/worker-versioning#versioning-behaviors), either `AUTO_UPGRADE` or `PINNED`. +Set it per-Workflow with `setWorkflowOptions` in the Workflow file, or set a default for all Workflows with `defaultVersioningBehavior` in the configure callback. + For details on configuration options, Lambda-tuned defaults, and observability, see [Serverless Workers - TypeScript SDK](/develop/typescript/workers/serverless-workers/aws-lambda). @@ -225,6 +230,8 @@ zip -r function.zip lib/ node_modules/ workflow-bundle.js ### ii. Deploy Lambda function {#deploy-lambda-function-step} +Replace the placeholder values and run the following command to create the Lambda function in your AWS environment. + From a7fba6903adbf43aaeb0e121d6cd486b94ac5152 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Tue, 28 Apr 2026 13:46:13 -0700 Subject: [PATCH 23/62] clarify go sample otel instructions --- .../workers/serverless-workers/aws-lambda.mdx | 56 ++++++++++++++++++- .../workers/serverless-workers/aws-lambda.mdx | 2 +- .../workers/serverless-workers/aws-lambda.mdx | 2 +- 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx index 45cea73bd5..c4f9485291 100644 --- a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx @@ -140,7 +140,59 @@ func main() { `ApplyDefaults` configures both metrics and tracing. By default, telemetry is sent to `localhost:4317`, which is the ADOT Lambda layer's default collector endpoint. -To collect this telemetry, attach the [AWS Distro for OpenTelemetry Lambda layer](https://aws-otel.github.io/docs/getting-started/lambda/lambda-go) to your Lambda function. -The layer runs a collector sidecar that receives telemetry on `localhost:4317` and forwards it to your configured backend (e.g., AWS X-Ray, Amazon CloudWatch). +To collect this telemetry, attach the [ADOT Collector layer](https://aws-otel.github.io/docs/getting-started/lambda) to your Lambda function. +The layer runs a collector sidecar that receives telemetry on `localhost:4317` and forwards traces to X-Ray and metrics to CloudWatch. +Go does not need a language-specific ADOT layer because the OTel SDK is compiled into the binary. + +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: + +```yaml +receivers: + otlp: + protocols: + grpc: + endpoint: 'localhost:4317' + http: + endpoint: 'localhost:4318' + +exporters: + debug: + awsxray: + region: + awsemf: + namespace: TemporalWorkerMetrics + log_group_name: /aws/lambda/ + region: + dimension_rollup_option: NoDimensionRollup + resource_to_telemetry_conversion: + enabled: true + +service: + pipelines: + traces: + receivers: [otlp] + exporters: [awsxray, debug] + metrics: + receivers: [otlp] + exporters: [awsemf] +``` + +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 `otel.ApplyMetrics` or `otel.ApplyTracing` individually. diff --git a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx index 93ceb66843..c6ede1d6c7 100644 --- a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx @@ -158,7 +158,7 @@ By default, telemetry is sent to `localhost:4317`, which is the ADOT Lambda laye To collect this telemetry, attach the [ADOT Python Lambda layer](https://aws-otel.github.io/docs/getting-started/lambda/lambda-python) to your Lambda function. The layer includes both auto-instrumentation and an OpenTelemetry Collector that receives telemetry on `localhost:4317` and forwards traces to AWS X-Ray and metrics to Amazon CloudWatch. -The default Collector configuration does not route OTLP data to the traces pipeline. +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: diff --git a/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx b/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx index cac36d59ba..dce08ac844 100644 --- a/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx @@ -138,7 +138,7 @@ export const handler = runWorker( ); ``` -`applyDefaults` registers Temporal SDK interceptors for tracing and configures the Core SDK to export metrics via OTLP. +`applyDefaults` registers Temporal SDK interceptors for tracing and configures the Core SDK to export metrics via OpenTelemetry Protocol (OTLP). By default, telemetry is sent to `localhost:4317`, which is the ADOT Lambda layer's default collector endpoint. To collect this telemetry, attach two ADOT Lambda layers: From b8225152aeb736f5fc30502451d8b93cea2ce548 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Tue, 28 Apr 2026 13:55:55 -0700 Subject: [PATCH 24/62] copyedits --- .../serverless-workers/index.mdx | 108 +++++++++++------- .../config/vocabularies/Temporal/accept.txt | 2 +- 2 files changed, 67 insertions(+), 43 deletions(-) diff --git a/docs/evaluate/development-production-features/serverless-workers/index.mdx b/docs/evaluate/development-production-features/serverless-workers/index.mdx index 833f04d954..ee6b7fef43 100644 --- a/docs/evaluate/development-production-features/serverless-workers/index.mdx +++ b/docs/evaluate/development-production-features/serverless-workers/index.mdx @@ -3,7 +3,9 @@ id: index title: Serverless Workers sidebar_label: Serverless Workers slug: /evaluate/serverless-workers -description: Understand the benefits of Serverless Workers and when to use them. Run Temporal Workers on serverless compute with no infrastructure to manage. +description: + Understand the benefits of Serverless Workers and when to use them. Run Temporal Workers on serverless compute with no + infrastructure to manage. toc_max_heading_level: 4 keywords: - serverless @@ -17,81 +19,103 @@ tags: - Serverless --- -Serverless Workers let you run Temporal Workers on serverless compute platforms like AWS Lambda. -There are no servers to provision, no clusters to scale, and no idle compute to pay for. -Temporal invokes the Worker when Tasks arrive, and the Worker shuts down when the work is done. +Serverless Workers let you run Temporal Workers on serverless compute platforms like AWS Lambda. There are no servers to +provision, no clusters to scale, and no idle compute to pay for. Temporal invokes the Worker when Tasks arrive, and the +Worker shuts down when the work is done. -Serverless Workers use the same Temporal SDKs as traditional long-lived Workers. -You register Workflows and Activities the same way. -The difference is in the lifecycle: instead of running a long-lived process, Temporal invokes the Serverless Worker on demand when Tasks arrive. The Worker starts, polls for available Tasks, processes them, and exits when the work is done. +Serverless Workers use the same Temporal SDKs as traditional long-lived Workers. You register Workflows and Activities +the same way. The difference is in the lifecycle: instead of running a long-lived process, Temporal invokes the +Serverless Worker on demand when Tasks arrive. The Worker starts, polls for available Tasks, processes them, and exits +when the work is done. -For a deeper look at how Serverless invocation works under the hood, see [Serverless Workers](/serverless-workers) in the encyclopedia. +For a deeper look at how Serverless invocation works under the hood, see [Serverless Workers](/serverless-workers) in +the encyclopedia. -## Benefits +## Why use Serverless Workers? + +Serverless Workers are a good fit for many workloads. They offer several advantages compared to long-lived Workers on +dedicated compute. ### Reduce operational overhead -Long-lived Workers require you to provision infrastructure, configure scaling policies, manage deployments, and monitor host-level health. -Serverless Workers reduce this burden by offloading invocation and scaling to Temporal and the compute provider. -You still deploy the function and configure the compute provider, but there is no always-on infrastructure to manage and no autoscaling policies to tune. +Long-lived Workers require you to provision infrastructure, configure scaling policies, manage deployments, and monitor +host-level health. Serverless Workers reduce this burden by offloading invocation and scaling to Temporal and the +compute provider. You still deploy the function and configure the compute provider, but there is no always-on +infrastructure to manage and no autoscaling policies to tune. -Worker management is one of the most common sources of support questions for Temporal users. -Serverless Workers offer a prescriptive deployment path that reduces the operational surface area and lets you focus on writing Workflows instead of managing infrastructure. +Worker management is one of the most common sources of support questions for Temporal users. Serverless Workers offer a +prescriptive deployment path that reduces the operational surface area and lets you focus on writing Workflows instead +of managing infrastructure. ### Get started faster -Running a long-lived Worker requires choosing a hosting strategy, configuring compute resources, and setting up deployment pipelines before you can execute your first Workflow. +Running a long-lived Worker requires choosing a hosting strategy, configuring compute resources, and setting up +deployment pipelines before you can execute your first Workflow in production. -With Serverless Workers, deploying a Worker is as simple as deploying a function. -Package your Worker code, deploy it to your serverless provider, and configure the connection to Temporal. There is no need to set up Kubernetes, manage container orchestration, or design a scaling strategy. +With Serverless Workers, deploying a Worker is as simple as deploying a function. Package your Worker code, deploy it to +your serverless provider, and configure the connection to Temporal. There is no need to set up Kubernetes, manage +container orchestration, or design a scaling strategy. ### Scale automatically -Serverless compute providers handle scaling natively. -When Task volume increases, the provider spins up additional function instances. -When traffic drops, instances scale down. When there is no work, there is no compute running. +Serverless compute providers handle scaling natively. When Task volume increases, the provider spins up additional +function instances. When traffic drops, instances scale down. When there is no work, there is no compute running. -This automatic scaling is especially useful for bursty, event-driven workloads where traffic patterns are unpredictable or highly variable. +This automatic scaling is especially useful for bursty, event-driven workloads where traffic patterns are unpredictable +or highly variable. ### Pay only for what you use -Long-lived Workers run continuously, whether or not there is work to process. -Serverless Workers run only when Tasks are available. -For workloads with low or intermittent volume, this pay-per-invocation model can significantly reduce compute costs. +Long-lived Workers run continuously, whether or not there is work to process. Serverless Workers run only when Tasks are +available. For workloads with low or intermittent volume, this pay-per-invocation model can significantly reduce compute +costs. ## When to use Serverless Workers Serverless Workers are a good fit when: -- **Workloads are bursty or event-driven.** Order processing, notifications, webhook handlers, and similar workloads that experience spiky traffic benefit from automatic scaling without over-provisioning. -- **Traffic is low or intermittent.** If Workers spend most of their time idle, Serverless Workers eliminate the cost of always-on compute. -- **You want a simpler getting-started path.** Deploying a function is simpler than setting up a container orchestration platform. Serverless Workers reduce the steps between writing Worker code and running your first Workflow. -- **Your organization has standardized on serverless.** Teams that already run services on Lambda, Cloud Run, or similar platforms can run Temporal Workers using the same deployment patterns and tooling. -- **You serve multiple tenants with infrequent workloads.** Platforms that run Workflows on behalf of many users or customers can avoid running dedicated Workers per tenant. +- **Workloads are bursty or event-driven.** Order processing, notifications, webhook handlers, and similar workloads + that experience spiky traffic benefit from automatic scaling without over-provisioning. +- **Traffic is low or intermittent.** If Workers spend most of their time idle, Serverless Workers eliminate the cost of + always-on compute. +- **You want a simpler getting-started path.** Deploying a function is simpler than setting up a container orchestration + platform. Serverless Workers reduce the steps between writing Worker code and running your first Workflow. +- **Your organization has standardized on serverless.** Teams that already run services on Lambda, Cloud Run, or similar + platforms can run Temporal Workers using the same deployment patterns and tooling. +- **You serve multiple tenants with infrequent workloads.** Platforms that run Workflows on behalf of many users or + customers can avoid running dedicated Workers per tenant. Serverless Workers may not be ideal when: -- **Activities are long-running and cannot be interrupted.** Some serverless platforms enforce execution time limits. For example, AWS Lambda has a 15-minute execution limit. Activities that run longer than the provider's timeout and cannot be broken into smaller steps need a different hosting strategy or a provider with longer limits (such as Cloud Run). Long-running Workflows are not affected because Workflows can span multiple invocations. -- **Workloads require sustained high throughput.** For consistently high-volume Task Queues, long-lived Workers on dedicated compute may be more cost-effective and performant. -- **You need persistent connections.** Some features require a persistent connection between the Worker and Temporal, which serverless invocations do not maintain. +- **Activities are long-running and cannot be interrupted.** Some serverless platforms enforce execution time limits. + For example, AWS Lambda has a 15-minute execution limit. Activities that run longer than the provider's timeout and + cannot be broken into smaller steps need a different hosting strategy or a provider with longer limits (such as Cloud + Run). Long-running Workflows are not affected because Workflows can span multiple invocations. +- **Workloads require sustained high throughput.** For consistently high-volume Task Queues, long-lived Workers on + dedicated compute may be more cost-effective and performant. +- **You need persistent connections.** Some features require a persistent connection between the Worker and Temporal, + which serverless invocations do not maintain. ## How Serverless Workers compare to long-lived Workers -| | Long-lived Worker | Serverless Worker | -|---|---|---| -| **Lifecycle** | Long-lived process that runs continuously. | Invoked on demand. Starts and stops per invocation. | -| **Scaling** | You manage scaling (Kubernetes HPA, instance count, etc.). | Temporal invokes additional instances as needed, within the compute provider's concurrency limits. | -| **Connection** | Persistent connection to Temporal. | Fresh connection on each invocation. | +| | Long-lived Worker | Serverless Worker | +| -------------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | +| **Lifecycle** | Long-lived process that runs continuously. | Invoked on demand. Starts and stops per invocation. | +| **Scaling** | You manage scaling (Kubernetes HPA, instance count, etc.). | Temporal invokes additional instances as needed, within the compute provider's concurrency limits. | +| **Connection** | Persistent connection to Temporal. | Fresh connection on each invocation. | ## Supported providers -| Provider | Status | -|---|---| +| Provider | Status | +| ---------- | --------- | | AWS Lambda | Available | ## Next steps - [Interactive demo](/evaluate/serverless-workers/demo) to explore the configuration and invocation flow. -- [How Serverless Workers work](/serverless-workers) for a deeper look at the invocation lifecycle, compute providers, and architecture. -- [Deploy a Serverless Worker](/production-deployment/worker-deployments/serverless-workers) for the end-to-end deployment guide. -- [Serverless Workers - Go SDK](/develop/go/workers/serverless-workers/aws-lambda) for SDK-specific configuration and defaults. +- [How Serverless Workers work](/serverless-workers) for a deeper look at the invocation lifecycle, compute providers, + and architecture. +- [Deploy a Serverless Worker](/production-deployment/worker-deployments/serverless-workers) for the end-to-end + deployment guide. +- [Serverless Workers - Go SDK](/develop/go/workers/serverless-workers/aws-lambda) for SDK-specific configuration and + defaults. diff --git a/vale/styles/config/vocabularies/Temporal/accept.txt b/vale/styles/config/vocabularies/Temporal/accept.txt index 264999c357..7982118437 100644 --- a/vale/styles/config/vocabularies/Temporal/accept.txt +++ b/vale/styles/config/vocabularies/Temporal/accept.txt @@ -7,7 +7,7 @@ sample samples attempt multiple -serverless +[Ss]erverless Namespace gRPC tctl From 2ff0f7c2016730a4f192963773bcf0cb4e381acc Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Tue, 28 Apr 2026 14:11:02 -0700 Subject: [PATCH 25/62] fix: darken interactive demo button in dark mode Co-Authored-By: Claude Opus 4.6 (1M context) --- src/components/elements/serverless-worker-demo.module.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/components/elements/serverless-worker-demo.module.css b/src/components/elements/serverless-worker-demo.module.css index 9922156327..6f09d0843c 100644 --- a/src/components/elements/serverless-worker-demo.module.css +++ b/src/components/elements/serverless-worker-demo.module.css @@ -157,10 +157,18 @@ transition: background 0.2s; } +:global(html[data-theme='dark']) .executeBtn { + background: #2563eb; +} + .executeBtn:hover:not(.executeBtnDisabled) { background: var(--ifm-color-primary-dark); } +:global(html[data-theme='dark']) .executeBtn:hover:not(.executeBtnDisabled) { + background: #1d4ed8; +} + .executeBtnDisabled { opacity: 0.65; cursor: not-allowed; From c2b027ad9b8da215f914b6891eb704c1f1627857 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Tue, 28 Apr 2026 14:30:15 -0700 Subject: [PATCH 26/62] docs: update interactive demo --- .../serverless-workers/aws-lambda.mdx | 1 - .../elements/ServerlessWorkerDemo.js | 5 ++-- .../serverless-worker-demo.module.css | 26 ++++++++++++++++++- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index dcf382041d..c661d8bc5a 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -313,7 +313,6 @@ The following parameters apply to all SDKs: | `TEMPORAL_TLS_CLIENT_KEY_PATH` | Path to the TLS client key file for mTLS authentication. | | `TEMPORAL_API_KEY` | API key for API key authentication. | -The SDKs read environment variables automatically at startup. For the full list, see [Client environment configuration](/references/client-environment-configuration). The serverless Worker packages read environment variables automatically at startup. For the full list, see [Client environment configuration](/references/client-environment-configuration). Sensitive values like TLS keys and API keys should be encrypted at rest. See [AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars-encryption.html) for options. diff --git a/src/components/elements/ServerlessWorkerDemo.js b/src/components/elements/ServerlessWorkerDemo.js index 66db759d67..d5717bd7aa 100644 --- a/src/components/elements/ServerlessWorkerDemo.js +++ b/src/components/elements/ServerlessWorkerDemo.js @@ -47,12 +47,11 @@ aws lambda create-function \\ --function-name ${lambdaFunctionName} \\ --runtime provided.al2023 \\ --handler bootstrap \\ - --architectures x86_64 \\ --role arn:aws:iam:::role/my-temporal-worker-execution \\ --zip-file fileb://function.zip \\ - --timeout 60 \\ + --timeout 600 \\ --memory-size 256 \\ - --environment "Variables={TEMPORAL_ADDRESS=${namespace}.tmprl.cloud:7233,TEMPORAL_NAMESPACE=${namespace}}"`; + --environment "Variables={HOME=/tmp,TEMPORAL_ADDRESS=${namespace}.tmprl.cloud:7233,TEMPORAL_NAMESPACE=${namespace},TEMPORAL_API_KEY=}"`; } function generateIamScript(config) { diff --git a/src/components/elements/serverless-worker-demo.module.css b/src/components/elements/serverless-worker-demo.module.css index 6f09d0843c..ac7b6919fc 100644 --- a/src/components/elements/serverless-worker-demo.module.css +++ b/src/components/elements/serverless-worker-demo.module.css @@ -138,6 +138,11 @@ border-color: var(--ifm-color-primary); } +:global(html[data-theme='dark']) .codeTabActive { + background: #2563eb; + border-color: #2563eb; +} + /* ── Execute button ─────────────────────────────────────────────────────── */ .executeBtn { @@ -370,11 +375,22 @@ box-shadow: 0 0 0 1px var(--ifm-color-primary); } +:global(html[data-theme='dark']) .stepActive { + border-color: #2563eb; + background: rgba(37, 99, 235, 0.12); + box-shadow: 0 0 0 1px #2563eb; +} + .stepActive:hover { border-color: var(--ifm-color-primary); background: var(--ifm-color-primary-lightest, rgba(55, 125, 255, 0.06)); } +:global(html[data-theme='dark']) .stepActive:hover { + border-color: #2563eb; + background: rgba(37, 99, 235, 0.18); +} + .stepNumber { flex-shrink: 0; width: 24px; @@ -395,6 +411,10 @@ background: var(--ifm-color-primary); } +:global(html[data-theme='dark']) .stepNumberActive { + background: #2563eb; +} + .stepContent { flex: 1; min-width: 0; @@ -408,7 +428,7 @@ .stepDesc { font-size: 0.78rem; - color: var(--ifm-font-color-secondary); + color: var(--ifm-font-color-base); line-height: 1.4; margin-top: 4px; } @@ -419,3 +439,7 @@ color: var(--ifm-color-primary); font-weight: 700; } + +:global(html[data-theme='dark']) .codeStepLabel { + color: #60a5fa; +} From 8f33a4073459017f6dad1b81efa6b625897aed61 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Tue, 28 Apr 2026 19:28:29 -0700 Subject: [PATCH 27/62] docs: use captioned image component --- .../workers/serverless-workers.mdx | 40 ++++++------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/docs/encyclopedia/workers/serverless-workers.mdx b/docs/encyclopedia/workers/serverless-workers.mdx index c15602b48d..9199ac3b6c 100644 --- a/docs/encyclopedia/workers/serverless-workers.mdx +++ b/docs/encyclopedia/workers/serverless-workers.mdx @@ -17,7 +17,7 @@ tags: - Serverless --- -import ThemedImage from '@theme/ThemedImage'; +import CaptionedImage from '@site/src/components/images/CaptionedImage'; This page covers the following: @@ -53,19 +53,12 @@ Temporal does not need to know anything about the Worker's infrastructure. With Serverless Workers, Temporal starts the Worker. -
- -
- Temporal's Worker Controller Instance invokes a Serverless Worker when Tasks arrive on a Task Queue with a compute - provider configured. -
-
+ Temporal's internal Worker Controller Instance (WCI) decides when to start, scale, and stop compute invocations. @@ -120,19 +113,12 @@ If both scale dynamically, the long-lived Workers may scale up to handle the sam A single Serverless Worker invocation has three phases: init, work, and shutdown. -
- -
- The shutdown deadline buffer controls when the Worker stops polling, and the Worker stop timeout controls how long - the Worker waits for in-flight Tasks to finish before shutdown hooks run. -
-
+ During the **init** phase, the Worker initializes and establishes a client connection to Temporal. From 067ec2b78e4d75a5f5bfd0ada082ea89404cc55e Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Wed, 29 Apr 2026 11:29:53 -0700 Subject: [PATCH 28/62] docs: address review feedback - versioning behavior, code fence, CaptionedImage - Mention worker-level default versioning behavior across all SDK pages - Fix missing Python OTel code fence - Update prerequisite to include worker-level default option - Replace ThemedImage with CaptionedImage on encyclopedia page - Add "not to scale" note to lifecycle diagram caption - Remove duplicate env vars sentence in deploy guide Co-Authored-By: Claude Opus 4.6 (1M context) --- .../develop/go/workers/serverless-workers/aws-lambda.mdx | 3 ++- .../python/workers/serverless-workers/aws-lambda.mdx | 4 +++- docs/encyclopedia/workers/serverless-workers.mdx | 2 +- .../worker-deployments/serverless-workers/aws-lambda.mdx | 9 +++++---- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx index c4f9485291..54621a4b61 100644 --- a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx @@ -59,7 +59,8 @@ func main() { The `WorkerDeploymentVersion` is required. Worker Deployment Versioning is always enabled for Serverless Workers. -Each Workflow must declare a [versioning behavior](/worker-versioning#versioning-behaviors) at registration time, either `AutoUpgrade` or `Pinned`. +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`. The `Options` callback gives you access to the same registration methods you use with a traditional Worker: `RegisterWorkflow`, `RegisterWorkflowWithOptions`, `RegisterActivity`, `RegisterActivityWithOptions`, and `RegisterNexusService`. diff --git a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx index c6ede1d6c7..21e44114f4 100644 --- a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx @@ -62,7 +62,8 @@ Worker Versioning is required for Serverless Workers. The `configure` callback receives a `LambdaWorkerConfig` dataclass with fields pre-populated with Lambda-appropriate defaults. Set the Task Queue, Workflows, and Activities through `worker_config`, which accepts the same keyword arguments as the `Worker` constructor. -Each Workflow registered with the Worker must declare a [versioning behavior](/worker-versioning#versioning-behaviors) in the `@workflow.defn` decorator, either `PINNED` or `AUTO_UPGRADE`: +Each Workflow must have a [versioning behavior](/worker-versioning#versioning-behaviors), either `PINNED` or `AUTO_UPGRADE`. +Set it per-Workflow in the `@workflow.defn` decorator, or set a worker-level default with `default_versioning_behavior` in the worker config. ```python {5} from temporalio import workflow @@ -128,6 +129,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/observability) and the [SDK metrics reference](/references/sdk-metrics). +```python from temporalio.common import WorkerDeploymentVersion from temporalio.contrib.aws.lambda_worker import LambdaWorkerConfig, run_worker from temporalio.contrib.aws.lambda_worker.otel import apply_defaults diff --git a/docs/encyclopedia/workers/serverless-workers.mdx b/docs/encyclopedia/workers/serverless-workers.mdx index 9199ac3b6c..4f37406c2c 100644 --- a/docs/encyclopedia/workers/serverless-workers.mdx +++ b/docs/encyclopedia/workers/serverless-workers.mdx @@ -195,7 +195,7 @@ With single-slot configuration, each Activity gets a dedicated execution environ | Activity duration | Must complete within the compute provider's invocation limit (minus shutdown deadline buffer). For AWS Lambda, the maximum is 15 minutes. | | Workflow duration | No limit. Workflows of any duration work, regardless of the invocation timeout. A Workflow runs across as many invocations 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 declare `AutoUpgrade` or `Pinned` behavior. | +| 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. | ## Compute providers {#compute-providers} diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index c661d8bc5a..d20809bb4e 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -30,7 +30,7 @@ This guide walks through deploying a Temporal [Serverless Worker](/serverless-wo - For self-hosted deployments, complete the [self-hosted setup](/production-deployment/worker-deployments/serverless-workers/self-hosted-setup) before following this guide. -- Every Workflow must declare a [versioning behavior](/worker-versioning#versioning-behaviors). +- Every Workflow must declare a [versioning behavior](/worker-versioning#versioning-behaviors), or the Worker must set a default versioning behavior. - An AWS account with permissions to create and invoke Lambda functions and create IAM roles. - 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. @@ -89,8 +89,8 @@ func main() { } ``` -Each Workflow must declare a [versioning behavior](/worker-versioning#versioning-behaviors) at registration time, either -`AutoUpgrade` or `Pinned`. +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 - Go SDK](/develop/go/workers/serverless-workers/aws-lambda). @@ -123,7 +123,8 @@ lambda_handler = run_worker( ) ``` -Each Workflow must declare a [versioning behavior](/worker-versioning#versioning-behaviors) in the `@workflow.defn` decorator, either `PINNED` or `AUTO_UPGRADE`: +Each Workflow must have a [versioning behavior](/worker-versioning#versioning-behaviors), either `PINNED` or `AUTO_UPGRADE`. +Set it per-Workflow in the `@workflow.defn` decorator, or set a worker-level default with `default_versioning_behavior` in the worker config. ```python from temporalio import workflow From e68e7b0bee58c2c15010fba3d2a696a3b0bba391 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Wed, 29 Apr 2026 11:49:33 -0700 Subject: [PATCH 29/62] docs: add Python lambda-worker-otel optional dependency note Co-Authored-By: Claude Opus 4.6 (1M context) --- .../worker-deployments/serverless-workers/aws-lambda.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index d20809bb4e..3a3ae50adb 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -202,6 +202,8 @@ Install dependencies into a local directory for packaging. Use `--platform` to f pip install --target ./package --platform manylinux2014_x86_64 --only-binary=:all: temporalio ``` +To include [OpenTelemetry support](/develop/python/workers/serverless-workers/aws-lambda#add-observability), install `temporalio[lambda-worker-otel]` instead. + Package the dependencies and your application code into a zip file: ```bash From 406fd3a2504dcde628b2e6a521f41589bf1cd9c4 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Wed, 29 Apr 2026 12:08:15 -0700 Subject: [PATCH 30/62] docs: use JSON syntax for --environment to avoid parsing errors The shorthand Variables={} syntax fails when values contain colons or periods, which Temporal addresses always have. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/develop/go/workers/serverless-workers/aws-lambda.mdx | 8 ++++++++ .../worker-deployments/serverless-workers/aws-lambda.mdx | 6 +++--- src/components/elements/ServerlessWorkerDemo.js | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx index 54621a4b61..4c1883809c 100644 --- a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx @@ -68,6 +68,14 @@ 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: + +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} diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 3a3ae50adb..3efb169154 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -247,7 +247,7 @@ aws lambda create-function \ --zip-file fileb://function.zip \ --timeout 600 \ --memory-size 256 \ - --environment "Variables={HOME=/tmp,TEMPORAL_ADDRESS=:7233,TEMPORAL_NAMESPACE=,TEMPORAL_API_KEY=}" + --environment '{"Variables":{"HOME":"/tmp","TEMPORAL_ADDRESS":":7233","TEMPORAL_NAMESPACE":"","TEMPORAL_API_KEY":""}}' ``` | Parameter | Description | @@ -268,7 +268,7 @@ aws lambda create-function \ --zip-file fileb://function.zip \ --timeout 600 \ --memory-size 256 \ - --environment "Variables={TEMPORAL_ADDRESS=:7233,TEMPORAL_NAMESPACE=,TEMPORAL_API_KEY=}" + --environment '{"Variables":{"TEMPORAL_ADDRESS":":7233","TEMPORAL_NAMESPACE":"","TEMPORAL_API_KEY":""}}' ``` | Parameter | Description | @@ -289,7 +289,7 @@ aws lambda create-function \ --zip-file fileb://function.zip \ --timeout 600 \ --memory-size 256 \ - --environment "Variables={HOME=/tmp,TEMPORAL_ADDRESS=:7233,TEMPORAL_NAMESPACE=,TEMPORAL_API_KEY=}" + --environment '{"Variables":{"HOME":"/tmp","TEMPORAL_ADDRESS":":7233","TEMPORAL_NAMESPACE":"","TEMPORAL_API_KEY":""}}' ``` | Parameter | Description | diff --git a/src/components/elements/ServerlessWorkerDemo.js b/src/components/elements/ServerlessWorkerDemo.js index d5717bd7aa..850f320c21 100644 --- a/src/components/elements/ServerlessWorkerDemo.js +++ b/src/components/elements/ServerlessWorkerDemo.js @@ -51,7 +51,7 @@ aws lambda create-function \\ --zip-file fileb://function.zip \\ --timeout 600 \\ --memory-size 256 \\ - --environment "Variables={HOME=/tmp,TEMPORAL_ADDRESS=${namespace}.tmprl.cloud:7233,TEMPORAL_NAMESPACE=${namespace},TEMPORAL_API_KEY=}"`; + --environment '{"Variables":{"HOME":"/tmp","TEMPORAL_ADDRESS":"${namespace}.tmprl.cloud:7233","TEMPORAL_NAMESPACE":"${namespace}","TEMPORAL_API_KEY":""}}'`; } function generateIamScript(config) { From 4675ee2e7f0f36daa8166c75d1723484f7f18aca Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Wed, 29 Apr 2026 12:18:09 -0700 Subject: [PATCH 31/62] docs: clarify IAM role and External ID in deploy guide - Clarify which role to use in create-version step (not execution role or user IAM role) - Fix External ID description: user-chosen, not provided by Temporal Cloud - Add Go config file resolution order to match Python and TS pages Co-Authored-By: Claude Opus 4.6 (1M context) --- .../serverless-workers/aws-lambda.mdx | 10 +++++----- .../files/temporal-cloud-serverless-worker-role.yaml | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 3efb169154..b8f60eea00 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -343,7 +343,7 @@ Deploy the following CloudFormation template to create the invocation role and i | Parameter | Description | | ---------------------- | ---------------------------------------------------------------------------------------------------------------------- | -| `AssumeRoleExternalId` | A unique identifier that Temporal Cloud presents when assuming the role. Provided in your Namespace configuration. | +| `AssumeRoleExternalId` | 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. | | `LambdaFunctionARNs` | Comma-separated list of Lambda function ARNs that Temporal may invoke. One role can authorize multiple Worker Lambdas. | | `RoleName` | Base name for the created IAM role. Defaults to `Temporal-Cloud-Serverless-Worker`. | @@ -359,7 +359,7 @@ Description: Parameters: AssumeRoleExternalId: Type: String - Description: The External ID provided by Temporal Cloud + Description: A string you choose. Can be any value. AllowedPattern: '[a-zA-Z0-9_+=,.@-]*' MinLength: 5 MaxLength: 45 @@ -388,7 +388,7 @@ Metadata: - RoleName ParameterLabels: AssumeRoleExternalId: - default: 'External ID (provided by Temporal Cloud)' + default: 'External ID' LambdaFunctionARNs: default: 'Lambda Function ARNs (comma-separated list)' RoleName: @@ -493,7 +493,7 @@ You can create the version using the Temporal UI or the Temporal CLI. your Worker code. 5. Under **Compute**, select **AWS Lambda** and provide: - **Lambda ARN**: the ARN of your Lambda function. - - **IAM Role ARN**: the role ARN from [Step 3](#configure-iam) (output of the CloudFormation stack). + - **IAM Role ARN**: the role ARN from [Step 3](#configure-iam) (output of the CloudFormation stack). This is not the Lambda execution role from [Step 2](#deploy-lambda-function) or your own IAM user/role. - **External ID**: the same value you passed to the CloudFormation template. 6. Click **Save**. @@ -531,7 +531,7 @@ temporal worker deployment create-version \ | `--deployment-name` | Worker Deployment name. Must match `DeploymentName` in your Worker code. | | `--build-id` | Worker Deployment Version build ID. Must match `BuildID` in your Worker code. | | `--aws-lambda-function-arn` | ARN of the Lambda function Temporal invokes for this version. | -| `--aws-lambda-assume-role-arn` | IAM role Temporal assumes to invoke the function. This is the `RoleARN` output from the CloudFormation stack in [Step 3](#configure-iam). | +| `--aws-lambda-assume-role-arn` | IAM role Temporal assumes to invoke the function. This is the `RoleARN` output from the CloudFormation stack in [Step 3](#configure-iam). This is not the Lambda execution role from [Step 2](#deploy-lambda-function) or your own IAM user/role. | | `--aws-lambda-assume-role-external-id` | External ID configured in the IAM role trust policy. | diff --git a/static/files/temporal-cloud-serverless-worker-role.yaml b/static/files/temporal-cloud-serverless-worker-role.yaml index 4b5546a5fb..f3cfd18aea 100644 --- a/static/files/temporal-cloud-serverless-worker-role.yaml +++ b/static/files/temporal-cloud-serverless-worker-role.yaml @@ -5,7 +5,7 @@ Description: Creates an IAM role that Temporal Cloud can assume to invoke multip Parameters: AssumeRoleExternalId: Type: String - Description: The External ID provided by Temporal Cloud + Description: A string you choose. Can be any value. AllowedPattern: '[a-zA-Z0-9_+=,.@-]*' MinLength: 5 MaxLength: 45 @@ -34,7 +34,7 @@ Metadata: - RoleName ParameterLabels: AssumeRoleExternalId: - default: "External ID (provided by Temporal Cloud)" + default: "External ID" LambdaFunctionARNs: default: "Lambda Function ARNs (comma-separated list)" RoleName: From e40086c101d0d4e74995469a5992124b47e4f3bf Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Wed, 29 Apr 2026 12:22:27 -0700 Subject: [PATCH 32/62] docs: add AWS namespace prerequisite for Lambda deploy guide Co-Authored-By: Claude Opus 4.6 (1M context) --- .../worker-deployments/serverless-workers/aws-lambda.mdx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index b8f60eea00..006ba18054 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -26,7 +26,8 @@ This guide walks through deploying a Temporal [Serverless Worker](/serverless-wo ## Prerequisites {#prerequisites} -- A Temporal Cloud account or a self-hosted Temporal Service vx.xx.x or later. +- A Temporal Cloud account with an AWS-hosted Namespace, or a self-hosted Temporal Service vx.xx.x or later. + The Namespace's cloud provider must match the serverless compute provider. - For self-hosted deployments, complete the [self-hosted setup](/production-deployment/worker-deployments/serverless-workers/self-hosted-setup) before following this guide. From d1df952506b485a0e398da4ff281f197db1b42a6 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Wed, 29 Apr 2026 12:40:03 -0700 Subject: [PATCH 33/62] add links to quickstart --- .../serverless-workers/aws-lambda.mdx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 006ba18054..0981739316 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -41,16 +41,34 @@ This guide walks through deploying a Temporal [Serverless Worker](/serverless-wo - The [Go SDK](/develop/go) (`go.temporal.io/sdk`) +:::tip + +If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample Workflows and Activities from the [Go Quickstart](/develop/go/set-up). The Worker code samples on this page already set a default versioning behavior, so you don't need to modify the Workflow or Activity code. + +::: +
- The [Python SDK](/develop/python) (`temporalio`) +:::tip + +If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample Workflows and Activities from the [Python Quickstart](/develop/python/set-up). The Worker code samples on this page already set a default versioning behavior, so you don't need to modify the Workflow or Activity code. + +::: + - The [TypeScript SDK](/develop/typescript) (`@temporalio/lambda-worker`) +:::tip + +If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample Workflows and Activities from the [TypeScript Quickstart](/develop/typescript/set-up). The Worker code samples on this page already set a default versioning behavior, so you don't need to modify the Workflow or Activity code. + +::: +
From 2d4e8b4da269a9f3e67eb3db6ab0cc10862d9fb9 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Wed, 29 Apr 2026 13:01:55 -0700 Subject: [PATCH 34/62] update execution role arn parameter table --- .../worker-deployments/serverless-workers/aws-lambda.mdx | 6 +++--- src/components/elements/ServerlessWorkerDemo.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 0981739316..682bab44b6 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -262,7 +262,7 @@ aws lambda create-function \ --function-name my-temporal-worker \ --runtime provided.al2023 \ --handler bootstrap \ - --role arn:aws:iam:::role/my-temporal-worker-execution \ + --role \ --zip-file fileb://function.zip \ --timeout 600 \ --memory-size 256 \ @@ -283,7 +283,7 @@ aws lambda create-function \ --function-name my-temporal-worker \ --runtime python3.13 \ --handler lambda_function.lambda_handler \ - --role arn:aws:iam:::role/my-temporal-worker-execution \ + --role \ --zip-file fileb://function.zip \ --timeout 600 \ --memory-size 256 \ @@ -304,7 +304,7 @@ aws lambda create-function \ --function-name my-temporal-worker \ --runtime nodejs22.x \ --handler lib/index.handler \ - --role arn:aws:iam:::role/my-temporal-worker-execution \ + --role \ --zip-file fileb://function.zip \ --timeout 600 \ --memory-size 256 \ diff --git a/src/components/elements/ServerlessWorkerDemo.js b/src/components/elements/ServerlessWorkerDemo.js index 850f320c21..1cc4aa69a8 100644 --- a/src/components/elements/ServerlessWorkerDemo.js +++ b/src/components/elements/ServerlessWorkerDemo.js @@ -47,7 +47,7 @@ aws lambda create-function \\ --function-name ${lambdaFunctionName} \\ --runtime provided.al2023 \\ --handler bootstrap \\ - --role arn:aws:iam:::role/my-temporal-worker-execution \\ + --role \\ --zip-file fileb://function.zip \\ --timeout 600 \\ --memory-size 256 \\ From 39726d453b27b4e4678c48cdff9cf6c2732c3f41 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Wed, 29 Apr 2026 13:15:08 -0700 Subject: [PATCH 35/62] docs: add links to samples --- .../serverless-workers/aws-lambda.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 682bab44b6..22866cf03e 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -43,7 +43,7 @@ This guide walks through deploying a Temporal [Serverless Worker](/serverless-wo :::tip -If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample Workflows and Activities from the [Go Quickstart](/develop/go/set-up). The Worker code samples on this page already set a default versioning behavior, so you don't need to modify the Workflow or Activity code. +If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample Workflows and Activities from the [Go Lambda Worker sample](https://github.com/temporalio/samples-go/tree/main/lambda-worker). The Worker code samples on this page already set a default versioning behavior, so you don't need to modify the Workflow or Activity code. ::: @@ -54,7 +54,7 @@ If you are just exploring the Serverless Worker feature and don't have a Workflo :::tip -If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample Workflows and Activities from the [Python Quickstart](/develop/python/set-up). The Worker code samples on this page already set a default versioning behavior, so you don't need to modify the Workflow or Activity code. +If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample Workflows and Activities from the [Python Lambda Worker sample](https://github.com/temporalio/samples-python/tree/main/lambda_worker). The Worker code samples on this page already set a default versioning behavior, so you don't need to modify the Workflow or Activity code. ::: @@ -65,7 +65,7 @@ If you are just exploring the Serverless Worker feature and don't have a Workflo :::tip -If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample Workflows and Activities from the [TypeScript Quickstart](/develop/typescript/set-up). The Worker code samples on this page already set a default versioning behavior, so you don't need to modify the Workflow or Activity code. +If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample Workflows and Activities from the [TypeScript Lambda Worker sample](https://github.com/temporalio/samples-typescript/tree/main/lambda-worker). The Worker code samples on this page already set a default versioning behavior, so you don't need to modify the Workflow or Activity code. ::: @@ -540,8 +540,8 @@ temporal worker deployment create-version \ --namespace \ --deployment-name my-app \ --build-id build-1 \ - --aws-lambda-function-arn arn:aws:lambda:::function:my-temporal-worker \ - --aws-lambda-assume-role-arn arn:aws:iam:::role/ \ + --aws-lambda-function-arn \ + --aws-lambda-assume-role-arn \ --aws-lambda-assume-role-external-id ``` From 89fe42ab22877cd28c94131a678563a6aee5343e Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Wed, 29 Apr 2026 13:16:40 -0700 Subject: [PATCH 36/62] remove redundant sentence --- .../worker-deployments/serverless-workers/aws-lambda.mdx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 22866cf03e..4223bb329d 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -43,8 +43,7 @@ This guide walks through deploying a Temporal [Serverless Worker](/serverless-wo :::tip -If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample Workflows and Activities from the [Go Lambda Worker sample](https://github.com/temporalio/samples-go/tree/main/lambda-worker). The Worker code samples on this page already set a default versioning behavior, so you don't need to modify the Workflow or Activity code. - +If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample Workflows and Activities from the [Go Lambda Worker sample](https://github.com/temporalio/samples-go/tree/main/lambda-worker). ::: @@ -54,8 +53,7 @@ If you are just exploring the Serverless Worker feature and don't have a Workflo :::tip -If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample Workflows and Activities from the [Python Lambda Worker sample](https://github.com/temporalio/samples-python/tree/main/lambda_worker). The Worker code samples on this page already set a default versioning behavior, so you don't need to modify the Workflow or Activity code. - +If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample Workflows and Activities from the [Python Lambda Worker sample](https://github.com/temporalio/samples-python/tree/main/lambda_worker). ::: @@ -65,8 +63,7 @@ If you are just exploring the Serverless Worker feature and don't have a Workflo :::tip -If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample Workflows and Activities from the [TypeScript Lambda Worker sample](https://github.com/temporalio/samples-typescript/tree/main/lambda-worker). The Worker code samples on this page already set a default versioning behavior, so you don't need to modify the Workflow or Activity code. - +If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample Workflows and Activities from the [TypeScript Lambda Worker sample](https://github.com/temporalio/samples-typescript/tree/main/lambda-worker). :::
From 8a31a51da36b3e31347335baa1269b1a3b841386 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Wed, 29 Apr 2026 13:53:21 -0700 Subject: [PATCH 37/62] use multi-line command in self-hosted guide --- .../serverless-workers/self-hosted-setup.mdx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx b/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx index 39ad4a041a..e490448e26 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx @@ -103,7 +103,15 @@ Deploy the following CloudFormation template to create the role. command below and run it in your terminal: ```bash -aws cloudformation create-stack --stack-name temporal-serverless-worker --template-body file://temporal-self-hosted-serverless-worker-role.yaml --parameters ParameterKey=TemporalIamRoleArn,ParameterValue= ParameterKey=AssumeRoleExternalId,ParameterValue= ParameterKey=LambdaFunctionARNs,ParameterValue='""' --capabilities CAPABILITY_NAMED_IAM --region +aws cloudformation create-stack \ + --stack-name temporal-serverless-worker \ + --template-body file://temporal-self-hosted-serverless-worker-role.yaml \ + --parameters \ + ParameterKey=TemporalIamRoleArn,ParameterValue= \ + ParameterKey=AssumeRoleExternalId,ParameterValue= \ + ParameterKey=LambdaFunctionARNs,ParameterValue='""' \ + --capabilities CAPABILITY_NAMED_IAM \ + --region ``` | Parameter | Description | @@ -198,7 +206,11 @@ Outputs: After the stack finishes creating, retrieve the IAM role ARN from the stack outputs: ```bash -aws cloudformation describe-stacks --stack-name temporal-serverless-worker --query 'Stacks[0].Outputs[?OutputKey==`RoleARN`].OutputValue' --output text --region +aws cloudformation describe-stacks \ + --stack-name temporal-serverless-worker \ + --query 'Stacks[0].Outputs[?OutputKey==`RoleARN`].OutputValue' \ + --output text \ + --region ``` Use this role ARN when creating the Worker Deployment Version. From 496a321c40163371200077979f1d8311eb62bac4 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Wed, 29 Apr 2026 15:54:28 -0700 Subject: [PATCH 38/62] add validate connection step --- .../worker-deployments/serverless-workers/aws-lambda.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 4223bb329d..fc9abc3779 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -553,6 +553,8 @@ temporal worker deployment create-version \ +To verify that Temporal can reach your Lambda function, go to **Workers** > **Deployments** > select your deployment > open the **Actions** menu on the version and click **Validate Connection**. This checks that Temporal can assume the IAM role and invoke the function. + ## 5. Set version as current {#set-current-version} If you created the version through the Temporal UI, the version is already current and you can skip this step. From 19a49aeb1edcb9b86b180f946421678b41dd3337 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Wed, 29 Apr 2026 18:01:29 -0700 Subject: [PATCH 39/62] uses pinned versioning behavior; uses snipsync to sync code snippets --- .../workers/serverless-workers/aws-lambda.mdx | 87 +++++++++------ docs/develop/python/nexus/feature-guide.mdx | 2 +- .../workers/serverless-workers/aws-lambda.mdx | 100 ++++++++++-------- .../typescript/integrations/ai-sdk.mdx | 1 - .../workers/serverless-workers/aws-lambda.mdx | 71 ++++++++----- .../serverless-workers/aws-lambda.mdx | 4 +- 6 files changed, 157 insertions(+), 108 deletions(-) diff --git a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx index 4c1883809c..8d9cf84aac 100644 --- a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx @@ -31,11 +31,16 @@ For a full end-to-end deployment guide covering AWS IAM setup, compute configura Use the `RunWorker` function to start a Lambda-based Worker. Pass a `WorkerDeploymentVersion` and a callback that registers your Workflows and Activities. + +[samples-go/lambda-worker/worker/main.go](https://github.com/temporalio/samples-go/blob/lambda-worker/samples-go/lambda-worker/worker/main.go) ```go package main import ( + greeting "github.com/temporalio/samples-go/lambda-worker/greeting" + lambdaworker "go.temporal.io/sdk/contrib/aws/lambdaworker" +// ... "go.temporal.io/sdk/worker" "go.temporal.io/sdk/workflow" ) @@ -45,17 +50,20 @@ func main() { DeploymentName: "my-app", BuildID: "build-1", }, func(opts *lambdaworker.Options) error { - opts.TaskQueue = "my-task-queue" + opts.TaskQueue = "serverless-task-queue-1" + +// ... - opts.RegisterWorkflowWithOptions(MyWorkflow, workflow.RegisterOptions{ - VersioningBehavior: workflow.VersioningBehaviorAutoUpgrade, + opts.RegisterWorkflowWithOptions(greeting.SampleWorkflow, workflow.RegisterOptions{ + VersioningBehavior: workflow.VersioningBehaviorPinned, }) - opts.RegisterActivity(MyActivity) + opts.RegisterActivity(greeting.HelloActivity) return nil }) } ``` + The `WorkerDeploymentVersion` is required. Worker Deployment Versioning is always enabled for Serverless Workers. @@ -117,8 +125,14 @@ 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/observability) and the [SDK metrics reference](/references/sdk-metrics). + +[samples-go/lambda-worker/worker/main.go](https://github.com/temporalio/samples-go/blob/lambda-worker/samples-go/lambda-worker/worker/main.go) ```go +package main + import ( + greeting "github.com/temporalio/samples-go/lambda-worker/greeting" + lambdaworker "go.temporal.io/sdk/contrib/aws/lambdaworker" otel "go.temporal.io/sdk/contrib/aws/lambdaworker/otel" "go.temporal.io/sdk/worker" @@ -130,21 +144,22 @@ func main() { DeploymentName: "my-app", BuildID: "build-1", }, func(opts *lambdaworker.Options) error { - opts.TaskQueue = "my-task-queue" + opts.TaskQueue = "serverless-task-queue-1" if err := otel.ApplyDefaults(opts, &opts.ClientOptions, otel.Options{}); err != nil { return err } - opts.RegisterWorkflowWithOptions(MyWorkflow, workflow.RegisterOptions{ - VersioningBehavior: workflow.VersioningBehaviorAutoUpgrade, + opts.RegisterWorkflowWithOptions(greeting.SampleWorkflow, workflow.RegisterOptions{ + VersioningBehavior: workflow.VersioningBehaviorPinned, }) - opts.RegisterActivity(MyActivity) + opts.RegisterActivity(greeting.HelloActivity) return nil }) } ``` + `ApplyDefaults` configures both metrics and tracing. By default, telemetry is sent to `localhost:4317`, which is the ADOT Lambda layer's default collector endpoint. @@ -157,36 +172,46 @@ The default Collector configuration does not route OpenTelemetry Protocol (OTLP) 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: + +[samples-go/lambda-worker/otel-collector-config.yaml](https://github.com/temporalio/samples-go/blob/lambda-worker/samples-go/lambda-worker/otel-collector-config.yaml) ```yaml receivers: - otlp: - protocols: - grpc: - endpoint: 'localhost:4317' - http: - endpoint: 'localhost:4318' + otlp: + protocols: + grpc: + endpoint: "localhost:4317" + http: + endpoint: "localhost:4318" exporters: - debug: - awsxray: - region: - awsemf: - namespace: TemporalWorkerMetrics - log_group_name: /aws/lambda/ - region: - dimension_rollup_option: NoDimensionRollup - resource_to_telemetry_conversion: - enabled: true + debug: + awsxray: + region: us-west-2 + awsemf: + # AWS EMF exporter for metrics + # These are example configurations + 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] + 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: diff --git a/docs/develop/python/nexus/feature-guide.mdx b/docs/develop/python/nexus/feature-guide.mdx index afad0f58d9..442e212079 100644 --- a/docs/develop/python/nexus/feature-guide.mdx +++ b/docs/develop/python/nexus/feature-guide.mdx @@ -221,7 +221,7 @@ Workflow IDs should typically be business-meaningful IDs and are used to dedupe A Nexus Operation can only take one input parameter. If you want a Nexus Operation to start a Workflow that takes multiple arguments use the `ctx.start_workflow` method. -[nexus_multiple_args/handler/service_handler.py](https://github.com/temporalio/samples-python/blob/main/nexus_multiple_args/handler/service_handler.py) +[nexus_multiple_args/handler/service_handler.py](https://github.com/temporalio/samples-python/blob/lambda-worker/nexus_multiple_args/handler/service_handler.py) ```py @nexusrpc.handler.service_handler(service=MyNexusService) class MyNexusServiceHandler: diff --git a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx index 21e44114f4..35fbe1051e 100644 --- a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx @@ -31,28 +31,29 @@ For a full end-to-end deployment guide covering AWS IAM setup, compute configura Use the `run_worker` function to create a Lambda handler that runs a Temporal Worker. Pass a `WorkerDeploymentVersion` and a configure callback that registers your Workflows and Activities. -```python {14-20} + +[lambda_worker/lambda_function.py](https://github.com/temporalio/samples-python/blob/lambda-worker/lambda_worker/lambda_function.py) +```py {15-18} +from activities import hello_activity from temporalio.common import WorkerDeploymentVersion from temporalio.contrib.aws.lambda_worker import LambdaWorkerConfig, run_worker - -from my_workflows import MyWorkflow -from my_activities import my_activity +# ... +from workflows import TASK_QUEUE, SampleWorkflow def configure(config: LambdaWorkerConfig) -> None: - config.worker_config["task_queue"] = "my-task-queue" - config.worker_config["workflows"] = [MyWorkflow] - config.worker_config["activities"] = [my_activity] + config.worker_config["task_queue"] = TASK_QUEUE + config.worker_config["workflows"] = [SampleWorkflow] + config.worker_config["activities"] = [hello_activity] +# ... lambda_handler = run_worker( - WorkerDeploymentVersion( - deployment_name="my-app", - build_id="build-1", - ), + WorkerDeploymentVersion(deployment_name="my-app", build_id="build-1"), configure, ) ``` + `run_worker` takes a `WorkerDeploymentVersion` and a configure callback, and returns a Lambda handler. The `WorkerDeploymentVersion` identifies the [Worker Deployment](/worker-versioning#worker-deployments) and [Build ID](/worker-versioning#build-id) for this Worker. @@ -129,30 +130,29 @@ 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/observability) and the [SDK metrics reference](/references/sdk-metrics). -```python + +[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 from temporalio.common import WorkerDeploymentVersion from temporalio.contrib.aws.lambda_worker import LambdaWorkerConfig, run_worker from temporalio.contrib.aws.lambda_worker.otel import apply_defaults - -from my_workflows import MyWorkflow -from my_activities import my_activity +from workflows import TASK_QUEUE, SampleWorkflow def configure(config: LambdaWorkerConfig) -> None: - config.worker_config["task_queue"] = "my-task-queue" - config.worker_config["workflows"] = [MyWorkflow] - config.worker_config["activities"] = [my_activity] + config.worker_config["task_queue"] = TASK_QUEUE + config.worker_config["workflows"] = [SampleWorkflow] + config.worker_config["activities"] = [hello_activity] apply_defaults(config) lambda_handler = run_worker( - WorkerDeploymentVersion( - deployment_name="my-app", - build_id="build-1", - ), + WorkerDeploymentVersion(deployment_name="my-app", build_id="build-1"), configure, ) ``` + `apply_defaults` configures both metrics and tracing. By default, telemetry is sent to `localhost:4317`, which is the ADOT Lambda layer's default collector endpoint. @@ -164,36 +164,46 @@ The default Collector configuration does not route OpenTelemetry Protocol (OTLP) 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](https://github.com/temporalio/samples-python/blob/lambda-worker/lambda_worker/otel-collector-config.yaml) ```yaml receivers: - otlp: - protocols: - grpc: - endpoint: 'localhost:4317' - http: - endpoint: 'localhost:4318' + otlp: + protocols: + grpc: + endpoint: "localhost:4317" + http: + endpoint: "localhost:4318" exporters: - debug: - awsxray: - region: - awsemf: - namespace: TemporalWorkerMetrics - log_group_name: /aws/lambda/ - region: - dimension_rollup_option: NoDimensionRollup - resource_to_telemetry_conversion: - enabled: true + debug: + awsxray: + region: us-west-2 + awsemf: + # AWS EMF exporter for metrics + # These are example configurations + 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] + pipelines: + traces: + receivers: [otlp] + exporters: [awsxray, debug] + metrics: + receivers: [otlp] + exporters: [awsemf] + telemetry: + logs: + level: debug + metrics: + address: localhost:8888 ``` + Set the following environment variables on the Lambda function: diff --git a/docs/develop/typescript/integrations/ai-sdk.mdx b/docs/develop/typescript/integrations/ai-sdk.mdx index 2315d0f8f8..9ad7acde0a 100644 --- a/docs/develop/typescript/integrations/ai-sdk.mdx +++ b/docs/develop/typescript/integrations/ai-sdk.mdx @@ -164,7 +164,6 @@ from the tool function. The following is an example of an Activity that gets the export async function getWeather(input: { location: string; }): Promise<{ city: string; temperatureRange: string; conditions: string }> { - console.log('Activity execution'); return { city: input.location, temperatureRange: '14-20C', diff --git a/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx b/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx index dce08ac844..022df8f2ae 100644 --- a/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx @@ -31,21 +31,24 @@ 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. -```typescript + +[samples-typescript/lambda-worker/src/index.ts](https://github.com/temporalio/samples-typescript/blob/lambda-worker/samples-typescript/lambda-worker/src/index.ts) +```ts import { runWorker } from '@temporalio/lambda-worker'; +// ... import * as activities from './activities'; - -export const handler = runWorker( - { deploymentName: 'my-app', buildId: 'build-1' }, - (config) => { - config.workerOptions.taskQueue = 'my-task-queue'; - config.workerOptions.workflowBundle = { - codePath: require.resolve('./workflow-bundle.js'), - }; - config.workerOptions.activities = activities; - }, -); +import { TASK_QUEUE } from './workflows'; + +export const handler = runWorker({ deploymentName: 'sdk-demo', buildId: 'v1' }, (config) => { + config.workerOptions.taskQueue = TASK_QUEUE; + config.workerOptions.workflowBundle = { + codePath: require.resolve('./workflow-bundle.js'), + }; + config.workerOptions.activities = activities; +// ... +}); ``` + The deployment version is required. Worker Deployment Versioning is always enabled for Serverless Workers. @@ -120,23 +123,24 @@ 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/observability) and the [SDK metrics reference](/references/sdk-metrics). -```typescript + +[samples-typescript/lambda-worker/src/index.ts](https://github.com/temporalio/samples-typescript/blob/lambda-worker/samples-typescript/lambda-worker/src/index.ts) +```ts import { runWorker } from '@temporalio/lambda-worker'; import { applyDefaults } from '@temporalio/lambda-worker/otel'; import * as activities from './activities'; - -export const handler = runWorker( - { deploymentName: 'my-app', buildId: 'build-1' }, - (config) => { - config.workerOptions.taskQueue = 'my-task-queue'; - config.workerOptions.workflowBundle = { - codePath: require.resolve('./workflow-bundle.js'), - }; - config.workerOptions.activities = activities; - applyDefaults(config); - }, -); +import { TASK_QUEUE } from './workflows'; + +export const handler = runWorker({ deploymentName: 'sdk-demo', buildId: 'v1' }, (config) => { + config.workerOptions.taskQueue = TASK_QUEUE; + config.workerOptions.workflowBundle = { + codePath: require.resolve('./workflow-bundle.js'), + }; + config.workerOptions.activities = activities; + applyDefaults(config); +}); ``` + `applyDefaults` registers Temporal SDK interceptors for tracing and configures the Core SDK to export metrics via OpenTelemetry Protocol (OTLP). By default, telemetry is sent to `localhost:4317`, which is the ADOT Lambda layer's default collector endpoint. @@ -150,6 +154,8 @@ The default Collector configuration does not route OTLP data to the traces pipel 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: + +[samples-typescript/lambda-worker/otel-collector-config.yaml](https://github.com/temporalio/samples-typescript/blob/lambda-worker/samples-typescript/lambda-worker/otel-collector-config.yaml) ```yaml receivers: otlp: @@ -162,11 +168,14 @@ receivers: exporters: debug: awsxray: - region: + region: us-west-2 awsemf: + # AWS EMF exporter for metrics + # These are example configurations namespace: TemporalWorkerMetrics - log_group_name: /aws/lambda/ - region: + # log_group_name: /aws/lambda/ + log_group_name: /aws/lambda/sdk-worker-typescript + region: us-west-2 dimension_rollup_option: NoDimensionRollup resource_to_telemetry_conversion: enabled: true @@ -179,7 +188,13 @@ service: metrics: receivers: [otlp] exporters: [awsemf] + telemetry: + logs: + level: debug + metrics: + address: localhost:8888 ``` + Set the following environment variables on the Lambda function: diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index fc9abc3779..077d5b03c7 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -96,7 +96,7 @@ func main() { opts.TaskQueue = "my-task-queue" opts.RegisterWorkflowWithOptions(MyWorkflow, workflow.RegisterOptions{ - VersioningBehavior: workflow.VersioningBehaviorAutoUpgrade, + VersioningBehavior: workflow.VersioningBehaviorPinned, }) opts.RegisterActivity(MyActivity) @@ -173,7 +173,7 @@ export const handler = runWorker( codePath: require.resolve('./workflow-bundle.js'), }; config.workerOptions.activities = activities; - config.workerOptions.workerDeploymentOptions!.defaultVersioningBehavior = 'AUTO_UPGRADE'; + config.workerOptions.workerDeploymentOptions!.defaultVersioningBehavior = 'PINNED'; }, ); ``` From c1123a7c428b2fe2c93d5317fc7daa200f65023d Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Thu, 30 Apr 2026 11:13:22 -0700 Subject: [PATCH 40/62] add prerelease banners --- docs/develop/go/workers/serverless-workers/aws-lambda.mdx | 8 ++++++++ .../python/workers/serverless-workers/aws-lambda.mdx | 8 ++++++++ .../typescript/workers/serverless-workers/aws-lambda.mdx | 8 ++++++++ docs/encyclopedia/workers/serverless-workers.mdx | 8 ++++++++ .../serverless-workers/demo.mdx | 8 ++++++++ .../worker-deployments/serverless-workers/aws-lambda.mdx | 8 ++++++++ .../serverless-workers/self-hosted-setup.mdx | 8 ++++++++ 7 files changed, 56 insertions(+) diff --git a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx index 8d9cf84aac..33c7c83300 100644 --- a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx @@ -19,6 +19,14 @@ tags: - AWS Lambda --- +:::tip SUPPORT, STABILITY, and DEPENDENCY INFO + +Serverless Workers are in [Pre-release](/evaluate/development-production-features/release-stages#pre-release). + +APIs are experimental and may be subject to backwards-incompatible changes. + +::: + 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. diff --git a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx index 35fbe1051e..74896644b4 100644 --- a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx @@ -19,6 +19,14 @@ tags: - AWS Lambda --- +:::tip SUPPORT, STABILITY, and DEPENDENCY INFO + +Serverless Workers are in [Pre-release](/evaluate/development-production-features/release-stages#pre-release). + +APIs are experimental and may be subject to backwards-incompatible changes. + +::: + 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. diff --git a/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx b/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx index 022df8f2ae..3742b9ac40 100644 --- a/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx @@ -19,6 +19,14 @@ tags: - AWS Lambda --- +:::tip SUPPORT, STABILITY, and DEPENDENCY INFO + +Serverless Workers are in [Pre-release](/evaluate/development-production-features/release-stages#pre-release). + +APIs are experimental and may be subject to backwards-incompatible changes. + +::: + 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. Each invocation starts a Worker, polls for Tasks, then gracefully shuts down before a configurable invocation deadline. diff --git a/docs/encyclopedia/workers/serverless-workers.mdx b/docs/encyclopedia/workers/serverless-workers.mdx index 4f37406c2c..ea9fb12ea8 100644 --- a/docs/encyclopedia/workers/serverless-workers.mdx +++ b/docs/encyclopedia/workers/serverless-workers.mdx @@ -19,6 +19,14 @@ tags: import CaptionedImage from '@site/src/components/images/CaptionedImage'; +:::tip SUPPORT, STABILITY, and DEPENDENCY INFO + +Serverless Workers are in [Pre-release](/evaluate/development-production-features/release-stages#pre-release). + +APIs are experimental and may be subject to backwards-incompatible changes. + +::: + This page covers the following: - [What is a Serverless Worker?](#serverless-worker) diff --git a/docs/evaluate/development-production-features/serverless-workers/demo.mdx b/docs/evaluate/development-production-features/serverless-workers/demo.mdx index fcfad1a6b6..bb004e14e8 100644 --- a/docs/evaluate/development-production-features/serverless-workers/demo.mdx +++ b/docs/evaluate/development-production-features/serverless-workers/demo.mdx @@ -18,6 +18,14 @@ tags: description: An interactive demo for Temporal Serverless Workers. Explore the configuration, generated code, and execution flow for running Workers on AWS Lambda. --- +:::tip SUPPORT, STABILITY, and DEPENDENCY INFO + +Serverless Workers are in [Pre-release](/evaluate/development-production-features/release-stages#pre-release). + +APIs are experimental and may be subject to backwards-incompatible changes. + +::: + 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 done. diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 077d5b03c7..c276c3f753 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -22,6 +22,14 @@ import SdkTabs from '@site/src/components/elements/SdkTabs'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; +:::tip SUPPORT, STABILITY, and DEPENDENCY INFO + +Serverless Workers are in [Pre-release](/evaluate/development-production-features/release-stages#pre-release). + +APIs are experimental and may be subject to backwards-incompatible changes. + +::: + This guide walks through deploying a Temporal [Serverless Worker](/serverless-workers) on AWS Lambda. ## Prerequisites {#prerequisites} diff --git a/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx b/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx index e490448e26..3d7dc77d26 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx @@ -19,6 +19,14 @@ tags: - Self-hosted --- +:::tip SUPPORT, STABILITY, and DEPENDENCY INFO + +Serverless Workers are in [Pre-release](/evaluate/development-production-features/release-stages#pre-release). + +APIs are experimental and may be subject to backwards-incompatible changes. + +::: + This page covers the prerequisites for running [Serverless Workers](/serverless-workers) on a self-hosted Temporal Service with AWS Lambda: From 1afbb83536602fd9e4fc5a0fce3674ef3bab64ee Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Thu, 30 Apr 2026 14:30:43 -0700 Subject: [PATCH 41/62] add version requirements --- .../worker-deployments/serverless-workers/aws-lambda.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index c276c3f753..be9148340f 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -34,7 +34,7 @@ This guide walks through deploying a Temporal [Serverless Worker](/serverless-wo ## Prerequisites {#prerequisites} -- A Temporal Cloud account with an AWS-hosted Namespace, or a self-hosted Temporal Service vx.xx.x or later. +- A Temporal Cloud account with an AWS-hosted Namespace, or a self-hosted Temporal Service v1.31.0 or later. The Namespace's cloud provider must match the serverless compute provider. - For self-hosted deployments, complete the [self-hosted setup](/production-deployment/worker-deployments/serverless-workers/self-hosted-setup) before following From fc7eb777ebc13b1b1fa97dfb572cce8e2045a369 Mon Sep 17 00:00:00 2001 From: Lenny Chen <55669665+lennessyy@users.noreply.github.com> Date: Fri, 1 May 2026 11:12:19 -0700 Subject: [PATCH 42/62] docs: add Activity Heartbeat tip for long-running Activities on serverless (#4495) Co-authored-by: Claude Opus 4.6 (1M context) --- docs/encyclopedia/workers/serverless-workers.mdx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/encyclopedia/workers/serverless-workers.mdx b/docs/encyclopedia/workers/serverless-workers.mdx index ea9fb12ea8..248f149603 100644 --- a/docs/encyclopedia/workers/serverless-workers.mdx +++ b/docs/encyclopedia/workers/serverless-workers.mdx @@ -147,6 +147,13 @@ If your Worker handles long-running Activities, set these three values together: - **Invocation deadline > longest Activity runtime + shutdown deadline buffer.** Set on the compute provider to give each invocation enough total runtime. + :::tip + + If your longest-running Activity runs longer than half the maximum invocation deadline, this constraint may be difficult or impossible to meet. + In this case, use [Activity Heartbeats](/activity-heartbeat) to record the state of the Activity execution so that the next retry can pick up where it left off. + + ::: + For example, if your longest Activity runtime is 5 minutes, and your shutdown hooks take 3 seconds to run, set the Worker stop timeout to more than 5 minutes, and the shutdown deadline buffer to more than 303 seconds (5 minutes + 3 seconds). Set your invocation deadline to at least 10 minutes and 3 seconds (5 minutes + 303 seconds). From a836b538a656f1e2268ea006f6682aa9d12f0541 Mon Sep 17 00:00:00 2001 From: Lenny Chen <55669665+lennessyy@users.noreply.github.com> Date: Fri, 1 May 2026 11:13:51 -0700 Subject: [PATCH 43/62] docs: add note about lambda versioning best practice (#4503) * docs: add note about lambda versioning best practice * fix: move admonition closing ::: to its own line The linter merged the ::: closing tag onto the preceding text line, which breaks MDX admonition rendering. Co-Authored-By: Claude Opus 4.6 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- .../serverless-workers/aws-lambda.mdx | 144 +++++++++++------- 1 file changed, 87 insertions(+), 57 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index be9148340f..2d80a2bd0c 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -39,7 +39,8 @@ This guide walks through deploying a Temporal [Serverless Worker](/serverless-wo - For self-hosted deployments, complete the [self-hosted setup](/production-deployment/worker-deployments/serverless-workers/self-hosted-setup) before following this guide. -- Every Workflow must declare a [versioning behavior](/worker-versioning#versioning-behaviors), or the Worker must set a default versioning behavior. +- Every Workflow must declare a [versioning behavior](/worker-versioning#versioning-behaviors), or the Worker must set a + default versioning behavior. - An AWS account with permissions to create and invoke Lambda functions and create IAM roles. - 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. @@ -51,7 +52,10 @@ This guide walks through deploying a Temporal [Serverless Worker](/serverless-wo :::tip -If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample Workflows and Activities from the [Go Lambda Worker sample](https://github.com/temporalio/samples-go/tree/main/lambda-worker). +If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample +Workflows and Activities from the +[Go Lambda Worker sample](https://github.com/temporalio/samples-go/tree/main/lambda-worker). + ::: @@ -61,7 +65,10 @@ If you are just exploring the Serverless Worker feature and don't have a Workflo :::tip -If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample Workflows and Activities from the [Python Lambda Worker sample](https://github.com/temporalio/samples-python/tree/main/lambda_worker). +If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample +Workflows and Activities from the +[Python Lambda Worker sample](https://github.com/temporalio/samples-python/tree/main/lambda_worker). + ::: @@ -71,7 +78,10 @@ If you are just exploring the Serverless Worker feature and don't have a Workflo :::tip -If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample Workflows and Activities from the [TypeScript Lambda Worker sample](https://github.com/temporalio/samples-typescript/tree/main/lambda-worker). +If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample +Workflows and Activities from the +[TypeScript Lambda Worker sample](https://github.com/temporalio/samples-typescript/tree/main/lambda-worker). + :::
@@ -113,8 +123,9 @@ func main() { } ``` -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`. +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 - Go SDK](/develop/go/workers/serverless-workers/aws-lambda). @@ -147,8 +158,9 @@ lambda_handler = run_worker( ) ``` -Each Workflow must have a [versioning behavior](/worker-versioning#versioning-behaviors), either `PINNED` or `AUTO_UPGRADE`. -Set it per-Workflow in the `@workflow.defn` decorator, or set a worker-level default with `default_versioning_behavior` in the worker config. +Each Workflow must have a [versioning behavior](/worker-versioning#versioning-behaviors), either `PINNED` or +`AUTO_UPGRADE`. Set it per-Workflow in the `@workflow.defn` decorator, or set a worker-level default with +`default_versioning_behavior` in the worker config. ```python from temporalio import workflow @@ -162,7 +174,8 @@ class MyWorkflow: ... ``` -For details on configuration options, Lambda-tuned defaults, and observability, see [Serverless Workers - Python SDK](/develop/python/workers/serverless-workers/aws-lambda). +For details on configuration options, Lambda-tuned defaults, and observability, see +[Serverless Workers - Python SDK](/develop/python/workers/serverless-workers/aws-lambda). @@ -186,12 +199,15 @@ export const handler = runWorker( ); ``` -Use `workflowBundle` with pre-bundled code instead of `workflowsPath` to avoid webpack bundling overhead on Lambda cold starts. +Use `workflowBundle` with pre-bundled code instead of `workflowsPath` to avoid webpack bundling overhead on Lambda cold +starts. -Each Workflow must declare a [versioning behavior](/worker-versioning#versioning-behaviors), either `AUTO_UPGRADE` or `PINNED`. -Set it per-Workflow with `setWorkflowOptions` in the Workflow file, or set a default for all Workflows with `defaultVersioningBehavior` in the configure callback. +Each Workflow must declare a [versioning behavior](/worker-versioning#versioning-behaviors), either `AUTO_UPGRADE` or +`PINNED`. Set it per-Workflow with `setWorkflowOptions` in the Workflow file, or set a default for all Workflows with +`defaultVersioningBehavior` in the configure callback. -For details on configuration options, Lambda-tuned defaults, and observability, see [Serverless Workers - TypeScript SDK](/develop/typescript/workers/serverless-workers/aws-lambda). +For details on configuration options, Lambda-tuned defaults, and observability, see +[Serverless Workers - TypeScript SDK](/develop/typescript/workers/serverless-workers/aws-lambda). @@ -220,13 +236,15 @@ zip function.zip bootstrap -Install dependencies into a local directory for packaging. Use `--platform` to fetch Linux-compatible binaries for the Lambda runtime: +Install dependencies into a local directory for packaging. Use `--platform` to fetch Linux-compatible binaries for the +Lambda runtime: ```bash pip install --target ./package --platform manylinux2014_x86_64 --only-binary=:all: temporalio ``` -To include [OpenTelemetry support](/develop/python/workers/serverless-workers/aws-lambda#add-observability), install `temporalio[lambda-worker-otel]` instead. +To include [OpenTelemetry support](/develop/python/workers/serverless-workers/aws-lambda#add-observability), install +`temporalio[lambda-worker-otel]` instead. Package the dependencies and your application code into a zip file: @@ -274,11 +292,11 @@ aws lambda create-function \ --environment '{"Variables":{"HOME":"/tmp","TEMPORAL_ADDRESS":":7233","TEMPORAL_NAMESPACE":"","TEMPORAL_API_KEY":""}}' ``` -| Parameter | Description | -|---|---| -| `--function-name` | Name of the Lambda function. | -| `--runtime` | Lambda runtime. Use `provided.al2023` for custom Go binaries. | -| `--handler` | Entry point binary name. Must be `bootstrap` when using the `provided.al2023` custom runtime. | +| Parameter | Description | +| ----------------- | --------------------------------------------------------------------------------------------- | +| `--function-name` | Name of the Lambda function. | +| `--runtime` | Lambda runtime. Use `provided.al2023` for custom Go binaries. | +| `--handler` | Entry point binary name. Must be `bootstrap` when using the `provided.al2023` custom runtime. | @@ -295,11 +313,11 @@ aws lambda create-function \ --environment '{"Variables":{"TEMPORAL_ADDRESS":":7233","TEMPORAL_NAMESPACE":"","TEMPORAL_API_KEY":""}}' ``` -| Parameter | Description | -|---|---| -| `--function-name` | Name of the Lambda function. | -| `--runtime` | Lambda runtime. Use `python3.13` or another supported Python version. | -| `--handler` | Entry point in `module.function` format. Must point to the handler returned by `run_worker`. | +| Parameter | Description | +| ----------------- | -------------------------------------------------------------------------------------------- | +| `--function-name` | Name of the Lambda function. | +| `--runtime` | Lambda runtime. Use `python3.13` or another supported Python version. | +| `--handler` | Entry point in `module.function` format. Must point to the handler returned by `run_worker`. | @@ -316,33 +334,35 @@ aws lambda create-function \ --environment '{"Variables":{"HOME":"/tmp","TEMPORAL_ADDRESS":":7233","TEMPORAL_NAMESPACE":"","TEMPORAL_API_KEY":""}}' ``` -| Parameter | Description | -|---|---| -| `--function-name` | Name of the Lambda function. | -| `--runtime` | Lambda runtime. Use `nodejs22.x` or another supported Node.js version (20+). | -| `--handler` | Entry point in `module.export` format. Must point to the handler exported by `runWorker`. | +| Parameter | Description | +| ----------------- | ----------------------------------------------------------------------------------------- | +| `--function-name` | Name of the Lambda function. | +| `--runtime` | Lambda runtime. Use `nodejs22.x` or another supported Node.js version (20+). | +| `--handler` | Entry point in `module.export` format. Must point to the handler exported by `runWorker`. | The following parameters apply to all SDKs: -| Parameter | Description | -|---|---| -| `--role` | ARN of the Lambda [execution role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html), which grants the function permission to run. Trusted principal must be `lambda.amazonaws.com`. This is separate from the role Temporal uses to invoke the function in [Step 3](#configure-iam). The role must have at least the [`AWSLambdaBasicExecutionRole`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaBasicExecutionRole.html) managed policy attached. | -| `--zip-file` | Path to your packaged deployment zip. | -| `--timeout` | Invocation deadline in seconds. This is the maximum time each Lambda invocation can run before AWS terminates it. Set this high enough for the Worker to start, process Tasks, and [shut down gracefully](/serverless-workers#worker-lifecycle). | -| `--memory-size` | Memory in MB allocated to each invocation. | -| `TEMPORAL_ADDRESS` | Temporal frontend address (e.g., `..tmprl.cloud:7233`). | -| `TEMPORAL_NAMESPACE` | Temporal Namespace. | -| `TEMPORAL_TASK_QUEUE` | Task Queue name. Overrides the value set in code. | -| `TEMPORAL_TLS_CLIENT_CERT_PATH` | Path to the TLS client certificate file for mTLS authentication. | -| `TEMPORAL_TLS_CLIENT_KEY_PATH` | Path to the TLS client key file for mTLS authentication. | -| `TEMPORAL_API_KEY` | API key for API key authentication. | - -The serverless Worker packages read environment variables automatically at startup. For the full list, see [Client environment configuration](/references/client-environment-configuration). - -Sensitive values like TLS keys and API keys should be encrypted at rest. See [AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars-encryption.html) for options. +| Parameter | Description | +| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--role` | ARN of the Lambda [execution role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html), which grants the function permission to run. Trusted principal must be `lambda.amazonaws.com`. This is separate from the role Temporal uses to invoke the function in [Step 3](#configure-iam). The role must have at least the [`AWSLambdaBasicExecutionRole`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaBasicExecutionRole.html) managed policy attached. | +| `--zip-file` | Path to your packaged deployment zip. | +| `--timeout` | Invocation deadline in seconds. This is the maximum time each Lambda invocation can run before AWS terminates it. Set this high enough for the Worker to start, process Tasks, and [shut down gracefully](/serverless-workers#worker-lifecycle). | +| `--memory-size` | Memory in MB allocated to each invocation. | +| `TEMPORAL_ADDRESS` | Temporal frontend address (e.g., `..tmprl.cloud:7233`). | +| `TEMPORAL_NAMESPACE` | Temporal Namespace. | +| `TEMPORAL_TASK_QUEUE` | Task Queue name. Overrides the value set in code. | +| `TEMPORAL_TLS_CLIENT_CERT_PATH` | Path to the TLS client certificate file for mTLS authentication. | +| `TEMPORAL_TLS_CLIENT_KEY_PATH` | Path to the TLS client key file for mTLS authentication. | +| `TEMPORAL_API_KEY` | API key for API key authentication. | + +The serverless Worker packages read environment variables automatically at startup. For the full list, see +[Client environment configuration](/references/client-environment-configuration). + +Sensitive values like TLS keys and API keys should be encrypted at rest. See +[AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars-encryption.html) for options. To update an existing function with new code: @@ -352,6 +372,15 @@ aws lambda update-function-code \ --zip-file fileb://function.zip ``` +:::caution Lambda versioning best practices + +Create a 1-to-1 mapping between each build ID in your Worker code and a +[Lambda function version](https://docs.aws.amazon.com/lambda/latest/dg/configuration-versions.html). If you use an +unversioned Lambda, do not change the build ID in your Worker code without also creating a new Worker Deployment +Version. + +::: + ## 3. Configure IAM for Temporal invocation (Cloud only) {#configure-iam} This section applies to Temporal Cloud. For self-hosted Temporal Service deployments, see @@ -365,11 +394,11 @@ call `lambda:InvokeFunction`. The trust policy on the role includes an External Deploy the following CloudFormation template to create the invocation role and its permissions. [Download the template](/files/temporal-cloud-serverless-worker-role.yaml). -| Parameter | Description | -| ---------------------- | ---------------------------------------------------------------------------------------------------------------------- | +| Parameter | Description | +| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `AssumeRoleExternalId` | 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. | -| `LambdaFunctionARNs` | Comma-separated list of Lambda function ARNs that Temporal may invoke. One role can authorize multiple Worker Lambdas. | -| `RoleName` | Base name for the created IAM role. Defaults to `Temporal-Cloud-Serverless-Worker`. | +| `LambdaFunctionARNs` | Comma-separated list of Lambda function ARNs that Temporal may invoke. One role can authorize multiple Worker Lambdas. | +| `RoleName` | Base name for the created IAM role. Defaults to `Temporal-Cloud-Serverless-Worker`. |
CloudFormation template @@ -517,7 +546,8 @@ You can create the version using the Temporal UI or the Temporal CLI. your Worker code. 5. Under **Compute**, select **AWS Lambda** and provide: - **Lambda ARN**: the ARN of your Lambda function. - - **IAM Role ARN**: the role ARN from [Step 3](#configure-iam) (output of the CloudFormation stack). This is not the Lambda execution role from [Step 2](#deploy-lambda-function) or your own IAM user/role. + - **IAM Role ARN**: the role ARN from [Step 3](#configure-iam) (output of the CloudFormation stack). This is not the + Lambda execution role from [Step 2](#deploy-lambda-function) or your own IAM user/role. - **External ID**: the same value you passed to the CloudFormation template. 6. Click **Save**. @@ -550,13 +580,13 @@ temporal worker deployment create-version \ --aws-lambda-assume-role-external-id ``` -| Flag | Description | -| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `--deployment-name` | Worker Deployment name. Must match `DeploymentName` in your Worker code. | -| `--build-id` | Worker Deployment Version build ID. Must match `BuildID` in your Worker code. | -| `--aws-lambda-function-arn` | ARN of the Lambda function Temporal invokes for this version. | +| Flag | Description | +| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--deployment-name` | Worker Deployment name. Must match `DeploymentName` in your Worker code. | +| `--build-id` | Worker Deployment Version build ID. Must match `BuildID` in your Worker code. | +| `--aws-lambda-function-arn` | ARN of the Lambda function Temporal invokes for this version. | | `--aws-lambda-assume-role-arn` | IAM role Temporal assumes to invoke the function. This is the `RoleARN` output from the CloudFormation stack in [Step 3](#configure-iam). This is not the Lambda execution role from [Step 2](#deploy-lambda-function) or your own IAM user/role. | -| `--aws-lambda-assume-role-external-id` | External ID configured in the IAM role trust policy. | +| `--aws-lambda-assume-role-external-id` | External ID configured in the IAM role trust policy. | From 289f0411988e59e28296a9238978a649a7b04c09 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Fri, 1 May 2026 11:24:46 -0700 Subject: [PATCH 44/62] minor copy edit --- .../serverless-workers/aws-lambda.mdx | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 2d80a2bd0c..59b9583d02 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -22,6 +22,8 @@ import SdkTabs from '@site/src/components/elements/SdkTabs'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; +This guide walks through deploying a Temporal [Serverless Worker](/serverless-workers) on AWS Lambda. + :::tip SUPPORT, STABILITY, and DEPENDENCY INFO Serverless Workers are in [Pre-release](/evaluate/development-production-features/release-stages#pre-release). @@ -30,12 +32,10 @@ APIs are experimental and may be subject to backwards-incompatible changes. ::: -This guide walks through deploying a Temporal [Serverless Worker](/serverless-workers) on AWS Lambda. - ## Prerequisites {#prerequisites} -- A Temporal Cloud account with an AWS-hosted Namespace, or a self-hosted Temporal Service v1.31.0 or later. - The Namespace's cloud provider must match the serverless compute provider. +- A Temporal Cloud account with an AWS-hosted Namespace, or a self-hosted Temporal Service v1.31.0 or later. The + Namespace's cloud provider must match the serverless compute provider. - For self-hosted deployments, complete the [self-hosted setup](/production-deployment/worker-deployments/serverless-workers/self-hosted-setup) before following this guide. @@ -50,13 +50,13 @@ This guide walks through deploying a Temporal [Serverless Worker](/serverless-wo - The [Go SDK](/develop/go) (`go.temporal.io/sdk`) -:::tip + :::tip -If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample -Workflows and Activities from the -[Go Lambda Worker sample](https://github.com/temporalio/samples-go/tree/main/lambda-worker). + If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample + Workflows and Activities from the + [Go Lambda Worker sample](https://github.com/temporalio/samples-go/tree/main/lambda-worker). -::: + ::: @@ -186,17 +186,14 @@ Use the `@temporalio/lambda-worker` package. import { runWorker } from '@temporalio/lambda-worker'; import * as activities from './activities'; -export const handler = runWorker( - { deploymentName: 'my-app', buildId: 'build-1' }, - (config) => { - config.workerOptions.taskQueue = 'my-task-queue'; - config.workerOptions.workflowBundle = { - codePath: require.resolve('./workflow-bundle.js'), - }; - config.workerOptions.activities = activities; - config.workerOptions.workerDeploymentOptions!.defaultVersioningBehavior = 'PINNED'; - }, -); +export const handler = runWorker({ deploymentName: 'my-app', buildId: 'build-1' }, (config) => { + config.workerOptions.taskQueue = 'my-task-queue'; + config.workerOptions.workflowBundle = { + codePath: require.resolve('./workflow-bundle.js'), + }; + config.workerOptions.activities = activities; + config.workerOptions.workerDeploymentOptions!.defaultVersioningBehavior = 'PINNED'; +}); ``` Use `workflowBundle` with pre-bundled code instead of `workflowsPath` to avoid webpack bundling overhead on Lambda cold @@ -546,8 +543,9 @@ You can create the version using the Temporal UI or the Temporal CLI. your Worker code. 5. Under **Compute**, select **AWS Lambda** and provide: - **Lambda ARN**: the ARN of your Lambda function. - - **IAM Role ARN**: the role ARN from [Step 3](#configure-iam) (output of the CloudFormation stack). This is not the - Lambda execution role from [Step 2](#deploy-lambda-function) or your own IAM user/role. + - **IAM Role ARN**: the ARN of the role Temporal assumes to invoke your Lambda function. This is the role ARN from + [Step 3](#configure-iam) (output of the CloudFormation stack). This is not the Lambda execution role from + [Step 2](#deploy-lambda-function) or your own IAM user/role. - **External ID**: the same value you passed to the CloudFormation template. 6. Click **Save**. @@ -591,7 +589,9 @@ temporal worker deployment create-version \ -To verify that Temporal can reach your Lambda function, go to **Workers** > **Deployments** > select your deployment > open the **Actions** menu on the version and click **Validate Connection**. This checks that Temporal can assume the IAM role and invoke the function. +To verify that Temporal can reach your Lambda function, go to **Workers** > **Deployments** > select your deployment > +open the **Actions** menu on the version and click **Validate Connection**. This checks that Temporal can assume the IAM +role and invoke the function. ## 5. Set version as current {#set-current-version} From 923cf5f6a2efe93c4551600b084b28668c77eab9 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Fri, 1 May 2026 11:26:47 -0700 Subject: [PATCH 45/62] indent admonition --- .../serverless-workers/aws-lambda.mdx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 59b9583d02..8a04fb7b4a 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -63,26 +63,26 @@ APIs are experimental and may be subject to backwards-incompatible changes. - The [Python SDK](/develop/python) (`temporalio`) -:::tip + :::tip -If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample -Workflows and Activities from the -[Python Lambda Worker sample](https://github.com/temporalio/samples-python/tree/main/lambda_worker). + If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample + Workflows and Activities from the + [Python Lambda Worker sample](https://github.com/temporalio/samples-python/tree/main/lambda_worker). -::: + ::: - The [TypeScript SDK](/develop/typescript) (`@temporalio/lambda-worker`) -:::tip + :::tip -If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample -Workflows and Activities from the -[TypeScript Lambda Worker sample](https://github.com/temporalio/samples-typescript/tree/main/lambda-worker). + If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample + Workflows and Activities from the + [TypeScript Lambda Worker sample](https://github.com/temporalio/samples-typescript/tree/main/lambda-worker). -::: + ::: From 2dd3e2f232b78f55b9cabf844c054e55a93fdd87 Mon Sep 17 00:00:00 2001 From: Lenny Chen <55669665+lennessyy@users.noreply.github.com> Date: Mon, 4 May 2026 08:50:05 -0700 Subject: [PATCH 46/62] Apply suggestions from code review Co-authored-by: Milecia McG <47196133+flippedcoder@users.noreply.github.com> --- docs/develop/go/workers/serverless-workers/aws-lambda.mdx | 2 +- docs/develop/python/workers/serverless-workers/aws-lambda.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx index 33c7c83300..447b7ce9c4 100644 --- a/docs/develop/go/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/go/workers/serverless-workers/aws-lambda.mdx @@ -131,7 +131,7 @@ With this enabled, the Worker emits SDK metrics and distributed traces for Workf 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 Go SDK emits in any environment. -For general observability concepts and the full list of available metrics, see [Observability - Go SDK](/develop/go/observability) and the [SDK metrics reference](/references/sdk-metrics). +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). [samples-go/lambda-worker/worker/main.go](https://github.com/temporalio/samples-go/blob/lambda-worker/samples-go/lambda-worker/worker/main.go) diff --git a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx index 74896644b4..7ad1c52a97 100644 --- a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx @@ -64,7 +64,7 @@ lambda_handler = run_worker( `run_worker` takes a `WorkerDeploymentVersion` and a configure callback, and returns a Lambda handler. -The `WorkerDeploymentVersion` identifies the [Worker Deployment](/worker-versioning#worker-deployments) and [Build ID](/worker-versioning#build-id) for this Worker. +The `WorkerDeploymentVersion` identifies the [Worker Deployment](/worker-versioning#deployments) and [Build Id](/worker-versioning#build-id) for this Worker. The deployment name groups related Workers across versions, and the Build ID identifies a specific release of your Worker code. Worker Versioning is required for Serverless Workers. From 4ad8d01efa5a8f3b577cd6600e811c7acd0e331c Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Mon, 4 May 2026 08:57:57 -0700 Subject: [PATCH 47/62] address review comments --- .../workers/serverless-workers.mdx | 12 ++--- .../worker-deployments/index.mdx | 2 +- .../serverless-workers/aws-lambda.mdx | 44 +++---------------- .../serverless-workers/index.mdx | 4 +- .../serverless-workers/self-hosted-setup.mdx | 2 +- 5 files changed, 17 insertions(+), 47 deletions(-) diff --git a/docs/encyclopedia/workers/serverless-workers.mdx b/docs/encyclopedia/workers/serverless-workers.mdx index 248f149603..a56ef3125b 100644 --- a/docs/encyclopedia/workers/serverless-workers.mdx +++ b/docs/encyclopedia/workers/serverless-workers.mdx @@ -81,7 +81,7 @@ The invocation flow works as follows: 5. The Serverless Worker starts, creates a Temporal Client, and begins polling the Task Queue. 6. The Worker processes available Tasks until it exits (see [Worker lifecycle](#worker-lifecycle)). -The WCI also monitors the Task Queue backlog independently. If tasks arrive faster than Workers can process them, the +The WCI also monitors the Task Queue backlog independently. If Tasks arrive faster than Workers can process them, the WCI invokes additional Workers in parallel until the backlog drains or provider concurrency limits are reached. Each invocation is independent. The Worker creates a fresh client connection on every invocation. There is no connection @@ -90,7 +90,7 @@ reuse or shared state across invocations. ## Autoscaling {#autoscaling} Temporal automatically scales Serverless Workers based on Task Queue signals. When Tasks arrive and no Worker is -available, Temporal invokes new Workers. When the work is done, Workers exit and scale to zero. +available, Temporal invokes new Workers. When the Tasks are done, Workers exit and scale to zero. The WCI uses two signals to decide when to invoke new Workers: @@ -105,7 +105,7 @@ responsive. ### Task Queue backlog {#task-queue-backlog} The WCI monitors Task Queue metadata to determine whether pending Tasks exist without enough Workers to process them. If -there is work on the queue and not enough Workers, the WCI invokes additional Workers. +there are Tasks on the queue and not enough Workers, the WCI invokes additional Workers. ## Scaling with long-lived Workers {#scaling-with-long-lived-workers} @@ -125,7 +125,7 @@ A single Serverless Worker invocation has three phases: init, work, and shutdown src="/diagrams/serverless-worker-lifecycle.svg" srcDark="/diagrams/serverless-worker-lifecycle-dark.svg" alt="Serverless Worker lifecycle" - title="The shutdown deadline buffer controls when the Worker stops polling, and the Worker stop timeout controls how long the Worker waits for in-flight Tasks to finish before shutdown hooks run. Diagram is not to scale. Shutdown hooks typically take less than a few seconds." + title="Diagram is not to scale. The shutdown deadline buffer controls when the Worker stops polling, and the Worker stop timeout controls how long the Worker waits for in-flight Tasks to finish before shutdown hooks run. Shutdown hooks typically take less than a few seconds." /> During the **init** phase, the Worker initializes and establishes a client connection to Temporal. @@ -150,7 +150,7 @@ If your Worker handles long-running Activities, set these three values together: :::tip If your longest-running Activity runs longer than half the maximum invocation deadline, this constraint may be difficult or impossible to meet. - In this case, use [Activity Heartbeats](/activity-heartbeat) to record the state of the Activity execution so that the next retry can pick up where it left off. + In this case, use [Activity Heartbeats](/detecting-activity-failures#activity-heartbeat) to record the state of the Activity execution so that the next retry can pick up where it left off. ::: @@ -210,7 +210,7 @@ With single-slot configuration, each Activity gets a dedicated execution environ | Activity duration | Must complete within the compute provider's invocation limit (minus shutdown deadline buffer). For AWS Lambda, the maximum is 15 minutes. | | Workflow duration | No limit. Workflows of any duration work, regardless of the invocation timeout. A Workflow runs across as many invocations 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. | +| 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. | ## Compute providers {#compute-providers} diff --git a/docs/production-deployment/worker-deployments/index.mdx b/docs/production-deployment/worker-deployments/index.mdx index f6fb081dde..97960c8015 100644 --- a/docs/production-deployment/worker-deployments/index.mdx +++ b/docs/production-deployment/worker-deployments/index.mdx @@ -37,7 +37,7 @@ This section also covers specific Worker Deployment examples: - [**Serverless Workers**](/production-deployment/worker-deployments/serverless-workers) Deploy Serverless Workers on serverless compute like AWS Lambda. - Temporal invokes your Worker when tasks arrive, with no long-lived processes to manage. + Temporal invokes your Worker when Tasks arrive, with no long-lived processes to manage. - [**Deploy Workers to Amazon EKS**](/production-deployment/worker-deployments/deploy-workers-to-aws-eks) Containerize your Worker, publish it to Amazon Elastic Container Registry (ECR), and deploy it to Amazon Elastic Kubernetes Service (EKS) using the Temporal Python SDK. diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 8a04fb7b4a..cc686559ef 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -45,48 +45,18 @@ APIs are experimental and may be subject to backwards-incompatible changes. - 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) (`go.temporal.io/sdk`) - - :::tip - - If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample - Workflows and Activities from the - [Go Lambda Worker sample](https://github.com/temporalio/samples-go/tree/main/lambda-worker). - - ::: - - - - -- The [Python SDK](/develop/python) (`temporalio`) +- 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. :::tip - If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample - Workflows and Activities from the - [Python Lambda Worker sample](https://github.com/temporalio/samples-python/tree/main/lambda_worker). - - ::: - - - - -- The [TypeScript SDK](/develop/typescript) (`@temporalio/lambda-worker`) - - :::tip - - If you are just exploring the Serverless Worker feature and don't have a Workflow ready, you can use the sample - Workflows and Activities from the + 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). ::: - - - ## 1. Write Worker code {#write-worker-code} Write a Worker that runs inside a Lambda function. The Worker handles the per-invocation lifecycle: connecting to @@ -124,7 +94,7 @@ func main() { ``` 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 +`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 @@ -159,7 +129,7 @@ lambda_handler = run_worker( ``` Each Workflow must have a [versioning behavior](/worker-versioning#versioning-behaviors), either `PINNED` or -`AUTO_UPGRADE`. Set it per-Workflow in the `@workflow.defn` decorator, or set a worker-level default with +`AUTO_UPGRADE`. Set it per-Workflow in the `@workflow.defn` decorator, or set a Worker-level default with `default_versioning_behavior` in the worker config. ```python diff --git a/docs/production-deployment/worker-deployments/serverless-workers/index.mdx b/docs/production-deployment/worker-deployments/serverless-workers/index.mdx index af8e534b31..82ba63f5c0 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/index.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/index.mdx @@ -21,8 +21,8 @@ Deploy your Worker code to a serverless provider, configure a compute provider f There are no long-lived processes to provision or scale. Temporal monitors Task Queues that have a compute provider configured. -When a task arrives and no Worker is polling, Temporal invokes the configured compute target. -The Worker starts, processes available tasks, and shuts down when the invocation window ends. +When a Task arrives and no Worker is polling, Temporal invokes the configured compute target. +The Worker starts, processes available Tasks, and shuts down when the invocation window ends. ## Supported providers diff --git a/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx b/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx index 3d7dc77d26..045616ed51 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx @@ -41,7 +41,7 @@ Worker. ## Ensure Lambda can reach the Temporal Service {#ensure-network-reachability} -The [Temporal Service frontend](/temporal-service#frontend-service) must be reachable from the Lambda execution +The [Temporal Service frontend](/temporal-service/temporal-server#frontend-service) must be reachable from the Lambda execution environment. How to achieve this depends on your network setup. If the Temporal Service runs on a private network, you may need [VPC access for Lambda](https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc.html), VPC peering, or a similar mechanism to allow the Lambda function to connect to the Temporal frontend. From f9b29fe4808c85e49ce3ff74b5c958e875e7d53d Mon Sep 17 00:00:00 2001 From: Lenny Chen <55669665+lennessyy@users.noreply.github.com> Date: Mon, 4 May 2026 09:27:48 -0700 Subject: [PATCH 48/62] Apply suggestions from code review Co-authored-by: Milecia McG <47196133+flippedcoder@users.noreply.github.com> --- docs/develop/python/workers/serverless-workers/aws-lambda.mdx | 4 ++-- .../typescript/workers/serverless-workers/aws-lambda.mdx | 2 +- .../serverless-workers/index.mdx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx index 7ad1c52a97..317de3c145 100644 --- a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx @@ -65,7 +65,7 @@ lambda_handler = run_worker( `run_worker` takes a `WorkerDeploymentVersion` and a configure callback, and returns a Lambda handler. The `WorkerDeploymentVersion` identifies the [Worker Deployment](/worker-versioning#deployments) and [Build Id](/worker-versioning#build-id) for this Worker. -The deployment name groups related Workers across versions, and the Build ID identifies a specific release of your Worker code. +The deployment name groups related Workers across versions, and the Build Id identifies a specific release of your Worker code. Worker Versioning is required for Serverless Workers. The `configure` callback receives a `LambdaWorkerConfig` dataclass with fields pre-populated with Lambda-appropriate defaults. @@ -136,7 +136,7 @@ With this enabled, the Worker emits SDK metrics and distributed traces for Workf 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 Python SDK emits in any environment. -For general observability concepts and the full list of available metrics, see [Observability - Python SDK](/develop/python/observability) and the [SDK metrics reference](/references/sdk-metrics). +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) diff --git a/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx b/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx index 3742b9ac40..02efdb9e02 100644 --- a/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx @@ -129,7 +129,7 @@ The `@temporalio/lambda-worker/otel` module provides OpenTelemetry integration w With this enabled, the Worker emits SDK metrics and distributed traces for Workflow and Activity executions. 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/observability) and the [SDK metrics reference](/references/sdk-metrics). +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). [samples-typescript/lambda-worker/src/index.ts](https://github.com/temporalio/samples-typescript/blob/lambda-worker/samples-typescript/lambda-worker/src/index.ts) diff --git a/docs/evaluate/development-production-features/serverless-workers/index.mdx b/docs/evaluate/development-production-features/serverless-workers/index.mdx index ee6b7fef43..64cae331f7 100644 --- a/docs/evaluate/development-production-features/serverless-workers/index.mdx +++ b/docs/evaluate/development-production-features/serverless-workers/index.mdx @@ -26,7 +26,7 @@ Worker shuts down when the work is done. Serverless Workers use the same Temporal SDKs as traditional long-lived Workers. You register Workflows and Activities the same way. The difference is in the lifecycle: instead of running a long-lived process, Temporal invokes the Serverless Worker on demand when Tasks arrive. The Worker starts, polls for available Tasks, processes them, and exits -when the work is done. +when the Task is done. For a deeper look at how Serverless invocation works under the hood, see [Serverless Workers](/serverless-workers) in the encyclopedia. From 25d540da7b3d8fd471006d0c2699801c075d533d Mon Sep 17 00:00:00 2001 From: Lenny Chen <55669665+lennessyy@users.noreply.github.com> Date: Mon, 4 May 2026 09:31:26 -0700 Subject: [PATCH 49/62] Apply suggestions from code review Co-authored-by: Milecia McG <47196133+flippedcoder@users.noreply.github.com> --- .../serverless-workers/index.mdx | 2 +- .../worker-deployments/serverless-workers/aws-lambda.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/evaluate/development-production-features/serverless-workers/index.mdx b/docs/evaluate/development-production-features/serverless-workers/index.mdx index 64cae331f7..87b0e82519 100644 --- a/docs/evaluate/development-production-features/serverless-workers/index.mdx +++ b/docs/evaluate/development-production-features/serverless-workers/index.mdx @@ -21,7 +21,7 @@ tags: Serverless Workers let you run Temporal Workers on serverless compute platforms like AWS Lambda. There are no servers to provision, no clusters to scale, and no idle compute to pay for. Temporal invokes the Worker when Tasks arrive, and the -Worker shuts down when the work is done. +Worker shuts down when the Tasks are done. Serverless Workers use the same Temporal SDKs as traditional long-lived Workers. You register Workflows and Activities the same way. The difference is in the lifecycle: instead of running a long-lived process, Temporal invokes the diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index cc686559ef..1189817209 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -520,7 +520,7 @@ You can create the version using the Temporal UI or the Temporal CLI. 6. Click **Save**. When you create a version through the UI, the version is automatically set as current. Skip to -[Verify the deployment](#verify-the-deployment). +[Verify the deployment](#verify-deployment). From 4ac020a78023b1cd0836a7786e6328ac94a90e8d Mon Sep 17 00:00:00 2001 From: Lenny Chen <55669665+lennessyy@users.noreply.github.com> Date: Mon, 4 May 2026 09:38:54 -0700 Subject: [PATCH 50/62] Apply suggestions from code review Co-authored-by: Milecia McG <47196133+flippedcoder@users.noreply.github.com> --- .../worker-deployments/serverless-workers/aws-lambda.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index 1189817209..de360682aa 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -343,7 +343,7 @@ aws lambda update-function-code \ Create a 1-to-1 mapping between each build ID in your Worker code and a [Lambda function version](https://docs.aws.amazon.com/lambda/latest/dg/configuration-versions.html). If you use an -unversioned Lambda, do not change the build ID in your Worker code without also creating a new Worker Deployment +unversioned Lambda, do not change the Build Id in your Worker code without also creating a new Worker Deployment Version. ::: From 216e2d36920bbfdb48b8d8ae1205c77fee468954 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Mon, 4 May 2026 09:40:15 -0700 Subject: [PATCH 51/62] address feedback --- .../workers/worker-versioning.mdx | 2 ++ .../serverless-workers/index.mdx | 19 +++++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/docs/encyclopedia/workers/worker-versioning.mdx b/docs/encyclopedia/workers/worker-versioning.mdx index f536a9a313..516bdd100e 100644 --- a/docs/encyclopedia/workers/worker-versioning.mdx +++ b/docs/encyclopedia/workers/worker-versioning.mdx @@ -34,6 +34,8 @@ Each Deployment has a name (such as your service name) and supports versioning t ## Worker Deployment Versions {#deployment-versions} A Worker Deployment Version represents an iteration of a Worker Deployment. +Each Deployment Version is identified by a deployment name and a Build ID. +The deployment name groups related Workers across versions, and the Build ID identifies a specific release of your Worker code. Each Deployment Version consists of Workers that share the same code build and environment. When a Worker starts polling for Workflow and Activity Tasks, it reports its Deployment Version to the Temporal Server. diff --git a/docs/production-deployment/worker-deployments/serverless-workers/index.mdx b/docs/production-deployment/worker-deployments/serverless-workers/index.mdx index 82ba63f5c0..bbf5f957bd 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/index.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/index.mdx @@ -2,7 +2,9 @@ id: index title: Serverless Workers sidebar_label: Serverless Workers -description: Deploy Temporal Workers on serverless compute providers. Temporal invokes your Worker when Tasks arrive, with no long-lived processes to manage. +description: + Deploy Temporal Workers on serverless compute providers. Temporal invokes your Worker when Tasks arrive, with no + long-lived processes to manage. slug: /production-deployment/worker-deployments/serverless-workers toc_max_heading_level: 4 keywords: @@ -16,14 +18,15 @@ tags: - Serverless --- -Serverless Workers let you run Temporal Workers on serverless compute like AWS Lambda. -Deploy your Worker code to a serverless provider, configure a compute provider for the Worker Deployment Version, and Temporal invokes the Worker when Tasks arrive. -There are no long-lived processes to provision or scale. +Serverless Workers let you run Temporal Workers on serverless compute like AWS Lambda. Deploy your Worker code to a +serverless provider, configure a compute provider for the Worker Deployment Version, and Temporal invokes the Worker +when Tasks arrive. There are no long-lived processes to provision or scale. -Temporal monitors Task Queues that have a compute provider configured. -When a Task arrives and no Worker is polling, Temporal invokes the configured compute target. -The Worker starts, processes available Tasks, and shuts down when the invocation window ends. +Temporal monitors Task Queues that have a compute provider configured. When a Task arrives and no Worker is polling, +Temporal invokes the configured compute target. The Worker starts, processes available Tasks, and shuts down when the +invocation window ends. ## Supported providers -- [**AWS Lambda**](/production-deployment/worker-deployments/serverless-workers/aws-lambda) - Deploy a Go SDK Worker as a Lambda function. Temporal assumes an IAM role in your AWS account to invoke the function when Tasks arrive. +- [**AWS Lambda**](/production-deployment/worker-deployments/serverless-workers/aws-lambda) - Deploy a Serverless Worker + as a Lambda function. Temporal assumes an IAM role in your AWS account to invoke the function when Tasks arrive. From 278638301efa7b589a71d26da045d36ae1c04816 Mon Sep 17 00:00:00 2001 From: Lenny Chen <55669665+lennessyy@users.noreply.github.com> Date: Mon, 4 May 2026 09:41:02 -0700 Subject: [PATCH 52/62] Apply suggestions from code review Co-authored-by: Milecia McG <47196133+flippedcoder@users.noreply.github.com> --- src/components/elements/ServerlessWorkerDemo.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/elements/ServerlessWorkerDemo.js b/src/components/elements/ServerlessWorkerDemo.js index 1cc4aa69a8..4161a9c4fe 100644 --- a/src/components/elements/ServerlessWorkerDemo.js +++ b/src/components/elements/ServerlessWorkerDemo.js @@ -104,7 +104,7 @@ const STEPS = [ { id: 'worker', number: '1', - title: 'Write worker code', + title: 'Write Worker code', description: 'Use the lambdaworker package to write a Worker that runs inside a Lambda function. Register Workflows and Activities the same way you would with a standard Worker.', codeLabel: 'Worker Code', @@ -136,7 +136,7 @@ const STEPS = [ number: '4', title: 'Create a Worker Deployment Version', description: - 'Use the CLI to create a Worker Deployment Version with your Lambda ARN as the compute provider. The deployment name and build ID must match your Worker code.', + 'Use the CLI to create a Worker Deployment Version with your Lambda ARN as the compute provider. The deployment name and Build Id must match your Worker code.', codeLabel: 'CLI Command', language: 'bash', generate: generateCliCode, From fda57f2e5fb0e2976fd538ae42378a39dcf92bd4 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Mon, 4 May 2026 09:51:50 -0700 Subject: [PATCH 53/62] link to env config pages --- .../worker-deployments/serverless-workers/aws-lambda.mdx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx index de360682aa..f00c9bfe69 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/aws-lambda.mdx @@ -325,8 +325,9 @@ The following parameters apply to all SDKs: | `TEMPORAL_TLS_CLIENT_KEY_PATH` | Path to the TLS client key file for mTLS authentication. | | `TEMPORAL_API_KEY` | API key for API key authentication. | -The serverless Worker packages read environment variables automatically at startup. For the full list, see -[Client environment configuration](/references/client-environment-configuration). +The serverless Worker packages read environment variables and configuration files automatically at startup. +For the full list of supported environment variables, config file format, and profiles, see +[Environment configuration](/develop/environment-configuration). Sensitive values like TLS keys and API keys should be encrypted at rest. See [AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars-encryption.html) for options. From a9f980c9b9ad36accc30deb27e3cc92c9382b8f1 Mon Sep 17 00:00:00 2001 From: Lenny Chen <55669665+lennessyy@users.noreply.github.com> Date: Mon, 4 May 2026 10:23:33 -0700 Subject: [PATCH 54/62] troubleshooting: serverless workers (#4521) * troubleshooting: serverless workers * copy edits * reorder checks * update troubleshooting guide * add brief wci explanation * add link to troubleshooting docs * address feedback * clarify WCI role --- .../workers/serverless-workers.mdx | 28 +++ .../serverless-workers/aws-lambda.mdx | 2 + docs/troubleshooting/index.mdx | 1 + docs/troubleshooting/serverless-workers.mdx | 167 ++++++++++++++++++ sidebars.js | 1 + 5 files changed, 199 insertions(+) create mode 100644 docs/troubleshooting/serverless-workers.mdx diff --git a/docs/encyclopedia/workers/serverless-workers.mdx b/docs/encyclopedia/workers/serverless-workers.mdx index a56ef3125b..1a1c0e7afe 100644 --- a/docs/encyclopedia/workers/serverless-workers.mdx +++ b/docs/encyclopedia/workers/serverless-workers.mdx @@ -61,6 +61,34 @@ Temporal does not need to know anything about the Worker's infrastructure. With Serverless Workers, Temporal starts the Worker. +### Worker Controller Instance {#worker-controller-instance} + +The Worker Controller Instance (WCI) is a system Workflow that scales Serverless Workers based on Task Queue conditions. +One WCI Workflow runs per Worker Deployment Version that has a compute provider configured. The WCI runs in the same +Namespace as your Worker Deployment. + +The WCI responds to two triggers. The Matching Service notifies the WCI when a sync match failure occurs, meaning a Task +arrived but no Worker was available to handle it. The WCI also polls Task Queue backlogs on a schedule to detect +accumulated work. When either trigger fires, the WCI produces a scaling action, such as invoking the configured compute +provider (for example, calling AWS Lambda's `InvokeFunction` API) to start new Workers. + +You can list WCI Workflows in your Namespace: + +```bash +temporal workflow list \ + --namespace \ + --query 'TemporalNamespaceDivision = "TemporalWorkerControllerInstance"' +``` + +WCI Workflow IDs follow the pattern `temporal-sys-worker-controller-instance::`. You can +inspect a WCI Workflow's history to see its recent Activity results: + +```bash +temporal workflow show \ + --namespace \ + --workflow-id 'temporal-sys-worker-controller-instance::' +``` + Functions > your function > Monitor**. Look for recent invocations in the +**Invocations** graph. You can also check **CloudWatch > Log groups > /aws/lambda/your-function-name** for execution +logs. + +If there are no invocations, continue to [Lambda is not being invoked](#lambda-not-invoked). + +If the Lambda is being invoked but Workflows are not progressing, skip to +[Lambda is invoked but Tasks are not completing](#lambda-invoked-not-completing). + +## Lambda is not being invoked {#lambda-not-invoked} + +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. + +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#create-invocation-role) +and that the External ID matches the value in the Worker Deployment Version configuration. + +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). + +### Check that the version is set as current {#check-version-current} + +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`. + +### Check that the WCI is detecting Tasks {#check-wci-detecting-tasks} + +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. + +Check which Task Queues are bound to the Worker Deployment Version and whether there is a backlog: + +```bash +temporal worker deployment describe-version \ + --namespace \ + --deployment-name \ + --build-id \ + --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, or missing dependencies), the Worker never connects to Temporal and never polls. Without a successful +poll, the Task Queue binding is never created. + +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. + +## Lambda is invoked but Tasks are not completing {#lambda-invoked-not-completing} + +If CloudWatch shows Lambda invocations but Workflows are not progressing, the problem is in the Worker's execution +within the Lambda function. + +### Check Lambda execution logs {#check-execution-logs} + +Check CloudWatch logs for errors during Worker startup. In the AWS Console, go to **CloudWatch > Log groups > +/aws/lambda/your-function-name** and look for recent error messages. + +Common errors include: + +- **Connection failures**: The Worker cannot reach the Temporal Service. Check that the `TEMPORAL_ADDRESS` and + `TEMPORAL_API_KEY` environment variables (or `temporal.toml` config file) are correctly set on the Lambda function. + For self-hosted deployments, verify + [network reachability](/production-deployment/worker-deployments/serverless-workers/self-hosted-setup#ensure-reachability). +- **TLS errors**: The TLS certificate or key is missing, expired, or does not match the Namespace. +- **Authentication errors**: The API key is invalid or does not have access to the Namespace. + +### Check for Lambda timeout {#check-lambda-timeout} + +If the Lambda function reaches its configured timeout before the Worker finishes processing, AWS terminates the +invocation. + +The Worker begins graceful shutdown before the Lambda deadline. If Activities take longer than the available execution +window, the Activities are abandoned mid-execution and retried on the next invocation. + +For long-running Activities, increase the Lambda timeout and the Worker's shutdown buffer together. See +[Tuning for long-running Activities](/serverless-workers#tuning-for-long-running-activities) for guidance on how these +values relate. + +### Check that the deployment name and build ID match {#check-deployment-match} + +If CloudWatch shows rapid, repeated invocations with no Workflow progress, the deployment name or build ID in the Worker +code may not match the Worker Deployment Version configuration. + +The deployment name and build ID in your Lambda function code must exactly match the values you used when creating the +Worker Deployment Version. Compare the values in your code against the WCI Workflow ID +(`temporal-sys-worker-controller-instance::`) and the output of +`temporal worker deployment describe`. + +A mismatch causes an invocation loop: the WCI invokes the Lambda, the Worker starts and polls with a different +deployment version than the WCI expects, the Task is not processed, and the WCI invokes the Lambda again. + +To fix the loop, update the deployment name and build ID in the Worker code to match the Worker Deployment Version, then +redeploy the Lambda function. diff --git a/sidebars.js b/sidebars.js index 0c35cbe329..f20f044151 100644 --- a/sidebars.js +++ b/sidebars.js @@ -1400,6 +1400,7 @@ module.exports = { 'troubleshooting/deadline-exceeded-error', 'troubleshooting/last-connection-error', 'troubleshooting/performance-bottlenecks', + 'troubleshooting/serverless-workers', ], }, { From 2131c0bafe2d6ba4d4e3d10114de48de5841259e Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Mon, 4 May 2026 10:26:49 -0700 Subject: [PATCH 55/62] minor copyedit --- .../workers/serverless-workers.mdx | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/encyclopedia/workers/serverless-workers.mdx b/docs/encyclopedia/workers/serverless-workers.mdx index 1a1c0e7afe..f586398917 100644 --- a/docs/encyclopedia/workers/serverless-workers.mdx +++ b/docs/encyclopedia/workers/serverless-workers.mdx @@ -67,10 +67,10 @@ The Worker Controller Instance (WCI) is a system Workflow that scales Serverless One WCI Workflow runs per Worker Deployment Version that has a compute provider configured. The WCI runs in the same Namespace as your Worker Deployment. -The WCI responds to two triggers. The Matching Service notifies the WCI when a sync match failure occurs, meaning a Task -arrived but no Worker was available to handle it. The WCI also polls Task Queue backlogs on a schedule to detect -accumulated work. When either trigger fires, the WCI produces a scaling action, such as invoking the configured compute -provider (for example, calling AWS Lambda's `InvokeFunction` API) to start new Workers. +The WCI responds to two triggers: [sync match failures](#sync-match-failure) and +[Task Queue backlog](#task-queue-backlog). When either trigger fires, the WCI produces a scaling action, such as +invoking the configured compute provider (for example, calling AWS Lambda's `InvokeFunction` API) to start new Workers. +For details on how scaling works, see [Autoscaling](#autoscaling). You can list WCI Workflows in your Namespace: @@ -89,6 +89,8 @@ temporal workflow show \ --workflow-id 'temporal-sys-worker-controller-instance::' ``` +The following diagram illustrates the invocation flow of a Serverless Worker. + -Temporal's internal Worker Controller Instance (WCI) decides when to start, scale, and stop compute invocations. - The invocation flow works as follows: 1. A Task is submitted (for example, `StartWorkflow` or `ScheduleActivity`). @@ -105,20 +105,17 @@ The invocation flow works as follows: available Worker (a sync match). 3. If a Worker is available, the Task is routed to that Worker. 4. If no Worker is available (sync match fails), the Matching Service pushes a signal to the WCI, and the WCI invokes - the configured compute provider (for example, calling AWS Lambda's `InvokeFunction` API). + the configured compute provider. 5. The Serverless Worker starts, creates a Temporal Client, and begins polling the Task Queue. 6. The Worker processes available Tasks until it exits (see [Worker lifecycle](#worker-lifecycle)). -The WCI also monitors the Task Queue backlog independently. If Tasks arrive faster than Workers can process them, the -WCI invokes additional Workers in parallel until the backlog drains or provider concurrency limits are reached. - Each invocation is independent. The Worker creates a fresh client connection on every invocation. There is no connection reuse or shared state across invocations. ## Autoscaling {#autoscaling} -Temporal automatically scales Serverless Workers based on Task Queue signals. When Tasks arrive and no Worker is -available, Temporal invokes new Workers. When the Tasks are done, Workers exit and scale to zero. +The [WCI](#worker-controller-instance) automatically scales Serverless Workers based on Task Queue signals. When Tasks +arrive and no Worker is available, the WCI invokes new Workers. When the Tasks are done, Workers exit and scale to zero. The WCI uses two signals to decide when to invoke new Workers: @@ -137,13 +134,14 @@ there are Tasks on the queue and not enough Workers, the WCI invokes additional ## Scaling with long-lived Workers {#scaling-with-long-lived-workers} -Serverless Workers can share a Task Queue with long-lived Workers. -Because Serverless Workers are only invoked on [sync match failure](#sync-match-failure), Serverless Workers only pick up Tasks that no long-lived Worker was available to handle. -In practice, the Serverless Workers act as spillover capacity for the long-lived fleet. +Serverless Workers can share a Task Queue with long-lived Workers. Because Serverless Workers are only invoked on +[sync match failure](#sync-match-failure), Serverless Workers only pick up Tasks that no long-lived Worker was available +to handle. In practice, the Serverless Workers act as spillover capacity for the long-lived fleet. -If you configure Serverless and long-lived Workers on the same Task Queue, do not enable dynamic scaling on the long-lived Workers. -The two groups cannot coordinate their scaling behavior. -If both scale dynamically, the long-lived Workers may scale up to handle the same Tasks that Temporal is simultaneously invoking Serverless Workers for, leading to unnecessary invocations and unpredictable scaling. +If you configure Serverless and long-lived Workers on the same Task Queue, do not enable dynamic scaling on the +long-lived Workers. The two groups cannot coordinate their scaling behavior. If both scale dynamically, the long-lived +Workers may scale up to handle the same Tasks that Temporal is simultaneously invoking Serverless Workers for, leading +to unnecessary invocations and unpredictable scaling. ## Worker lifecycle {#worker-lifecycle} @@ -177,8 +175,10 @@ If your Worker handles long-running Activities, set these three values together: :::tip - If your longest-running Activity runs longer than half the maximum invocation deadline, this constraint may be difficult or impossible to meet. - In this case, use [Activity Heartbeats](/detecting-activity-failures#activity-heartbeat) to record the state of the Activity execution so that the next retry can pick up where it left off. + If your longest-running Activity runs longer than half the maximum invocation deadline, this constraint may be + difficult or impossible to meet. In this case, use + [Activity Heartbeats](/detecting-activity-failures#activity-heartbeat) to record the state of the Activity execution + so that the next retry can pick up where it left off. ::: @@ -233,11 +233,11 @@ With single-slot configuration, each Activity gets a dedicated execution environ ## Constraints {#constraints} -| Constraint | Detail | -| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| Activity duration | Must complete within the compute provider's invocation limit (minus shutdown deadline buffer). For AWS Lambda, the maximum is 15 minutes. | -| Workflow duration | No limit. Workflows of any duration work, regardless of the invocation timeout. A Workflow runs across as many invocations as needed. | -| Worker code | Same Temporal SDK Worker code, using the serverless Worker package for your SDK. | +| Constraint | Detail | +| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Activity duration | Must complete within the compute provider's invocation limit (minus shutdown deadline buffer). For AWS Lambda, the maximum is 15 minutes. | +| Workflow duration | No limit. Workflows of any duration work, regardless of the invocation timeout. A Workflow runs across as many invocations 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. | ## Compute providers {#compute-providers} From 48fd201db215d4904eeaa88ce3cffbca18e75ab9 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Mon, 4 May 2026 11:40:29 -0700 Subject: [PATCH 56/62] fix broken links --- docs/encyclopedia/workers/serverless-workers.mdx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/encyclopedia/workers/serverless-workers.mdx b/docs/encyclopedia/workers/serverless-workers.mdx index f586398917..f76ad600f6 100644 --- a/docs/encyclopedia/workers/serverless-workers.mdx +++ b/docs/encyclopedia/workers/serverless-workers.mdx @@ -138,11 +138,15 @@ Serverless Workers can share a Task Queue with long-lived Workers. Because Serve [sync match failure](#sync-match-failure), Serverless Workers only pick up Tasks that no long-lived Worker was available to handle. In practice, the Serverless Workers act as spillover capacity for the long-lived fleet. +:::caution + If you configure Serverless and long-lived Workers on the same Task Queue, do not enable dynamic scaling on the long-lived Workers. The two groups cannot coordinate their scaling behavior. If both scale dynamically, the long-lived Workers may scale up to handle the same Tasks that Temporal is simultaneously invoking Serverless Workers for, leading to unnecessary invocations and unpredictable scaling. +::: + ## Worker lifecycle {#worker-lifecycle} A single Serverless Worker invocation has three phases: init, work, and shutdown. @@ -177,8 +181,8 @@ If your Worker handles long-running Activities, set these three values together: If your longest-running Activity runs longer than half the maximum invocation deadline, this constraint may be difficult or impossible to meet. In this case, use - [Activity Heartbeats](/detecting-activity-failures#activity-heartbeat) to record the state of the Activity execution - so that the next retry can pick up where it left off. + [Activity Heartbeats](/encyclopedia/detecting-activity-failures#activity-heartbeat) to record the state of the + Activity execution so that the next retry can pick up where it left off. ::: From 42edfbd5dddd4d64594c06d39749f125a138cfb6 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Mon, 4 May 2026 11:54:18 -0700 Subject: [PATCH 57/62] fix broken links --- docs/develop/go/nexus/feature-guide.mdx | 2 +- .../python/workers/serverless-workers/aws-lambda.mdx | 2 +- docs/encyclopedia/workers/worker-versioning.mdx | 2 +- docs/troubleshooting/serverless-workers.mdx | 10 +++++----- docusaurus.config.js | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/develop/go/nexus/feature-guide.mdx b/docs/develop/go/nexus/feature-guide.mdx index 6543342254..db7785653e 100644 --- a/docs/develop/go/nexus/feature-guide.mdx +++ b/docs/develop/go/nexus/feature-guide.mdx @@ -552,7 +552,7 @@ See the [Nexus cancelation sample](https://github.com/temporalio/samples-go/tree ## Make Nexus calls across Namespaces in Temporal Cloud {#nexus-calls-across-namespaces-temporal-cloud} -This section assumes you are already familiar with [how connect a Worker to Temporal Cloud](/develop/go/workers/cloud-worker). +This section assumes you are already familiar with [how to connect a Worker to Temporal Cloud](/develop/go/client/temporal-client#connect-to-temporal-cloud). The same [source code](https://github.com/temporalio/samples-go/tree/main/nexus) is used in this section, but the `tcld` CLI will be used to create Namespaces and the Nexus Endpoint, and mTLS client certificates will be used to securely connect the caller and handler Workers to their respective Temporal Cloud Namespaces. ### Install the latest `tcld` CLI and generate certificates diff --git a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx index 317de3c145..ec00f85358 100644 --- a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx @@ -64,7 +64,7 @@ lambda_handler = run_worker( `run_worker` takes a `WorkerDeploymentVersion` and a configure callback, and returns a Lambda handler. -The `WorkerDeploymentVersion` identifies the [Worker Deployment](/worker-versioning#deployments) and [Build Id](/worker-versioning#build-id) for this Worker. +The `WorkerDeploymentVersion` identifies the [Worker Deployment](/worker-versioning#deployments) and [Build ID](/worker-versioning#deployment-versions) for this Worker. The deployment name groups related Workers across versions, and the Build Id identifies a specific release of your Worker code. Worker Versioning is required for Serverless Workers. diff --git a/docs/encyclopedia/workers/worker-versioning.mdx b/docs/encyclopedia/workers/worker-versioning.mdx index 516bdd100e..f62ea2a5e1 100644 --- a/docs/encyclopedia/workers/worker-versioning.mdx +++ b/docs/encyclopedia/workers/worker-versioning.mdx @@ -34,7 +34,7 @@ Each Deployment has a name (such as your service name) and supports versioning t ## Worker Deployment Versions {#deployment-versions} A Worker Deployment Version represents an iteration of a Worker Deployment. -Each Deployment Version is identified by a deployment name and a Build ID. +Each Deployment Version is identified by a deployment name and a Build ID. The deployment name groups related Workers across versions, and the Build ID identifies a specific release of your Worker code. Each Deployment Version consists of Workers that share the same code build and environment. When a Worker starts polling for Workflow and Activity Tasks, it reports its Deployment Version to the Temporal Server. diff --git a/docs/troubleshooting/serverless-workers.mdx b/docs/troubleshooting/serverless-workers.mdx index 44664b29cd..046eddc4ec 100644 --- a/docs/troubleshooting/serverless-workers.mdx +++ b/docs/troubleshooting/serverless-workers.mdx @@ -35,9 +35,9 @@ This page walks through the Serverless Worker invocation flow and helps you iden When a Serverless Worker invocation works correctly, the following sequence happens: 1. You deploy the Worker function on Lambda. -2. You configure a [Worker Deployment Version](/worker-versioning#worker-deployment-version) with a compute provider. This starts a [Worker Controller Instance (WCI)](/serverless-workers#how-invocation-works) Workflow and a validation invocation of the Lambda function. -3. The Lambda polls the Temporal Service successfully, binding the [Task Queue](/encyclopedia/task-queues) configured on the Worker to the Worker Deployment Version. -4. The WCI continuously monitors the associated Task Queue on a schedule. The [Matching Service](/clusters#matching-service) also notifies the WCI Workflow of sync match failures immediately as they happen. +2. You configure a [Worker Deployment Version](/worker-versioning#deployment-versions) with a compute provider. This starts a [Worker Controller Instance (WCI)](/serverless-workers#how-invocation-works) Workflow and a validation invocation of the Lambda function. +3. The Lambda polls the Temporal Service successfully, binding the [Task Queue](/task-queue) configured on the Worker to the Worker Deployment Version. +4. The WCI continuously monitors the associated Task Queue on a schedule. The [Matching Service](/temporal-service/temporal-server#matching-service) also notifies the WCI Workflow of sync match failures immediately as they happen. 5. A Task arrives on the Task Queue and the WCI detects the backlog. 6. The WCI invokes the Lambda function. 7. The Lambda function starts, the Worker connects to Temporal and polls the Task Queue. @@ -71,7 +71,7 @@ role, and that the Lambda function can be invoked. 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#create-invocation-role) +[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. If the Worker Deployment Version does not have a compute provider configured, no @@ -134,7 +134,7 @@ Common errors include: - **Connection failures**: The Worker cannot reach the Temporal Service. Check that the `TEMPORAL_ADDRESS` and `TEMPORAL_API_KEY` environment variables (or `temporal.toml` config file) are correctly set on the Lambda function. For self-hosted deployments, verify - [network reachability](/production-deployment/worker-deployments/serverless-workers/self-hosted-setup#ensure-reachability). + [network reachability](/production-deployment/worker-deployments/serverless-workers/self-hosted-setup#ensure-network-reachability). - **TLS errors**: The TLS certificate or key is missing, expired, or does not match the Namespace. - **Authentication errors**: The API key is invalid or does not have access to the Namespace. diff --git a/docusaurus.config.js b/docusaurus.config.js index 7423c2aefe..310f34e1d3 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -9,8 +9,8 @@ module.exports = async function createConfigAsync() { tagline: 'Build invincible applications', url: 'https://docs.temporal.io', baseUrl: '/', - onBrokenLinks: 'warn', - onBrokenAnchors: 'warn', + onBrokenLinks: 'throw', + onBrokenAnchors: 'throw', favicon: 'img/favicon.ico', organizationName: 'temporalio', // Usually your GitHub org/user name. projectName: 'temporal-documentation', // Usually your repo name. From a5aef733ea5c669475388a4bd78ea0bcdede2f62 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Mon, 4 May 2026 13:33:25 -0700 Subject: [PATCH 58/62] address adot issue --- docs/develop/python/workers/serverless-workers/aws-lambda.mdx | 3 +-- .../typescript/workers/serverless-workers/aws-lambda.mdx | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx index ec00f85358..0d376c2b88 100644 --- a/docs/develop/python/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/python/workers/serverless-workers/aws-lambda.mdx @@ -213,9 +213,8 @@ service: ``` -Set the following environment variables on the Lambda function: +Set the following environment variable on the Lambda function: -- `AWS_LAMBDA_EXEC_WRAPPER=/opt/otel-instrument` - `OPENTELEMETRY_COLLECTOR_CONFIG_FILE=/var/task/otel-collector-config.yaml` Enable X-Ray active tracing on the Lambda function: diff --git a/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx b/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx index 02efdb9e02..bdcd301989 100644 --- a/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx +++ b/docs/develop/typescript/workers/serverless-workers/aws-lambda.mdx @@ -204,9 +204,8 @@ service: ``` -Set the following environment variables on the Lambda function: +Set the following environment variable on the Lambda function: -- `AWS_LAMBDA_EXEC_WRAPPER=/opt/otel-handler` - `OPENTELEMETRY_COLLECTOR_CONFIG_URI=/var/task/otel-collector-config.yaml` Enable X-Ray active tracing on the Lambda function: From 61c592eabd6a984d4b054181cfbe61d77506f61a Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Mon, 4 May 2026 16:02:15 -0700 Subject: [PATCH 59/62] adjust demo contrast --- .../elements/serverless-worker-demo.module.css | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/components/elements/serverless-worker-demo.module.css b/src/components/elements/serverless-worker-demo.module.css index ac7b6919fc..6ae6f1c652 100644 --- a/src/components/elements/serverless-worker-demo.module.css +++ b/src/components/elements/serverless-worker-demo.module.css @@ -319,6 +319,10 @@ color: var(--ifm-color-success-darkest, #2e7d32); } +[data-theme='dark'] .logLine_success .logMsg { + color: var(--ifm-color-success-lightest, #81c784); +} + .logLine_error .logMsg { color: var(--ifm-color-danger); } @@ -327,6 +331,10 @@ color: var(--ifm-color-warning-darkest, #e65100); } +[data-theme='dark'] .logLine_warn .logMsg { + color: var(--ifm-color-warning-lightest, #ffb74d); +} + /* ── Result banner ──────────────────────────────────────────────────────── */ .resultSuccess { @@ -340,6 +348,11 @@ color: var(--ifm-color-success-darkest, #2e7d32); } +[data-theme='dark'] .resultSuccess { + color: var(--ifm-color-success-lightest, #81c784); + background: rgba(76, 175, 80, 0.15); +} + /* ── Steps (clickable) ──────────────────────────────────────────────────── */ .stepsContainer { From f45aed6bfece95e37093d03bed6c8e7e272b718d Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Mon, 4 May 2026 16:24:19 -0700 Subject: [PATCH 60/62] small interactive demo polush --- .../serverless-workers/demo.mdx | 2 +- .../elements/ServerlessWorkerDemo.js | 69 ++++++++-------- .../serverless-worker-demo.module.css | 79 ++++++++++++++++--- 3 files changed, 102 insertions(+), 48 deletions(-) diff --git a/docs/evaluate/development-production-features/serverless-workers/demo.mdx b/docs/evaluate/development-production-features/serverless-workers/demo.mdx index bb004e14e8..040702657c 100644 --- a/docs/evaluate/development-production-features/serverless-workers/demo.mdx +++ b/docs/evaluate/development-production-features/serverless-workers/demo.mdx @@ -45,5 +45,5 @@ import { ServerlessWorkerDemo } from '@site/src/components'; ## Next steps -- [Serverless Workers - Go SDK](/develop/go/workers/serverless-workers/aws-lambda) for SDK-specific configuration, defaults, and lifecycle details. +- [Serverless Workers](/serverless-workers) for concepts, autoscaling, and lifecycle details. - [Deploy a Serverless Worker](/production-deployment/worker-deployments/serverless-workers) for the full end-to-end deployment guide. diff --git a/src/components/elements/ServerlessWorkerDemo.js b/src/components/elements/ServerlessWorkerDemo.js index 4161a9c4fe..e83ab1ee7a 100644 --- a/src/components/elements/ServerlessWorkerDemo.js +++ b/src/components/elements/ServerlessWorkerDemo.js @@ -253,9 +253,6 @@ export default function ServerlessWorkerDemo() { })); }; - // Jump to the last step and start simulation - setActiveStep(STEPS.length - 1); - setSim({ running: true, nodeStates: [...IDLE_NODES], @@ -355,9 +352,10 @@ export default function ServerlessWorkerDemo() {
{/* ── Simulation: the main interactive area ── */}
-
-
-

Serverless Worker Flow

+

Serverless Worker Flow

+
+ +
{FLOW_NODES.map((node, i) => ( @@ -383,10 +381,29 @@ export default function ServerlessWorkerDemo() { ))}
-
+
-
-

Execution Log

+
+ +
+ +

Execution Log

+

Configuration

+ +
{sim.log.length === 0 ? (
@@ -403,34 +420,13 @@ export default function ServerlessWorkerDemo() {
)) )} -
- - {sim.status === 'completed' && ( -
Workflow completed successfully.
- )} -
-
- -
-
- -
+
+
-
-

Configuration

+
-
- + diff --git a/src/components/elements/serverless-worker-demo.module.css b/src/components/elements/serverless-worker-demo.module.css index 6ae6f1c652..d58eb91d90 100644 --- a/src/components/elements/serverless-worker-demo.module.css +++ b/src/components/elements/serverless-worker-demo.module.css @@ -40,20 +40,73 @@ /* ── Two-column layout (simulation + config) ──────────────────────────── */ .columns { - display: flex; - gap: 24px; - align-items: flex-start; + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-rows: auto auto 1fr auto; + gap: 8px 24px; } -.leftCol, -.rightCol { - flex: 1; - min-width: 0; +.row1Left { + grid-column: 1; + grid-row: 1; + align-self: end; +} + +.row1Right { + grid-column: 2; + grid-row: 1; + align-self: end; +} + +.row2Left { + grid-column: 1; + grid-row: 2; + align-self: center; +} + +.row2Right { + grid-column: 2; + grid-row: 2; + align-self: center; +} + +.row3Left { + grid-column: 1; + grid-row: 3; + align-self: end; + padding-top: 16px; +} + +.row3Right { + grid-column: 2; + grid-row: 3; + align-self: end; + padding-top: 16px; +} + +.row4Left { + grid-column: 1; + grid-row: 4; + margin-bottom: 20px; +} + +.row4Right { + grid-column: 2; + grid-row: 4; + margin-bottom: 20px; } @media (max-width: 900px) { .columns { - flex-direction: column; + grid-template-columns: 1fr; + grid-template-rows: auto; + } + .row1Left, .row1Right, + .row2Left, .row2Right, + .row3Left, .row3Right, + .row4Left, .row4Right { + grid-column: 1; + grid-row: auto; } } @@ -282,18 +335,24 @@ border: 1px solid var(--ifm-color-emphasis-200); border-radius: 6px; padding: 12px; - max-height: 260px; + min-height: 100%; + max-height: 300px; overflow-y: auto; font-family: var(--ifm-font-family-monospace); font-size: 0.78rem; line-height: 1.6; + display: flex; + flex-direction: column; } .logPlaceholder { color: var(--ifm-font-color-secondary); font-style: italic; text-align: center; - padding: 24px 0; + flex: 1; + display: flex; + align-items: center; + justify-content: center; } .logLine { From 960fd0556c7e1e0c40e1c378ddf39a33c2a03399 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Mon, 4 May 2026 16:28:08 -0700 Subject: [PATCH 61/62] update demo sample to pinned --- src/components/elements/ServerlessWorkerDemo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/elements/ServerlessWorkerDemo.js b/src/components/elements/ServerlessWorkerDemo.js index e83ab1ee7a..8a4ac002ff 100644 --- a/src/components/elements/ServerlessWorkerDemo.js +++ b/src/components/elements/ServerlessWorkerDemo.js @@ -25,7 +25,7 @@ func main() { \t\topts.TaskQueue = "${taskQueue}" \t\topts.RegisterWorkflowWithOptions(MyWorkflow, workflow.RegisterOptions{ -\t\t\tVersioningBehavior: workflow.VersioningBehaviorAutoUpgrade, +\t\t\tVersioningBehavior: workflow.VersioningBehaviorPinned, \t\t}) \t\topts.RegisterActivity(MyActivity) From c83841a8d0122c49fde616e683a4a19ff202f3ce Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Mon, 4 May 2026 16:32:14 -0700 Subject: [PATCH 62/62] small polish --- .../serverless-workers/self-hosted-setup.mdx | 2 ++ src/components/elements/ServerlessWorkerDemo.js | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx b/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx index 045616ed51..850cee499c 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/self-hosted-setup.mdx @@ -27,6 +27,8 @@ APIs are experimental and may be subject to backwards-incompatible changes. ::: +Serverless Workers require Temporal Service v1.31.0 or later. + This page covers the prerequisites for running [Serverless Workers](/serverless-workers) on a self-hosted Temporal Service with AWS Lambda: diff --git a/src/components/elements/ServerlessWorkerDemo.js b/src/components/elements/ServerlessWorkerDemo.js index 8a4ac002ff..34b7fd4044 100644 --- a/src/components/elements/ServerlessWorkerDemo.js +++ b/src/components/elements/ServerlessWorkerDemo.js @@ -170,8 +170,8 @@ const STEPS = [ const FLOW_NODES = [ { label: 'Start', sub: 'Client' }, { label: 'Task Queue', sub: 'No pollers' }, - { label: 'Temporal', sub: 'Invokes Lambda' }, - { label: 'Worker', sub: 'Lambda' }, + { label: 'Temporal', sub: 'Invokes Worker' }, + { label: 'Worker', sub: 'Processing' }, { label: 'Done', sub: 'Result' }, ]; @@ -449,7 +449,7 @@ export default function ServerlessWorkerDemo() { onChange={(v) => updateConfig('namespace', v)} />