From ef66cde2919d4a018443471f2017a4f36b32240c Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Fri, 14 Aug 2026 13:26:46 -0700 Subject: [PATCH 1/6] docs: add Cloud Run Serverless Worker pages for Java, .NET, TypeScript, Ruby, and Rust Restores the TypeScript Cloud Run page and adds Cloud Run guides for Java, .NET, Ruby, and Rust. Each page was written from a worker that was built, deployed to a Cloud Run worker pool starting at 0 instances, and confirmed to run a Workflow through WCI scale-from-zero. Documents the packaging traps that testing surfaced: - TypeScript: node:22-slim ships without a CA bundle, so the SDK's Rust core fails at startup with NativeCertsNotFound. The existing Dockerfile in the deployment guide had this bug. - Ruby: install the precompiled gem, since Bundler can select the source gem and fail without a Rust toolchain. - Rust: the build needs libprotobuf-dev alongside protobuf-compiler, and debian:bookworm-slim needs ca-certificates added. - Java: the JVM defaults max heap to 25% of the container limit. Also fixes two unrelated Rust snippet bugs found while verifying that work. The versioned-Worker snippet in worker-process.mdx imported the raw proto VersioningBehavior, which stopped type-checking when SDK 0.6.0 added a first-class temporalio_common::worker::VersioningBehavior. The quickstart never built as written: its Cargo.toml omitted temporalio-workflow, which the Workflow macros expand to reference, and register_workflow was missing the ? it needs before build(). Both pages now compile against 0.6.0. vercel.json drops a duplicate JSON key that had silently disabled the /llms-api-reference.txt redirect. --- .../workers/serverless-workers/cloud-run.mdx | 138 ++++++++ .../workers/serverless-workers/index.mdx | 8 +- .../workers/serverless-workers/cloud-run.mdx | 159 +++++++++ .../java/workers/serverless-workers/index.mdx | 8 +- .../workers/serverless-workers/cloud-run.mdx | 133 ++++++++ .../ruby/workers/serverless-workers/index.mdx | 29 ++ docs/develop/rust/quickstart.mdx | 16 +- .../workers/serverless-workers/cloud-run.mdx | 150 +++++++++ .../rust/workers/serverless-workers/index.mdx | 29 ++ docs/develop/rust/workers/worker-process.mdx | 19 +- .../workers/serverless-workers/cloud-run.mdx | 152 +++++++++ .../workers/serverless-workers/index.mdx | 6 +- .../workers/serverless-workers/cloud-run.mdx | 5 + .../serverless-workers/index.mdx | 6 +- .../serverless-workers/cloud-run/index.mdx | 312 +++++++++++++++++- sidebars.js | 31 +- vercel.json | 2 - 17 files changed, 1176 insertions(+), 27 deletions(-) create mode 100644 docs/develop/dotnet/workers/serverless-workers/cloud-run.mdx create mode 100644 docs/develop/java/workers/serverless-workers/cloud-run.mdx create mode 100644 docs/develop/ruby/workers/serverless-workers/cloud-run.mdx create mode 100644 docs/develop/ruby/workers/serverless-workers/index.mdx create mode 100644 docs/develop/rust/workers/serverless-workers/cloud-run.mdx create mode 100644 docs/develop/rust/workers/serverless-workers/index.mdx create mode 100644 docs/develop/typescript/workers/serverless-workers/cloud-run.mdx diff --git a/docs/develop/dotnet/workers/serverless-workers/cloud-run.mdx b/docs/develop/dotnet/workers/serverless-workers/cloud-run.mdx new file mode 100644 index 0000000000..6cc80847a9 --- /dev/null +++ b/docs/develop/dotnet/workers/serverless-workers/cloud-run.mdx @@ -0,0 +1,138 @@ +--- +id: cloud-run +title: Serverless Workers on GCP Cloud Run - .NET SDK +sidebar_label: GCP Cloud Run +description: Run a Temporal Worker on a GCP Cloud Run worker pool using the .NET SDK. +slug: /develop/dotnet/workers/serverless-workers/cloud-run +toc_max_heading_level: 4 +tags: + - Workers + - .NET SDK + - Serverless + - GCP Cloud Run +--- + +import { ReleaseNoteHeader } from '@site/src/components'; + + + Cloud Run support is in Pre-release, and its APIs may change in backwards-incompatible ways. + Create a [support ticket](/cloud/support#support-ticket) or contact your account team for access, and + [sign up for updates](https://temporal.io/pages/serverless-workers-updates) to hear when Cloud Run reaches Public Preview. + + +On a [GCP Cloud Run worker pool](https://cloud.google.com/run/docs/resource-model#worker-pools), you run a standard long-lived Temporal Worker. +Register Workflows and Activities the same way you would with any other .NET Worker, and Temporal Cloud scales the pool up and down as work arrives and drains. + +A Cloud Run Worker needs no Cloud Run-specific package. +The one addition to a standard Worker is Worker Versioning, which is required for Serverless Workers. + +For the end-to-end deployment guide covering the Worker Pool, IAM, and compute configuration, see [Deploy a Serverless Worker on GCP Cloud Run](/production-deployment/worker-deployments/serverless-workers/cloud-run). + +## Create a versioned Worker {/* #versioned-worker */} + +Build the Worker as you would any long-running .NET Worker, then set `DeploymentOptions` on `TemporalWorkerOptions` to declare the Worker Deployment Version and turn versioning on. + +The following Worker reads its connection settings and Task Queue from the environment, so the same image can run against any Namespace: + +```csharp +using Temporalio.Client; +using Temporalio.Worker; + +var client = await TemporalClient.ConnectAsync(new(Environment.GetEnvironmentVariable("TEMPORAL_ADDRESS")!) +{ + Namespace = Environment.GetEnvironmentVariable("TEMPORAL_NAMESPACE")!, + ApiKey = Environment.GetEnvironmentVariable("TEMPORAL_API_KEY"), + Tls = new(), +}); + +var options = new TemporalWorkerOptions(Environment.GetEnvironmentVariable("TEMPORAL_TASK_QUEUE")!) +{ + DeploymentOptions = new(new("my-app", "build-1"), useWorkerVersioning: true) + { + DefaultVersioningBehavior = Temporalio.Common.VersioningBehavior.Pinned, + }, +}; +options.AddWorkflow(); +options.AddActivity(MyActivities.Greet); + +using var worker = new TemporalWorker(client, options); +await worker.ExecuteAsync(CancellationToken.None); +``` + +The two arguments to `WorkerDeploymentVersion` are the deployment name and the build ID, and together they identify the Worker Deployment Version. Both values must match the version you create with `temporal worker deployment create-version` in the deployment guide, or the Worker polls under a version the WCI does not manage. + +Every Workflow needs a [versioning behavior](/worker-versioning#versioning-behaviors), either `Pinned` or `AutoUpgrade`. +Setting `DefaultVersioningBehavior` as shown above covers every Workflow on the Worker. +To set the behavior per Workflow instead, set `VersioningBehavior` on the `Workflow` attribute: + +```csharp +using Temporalio.Common; +using Temporalio.Workflows; + +[Workflow(VersioningBehavior = VersioningBehavior.Pinned)] +public class MyWorkflow +{ + [WorkflowRun] + public async Task RunAsync(string name) => // ... +} +``` + +For general Worker setup and options that are not specific to Cloud Run, see [Run a Worker](/develop/dotnet/workers/run-worker-process). + +## Configure the Temporal connection {/* #configure-connection */} + +Read the Namespace, address, and Task Queue from environment variables you set on the Worker Pool, and mount the Temporal Cloud API key or TLS material from Secret Manager rather than passing it in plaintext. +The Worker above reads `TEMPORAL_ADDRESS`, `TEMPORAL_NAMESPACE`, `TEMPORAL_API_KEY`, and `TEMPORAL_TASK_QUEUE`, so the same image can run against any Namespace. + +To load those values through the shared configuration format instead of reading them yourself, use `ClientEnvConfig.LoadClientConnectOptions()` from the `Temporalio.Common.EnvConfig` namespace. +For the full list of supported variables, the config file format, and profiles, see [Environment configuration](/develop/environment-configuration). + +## Package the Worker image {/* #package-image */} + +Publish the Worker and run it on a .NET runtime image: + +```dockerfile +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build + +WORKDIR /src +COPY *.csproj ./ +RUN dotnet restore +COPY . . +RUN dotnet publish -c Release -o /out + +FROM mcr.microsoft.com/dotnet/runtime:9.0 + +WORKDIR /app +COPY --from=build /out ./ +CMD ["dotnet", "MyWorker.dll"] +``` + +The Worker runs on a Rust core that reads TLS roots from the operating system's certificate store, so the runtime image must include one. +The Debian-based `mcr.microsoft.com/dotnet/runtime` images do. + +## Keep Activities safe across scale-in {/* #scale-in */} + +The WCI decides when to remove an instance from Task Queue activity, not from what an individual instance is doing. +An instance running a long Activity can be stopped mid-execution. + +Use [Activity Heartbeats](/develop/dotnet/activities/timeouts#activity-heartbeats) so a retry resumes from the last recorded progress instead of starting over: + +```csharp +[Activity] +public static string Process(IReadOnlyList items) +{ + for (var i = 0; i < items.Count; i++) + { + ActivityExecutionContext.Current.Heartbeat(i); + // ... process items[i] + } + return "done"; +} +``` + +For how scale-in decisions are made, see [Serverless Workers on GCP Cloud Run](/serverless-workers/cloud-run#lifecycle). + +## Add observability {/* #add-observability */} + +A Cloud Run Worker emits the same traces and metrics as a Worker anywhere else. +For how to configure metrics export and OpenTelemetry tracing interceptors, see [Observability - .NET SDK](/develop/dotnet/platform/observability) and the [SDK metrics reference](/references/sdk-metrics). diff --git a/docs/develop/dotnet/workers/serverless-workers/index.mdx b/docs/develop/dotnet/workers/serverless-workers/index.mdx index 68e8e38198..999d872af9 100644 --- a/docs/develop/dotnet/workers/serverless-workers/index.mdx +++ b/docs/develop/dotnet/workers/serverless-workers/index.mdx @@ -17,7 +17,12 @@ tags: import { ReleaseNoteHeader } from '@site/src/components'; - + + AWS Lambda support is in Public Preview. GCP Cloud Run support is in Pre-release, and its APIs may change in + backwards-incompatible ways. To request Cloud Run access, create a [support ticket](/cloud/support#support-ticket) or + contact your account team, and [sign up for updates](https://temporal.io/pages/serverless-workers-updates) to hear + when Cloud Run reaches Public Preview. + 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. @@ -28,3 +33,4 @@ For the end-to-end deployment guide, see [Deploy a Serverless Worker](/productio ## Supported providers - [**AWS Lambda**](/develop/dotnet/workers/serverless-workers/aws-lambda) - Use the `Temporalio.Extensions.Aws.Lambda` NuGet package to run a Worker as a Lambda function. Covers setup, configuration, Lambda-tuned defaults, observability, and the invocation lifecycle. +- [**GCP Cloud Run**](/develop/dotnet/workers/serverless-workers/cloud-run) - Run a standard Worker on a Cloud Run worker pool. Covers the versioned Worker setup, connection configuration, container packaging, and handling scale-in. diff --git a/docs/develop/java/workers/serverless-workers/cloud-run.mdx b/docs/develop/java/workers/serverless-workers/cloud-run.mdx new file mode 100644 index 0000000000..afdb46c7ba --- /dev/null +++ b/docs/develop/java/workers/serverless-workers/cloud-run.mdx @@ -0,0 +1,159 @@ +--- +id: cloud-run +title: Serverless Workers on GCP Cloud Run - Java SDK +sidebar_label: GCP Cloud Run +description: Run a Temporal Worker on a GCP Cloud Run worker pool using the Java SDK. +slug: /develop/java/workers/serverless-workers/cloud-run +toc_max_heading_level: 4 +tags: + - Workers + - Java SDK + - Serverless + - GCP Cloud Run +--- + +import { ReleaseNoteHeader } from '@site/src/components'; + + + Cloud Run support is in Pre-release, and its APIs may change in backwards-incompatible ways. + Create a [support ticket](/cloud/support#support-ticket) or contact your account team for access, and + [sign up for updates](https://temporal.io/pages/serverless-workers-updates) to hear when Cloud Run reaches Public Preview. + + +On a [GCP Cloud Run worker pool](https://cloud.google.com/run/docs/resource-model#worker-pools), you run a standard long-lived Temporal Worker. +Register Workflows and Activities the same way you would with any other Java Worker, and Temporal Cloud scales the pool up and down as work arrives and drains. + +A Cloud Run Worker needs no Cloud Run-specific package. +The one addition to a standard Worker is Worker Versioning, which is required for Serverless Workers. + +For the end-to-end deployment guide covering the Worker Pool, IAM, and compute configuration, see [Deploy a Serverless Worker on GCP Cloud Run](/production-deployment/worker-deployments/serverless-workers/cloud-run). + +## Create a versioned Worker {/* #versioned-worker */} + +Build the Worker as you would any long-running Java Worker, then set `WorkerDeploymentOptions` on [`WorkerOptions`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/worker/WorkerOptions.html) to declare the Worker Deployment Version and turn versioning on. + +The following Worker reads its connection settings and Task Queue from the environment, so the same image can run against any Namespace: + +```java +package example; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowClientOptions; +import io.temporal.common.VersioningBehavior; +import io.temporal.common.WorkerDeploymentVersion; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.serviceclient.WorkflowServiceStubsOptions; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerDeploymentOptions; +import io.temporal.worker.WorkerFactory; +import io.temporal.worker.WorkerOptions; + +public class WorkerMain { + public static void main(String[] args) { + String apiKey = System.getenv("TEMPORAL_API_KEY"); + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs( + WorkflowServiceStubsOptions.newBuilder() + .setTarget(System.getenv("TEMPORAL_ADDRESS")) + .setEnableHttps(true) + .addApiKey(() -> apiKey) + .build()); + + WorkflowClient client = + WorkflowClient.newInstance( + service, + WorkflowClientOptions.newBuilder() + .setNamespace(System.getenv("TEMPORAL_NAMESPACE")) + .build()); + + WorkerFactory factory = WorkerFactory.newInstance(client); + + Worker worker = + factory.newWorker( + System.getenv("TEMPORAL_TASK_QUEUE"), + WorkerOptions.newBuilder() + .setDeploymentOptions( + WorkerDeploymentOptions.newBuilder() + .setUseVersioning(true) + .setVersion(new WorkerDeploymentVersion("my-app", "build-1")) + .setDefaultVersioningBehavior(VersioningBehavior.PINNED) + .build()) + .build()); + + worker.registerWorkflowImplementationTypes(MyWorkflowImpl.class); + worker.registerActivitiesImplementations(new MyActivitiesImpl()); + + factory.start(); + } +} +``` + +The two arguments to `WorkerDeploymentVersion` are the deployment name and the build ID, and together they identify the Worker Deployment Version. Both values must match the version you create with `temporal worker deployment create-version` in the deployment guide, or the Worker polls under a version the WCI does not manage. + +Every Workflow needs a [versioning behavior](/worker-versioning#versioning-behaviors), either `PINNED` or `AUTO_UPGRADE`. +Setting `setDefaultVersioningBehavior` as shown above covers every Workflow on the Worker. +To set the behavior per Workflow instead, annotate the Workflow method with `@WorkflowVersioningBehavior`: + +```java +import io.temporal.common.VersioningBehavior; +import io.temporal.workflow.WorkflowVersioningBehavior; + +public class MyWorkflowImpl implements MyWorkflow { + @Override + @WorkflowVersioningBehavior(VersioningBehavior.PINNED) + public String run(String name) { + // ... + } +} +``` + +For general Worker setup and options that are not specific to Cloud Run, see [Run a Worker](/develop/java/workers/run-worker-process). + +## Configure the Temporal connection {/* #configure-connection */} + +Read the Namespace, address, and Task Queue from environment variables you set on the Worker Pool, and mount the Temporal Cloud API key or TLS material from Secret Manager rather than passing it in plaintext. +The Worker above reads `TEMPORAL_ADDRESS`, `TEMPORAL_NAMESPACE`, `TEMPORAL_API_KEY`, and `TEMPORAL_TASK_QUEUE`, so the same image can run against any Namespace. + +`addApiKey` takes a supplier, which the SDK calls on each request. Rotate the key by returning a new value from the supplier instead of restarting the Worker. + +For TLS client certificates instead of an API key, see [Connect to Temporal Cloud](/develop/java/client/temporal-client). + +## Package the Worker image {/* #package-image */} + +Cloud Run runs one JVM per instance, so give the JVM a heap sized to the instance rather than to the host. +Java reads the container's memory limit and defaults the maximum heap to a quarter of it, which leaves most of a small instance unused. +Set `-XX:MaxRAMPercentage` to raise that share: + +```dockerfile +CMD ["java", "-XX:MaxRAMPercentage=75", "-jar", "/app/worker.jar"] +``` + +A Cloud Run Worker Pool defaults to 512 MiB per instance. Raise `--memory` when you create the pool if your Worker needs more. + +## Keep Activities safe across scale-in {/* #scale-in */} + +The WCI decides when to remove an instance from Task Queue activity, not from what an individual instance is doing. +An instance running a long Activity can be stopped mid-execution. + +Use [Activity Heartbeats](/develop/java/activities/timeouts#activity-heartbeats) so a retry resumes from the last recorded progress instead of starting over: + +```java +public class MyActivitiesImpl implements MyActivities { + @Override + public String process(List items) { + for (int i = 0; i < items.size(); i++) { + Activity.getExecutionContext().heartbeat(i); + // ... process items.get(i) + } + return "done"; + } +} +``` + +For how scale-in decisions are made, see [Serverless Workers on GCP Cloud Run](/serverless-workers/cloud-run#lifecycle). + +## Add observability {/* #add-observability */} + +A Cloud Run Worker emits the same traces and metrics as a Worker anywhere else. +For how to configure metrics export and OpenTelemetry tracing interceptors, see [Observability - Java SDK](/develop/java/platform/observability) and the [SDK metrics reference](/references/sdk-metrics). diff --git a/docs/develop/java/workers/serverless-workers/index.mdx b/docs/develop/java/workers/serverless-workers/index.mdx index 69cb6363cc..f68f5d305d 100644 --- a/docs/develop/java/workers/serverless-workers/index.mdx +++ b/docs/develop/java/workers/serverless-workers/index.mdx @@ -17,7 +17,12 @@ tags: import { ReleaseNoteHeader } from '@site/src/components'; - + + AWS Lambda support is in Public Preview. GCP Cloud Run support is in Pre-release, and its APIs may change in + backwards-incompatible ways. To request Cloud Run access, create a [support ticket](/cloud/support#support-ticket) or + contact your account team, and [sign up for updates](https://temporal.io/pages/serverless-workers-updates) to hear + when Cloud Run reaches Public Preview. + 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. @@ -28,3 +33,4 @@ For the end-to-end deployment guide, see [Deploy a Serverless Worker](/productio ## Supported providers - [**AWS Lambda**](/develop/java/workers/serverless-workers/aws-lambda) - Use the `temporal-aws-lambda` contrib module to run a Worker as a Lambda function. Covers setup, configuration, Lambda-tuned defaults, observability, and the invocation lifecycle. +- [**GCP Cloud Run**](/develop/java/workers/serverless-workers/cloud-run) - Run a standard Worker on a Cloud Run worker pool. Covers the versioned Worker setup, connection configuration, container packaging, and handling scale-in. diff --git a/docs/develop/ruby/workers/serverless-workers/cloud-run.mdx b/docs/develop/ruby/workers/serverless-workers/cloud-run.mdx new file mode 100644 index 0000000000..fac0e96aa4 --- /dev/null +++ b/docs/develop/ruby/workers/serverless-workers/cloud-run.mdx @@ -0,0 +1,133 @@ +--- +id: cloud-run +title: Serverless Workers on GCP Cloud Run - Ruby SDK +sidebar_label: GCP Cloud Run +description: Run a Temporal Worker on a GCP Cloud Run worker pool using the Ruby SDK. +slug: /develop/ruby/workers/serverless-workers/cloud-run +toc_max_heading_level: 4 +tags: + - Workers + - Ruby SDK + - Serverless + - GCP Cloud Run +--- + +import { ReleaseNoteHeader } from '@site/src/components'; + + + Cloud Run support is in Pre-release, and its APIs may change in backwards-incompatible ways. + Create a [support ticket](/cloud/support#support-ticket) or contact your account team for access, and + [sign up for updates](https://temporal.io/pages/serverless-workers-updates) to hear when Cloud Run reaches Public Preview. + + +On a [GCP Cloud Run worker pool](https://cloud.google.com/run/docs/resource-model#worker-pools), you run a standard long-lived Temporal Worker. +Register Workflows and Activities the same way you would with any other Ruby Worker, and Temporal Cloud scales the pool up and down as work arrives and drains. + +A Cloud Run Worker needs no Cloud Run-specific gem. +The one addition to a standard Worker is Worker Versioning, which is required for Serverless Workers. + +For the end-to-end deployment guide covering the Worker Pool, IAM, and compute configuration, see [Deploy a Serverless Worker on GCP Cloud Run](/production-deployment/worker-deployments/serverless-workers/cloud-run). + +## Create a versioned Worker {/* #versioned-worker */} + +Build the Worker as you would any long-running Ruby Worker, then pass `deployment_options` to `Temporalio::Worker.new` to declare the Worker Deployment Version and turn versioning on. + +The following Worker reads its connection settings and Task Queue from the environment, so the same image can run against any Namespace: + +```ruby +require 'temporalio/client' +require 'temporalio/worker' + +client = Temporalio::Client.connect( + ENV.fetch('TEMPORAL_ADDRESS'), + ENV.fetch('TEMPORAL_NAMESPACE'), + api_key: ENV.fetch('TEMPORAL_API_KEY'), + tls: true +) + +worker = Temporalio::Worker.new( + client:, + task_queue: ENV.fetch('TEMPORAL_TASK_QUEUE'), + workflows: [MyWorkflow], + activities: [Greet], + deployment_options: Temporalio::Worker::DeploymentOptions.new( + version: Temporalio::WorkerDeploymentVersion.new( + deployment_name: 'my-app', + build_id: 'build-1' + ), + use_worker_versioning: true, + default_versioning_behavior: Temporalio::VersioningBehavior::PINNED + ) +) + +worker.run +``` + +`deployment_name` and `build_id` together identify the Worker Deployment Version. Both values must match the version you create with `temporal worker deployment create-version` in the deployment guide, or the Worker polls under a version the WCI does not manage. + +Every Workflow needs a [versioning behavior](/worker-versioning#versioning-behaviors), either `PINNED` or `AUTO_UPGRADE`. +Setting `default_versioning_behavior` as shown above covers every Workflow on the Worker. +To set the behavior per Workflow instead, call `workflow_versioning_behavior` in the Workflow class: + +```ruby +class MyWorkflow < Temporalio::Workflow::Definition + workflow_versioning_behavior Temporalio::VersioningBehavior::PINNED + + def execute(name) + # ... + end +end +``` + +If versioning is on and neither is set, the Worker raises an error at startup rather than polling. + +For general Worker setup and options that are not specific to Cloud Run, see [Run a Worker](/develop/ruby/workers/run-worker-process). + +## Configure the Temporal connection {/* #configure-connection */} + +Read the Namespace, address, and Task Queue from environment variables you set on the Worker Pool, and mount the Temporal Cloud API key or TLS material from Secret Manager rather than passing it in plaintext. +The Worker above reads `TEMPORAL_ADDRESS`, `TEMPORAL_NAMESPACE`, `TEMPORAL_API_KEY`, and `TEMPORAL_TASK_QUEUE`, so the same image can run against any Namespace. + +For the shared configuration format that other Temporal tools read, see [Environment configuration](/develop/environment-configuration). + +## Package the Worker image {/* #package-image */} + +The Ruby SDK ships precompiled gems per platform, so install it in the image rather than building the native extension from source: + +```dockerfile +FROM ruby:3.3-slim + +WORKDIR /app +RUN gem install temporalio --no-document +COPY worker.rb ./ + +CMD ["ruby", "worker.rb"] +``` + +Installing through Bundler in a container can select the source gem instead of the precompiled one, which then fails to build without a Rust toolchain. If you use Bundler, add the target platform to the lockfile with `bundle lock --add-platform x86_64-linux`. + +## Keep Activities safe across scale-in {/* #scale-in */} + +The WCI decides when to remove an instance from Task Queue activity, not from what an individual instance is doing. +An instance running a long Activity can be stopped mid-execution. + +Use [Activity Heartbeats](/develop/ruby/activities/timeouts#activity-heartbeats) so a retry resumes from the last recorded progress instead of starting over: + +```ruby +class Process < Temporalio::Activity::Definition + def execute(items) + items.each_with_index do |item, i| + Temporalio::Activity::Context.current.heartbeat(i) + # ... process item + end + 'done' + end +end +``` + +For how scale-in decisions are made, see [Serverless Workers on GCP Cloud Run](/serverless-workers/cloud-run#lifecycle). + +## Add observability {/* #add-observability */} + +A Cloud Run Worker emits the same traces and metrics as a Worker anywhere else. +For how to configure metrics export and OpenTelemetry tracing interceptors, see [Observability - Ruby SDK](/develop/ruby/platform/observability) and the [SDK metrics reference](/references/sdk-metrics). diff --git a/docs/develop/ruby/workers/serverless-workers/index.mdx b/docs/develop/ruby/workers/serverless-workers/index.mdx new file mode 100644 index 0000000000..8d7d3bfb22 --- /dev/null +++ b/docs/develop/ruby/workers/serverless-workers/index.mdx @@ -0,0 +1,29 @@ +--- +id: index +title: Serverless Workers - Ruby SDK +sidebar_label: Serverless Workers +description: Write Temporal Workers that run on serverless compute using the Ruby SDK. +slug: /develop/ruby/workers/serverless-workers +toc_max_heading_level: 4 +tags: + - Workers + - Ruby SDK + - Serverless +--- + +import { ReleaseNoteHeader } from '@site/src/components'; + + + Cloud Run support is in Pre-release, and its APIs may change in backwards-incompatible ways. + Create a [support ticket](/cloud/support#support-ticket) or contact your account team for access, and + [sign up for updates](https://temporal.io/pages/serverless-workers-updates) to hear when Cloud Run reaches Public Preview. + + +Serverless Workers run on compute that Temporal starts and stops for you, rather than on long-lived processes you operate. + +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 + +- [**GCP Cloud Run**](/develop/ruby/workers/serverless-workers/cloud-run) - Run a standard Worker on a Cloud Run worker pool. Covers the versioned Worker setup, connection configuration, and handling scale-in. diff --git a/docs/develop/rust/quickstart.mdx b/docs/develop/rust/quickstart.mdx index eb50df12b4..9f1d454452 100644 --- a/docs/develop/rust/quickstart.mdx +++ b/docs/develop/rust/quickstart.mdx @@ -66,11 +66,12 @@ futures = "0.3.32" futures-util = "0.3.32" serde = { version = "1", features = ["derive"] } serde_json = "1" -temporalio-client = "0.5.0" -temporalio-common = "0.5.0" -temporalio-macros = "0.5.0" -temporalio-sdk = "0.5.0" -temporalio-sdk-core = "0.5.0" +temporalio-client = "0.6.0" +temporalio-common = "0.6.0" +temporalio-macros = "0.6.0" +temporalio-sdk = "0.6.0" +temporalio-sdk-core = "0.6.0" +temporalio-workflow = "0.6.0" tokio = { version = "1", features = ["full"] } `} @@ -89,6 +90,7 @@ Now update your project's `Cargo.toml` file to match the example and run `cargo The core dependencies you'll need are: - `temporalio-sdk` - The Rust SDK for Temporal +- `temporalio-workflow` - Referenced by the code the Workflow macros generate, so it must be a direct dependency even though your own code never names it - `tokio` - Async runtime required by the SDK - `serde` - For serialization/deserialization @@ -228,7 +230,7 @@ impl GreetingWorkflow { let name = ctx.state(|s| s.name.clone()); // Execute an activity - let greeting = ctx.start_activity( + let greeting = ctx.execute_activity( MyActivities::greet, name, ActivityOptions::start_to_close_timeout(Duration::from_secs(30)), @@ -270,7 +272,7 @@ async fn main() -> Result<(), Box> { let worker_options = WorkerOptions::new("my-task-queue") .register_activities(MyActivities) - .register_workflow::() + .register_workflow::()? .build(); Worker::new(&runtime, client, worker_options)?.run().await?; diff --git a/docs/develop/rust/workers/serverless-workers/cloud-run.mdx b/docs/develop/rust/workers/serverless-workers/cloud-run.mdx new file mode 100644 index 0000000000..0aa0625791 --- /dev/null +++ b/docs/develop/rust/workers/serverless-workers/cloud-run.mdx @@ -0,0 +1,150 @@ +--- +id: cloud-run +title: Serverless Workers on GCP Cloud Run - Rust SDK +sidebar_label: GCP Cloud Run +description: Run a Temporal Worker on a GCP Cloud Run worker pool using the Rust SDK. +slug: /develop/rust/workers/serverless-workers/cloud-run +toc_max_heading_level: 4 +tags: + - Workers + - Rust SDK + - Serverless + - GCP Cloud Run +--- + +import { ReleaseNoteHeader } from '@site/src/components'; + + + Cloud Run support is in Pre-release, and its APIs may change in backwards-incompatible ways. + Create a [support ticket](/cloud/support#support-ticket) or contact your account team for access, and + [sign up for updates](https://temporal.io/pages/serverless-workers-updates) to hear when Cloud Run reaches Public Preview. + + +The Rust SDK is in [Public Preview](/evaluate/development-production-features/release-stages#public-preview), and its API can change between releases. +The code on this page is written against `temporalio-sdk` 0.6.0. + +On a [GCP Cloud Run worker pool](https://cloud.google.com/run/docs/resource-model#worker-pools), you run a standard long-lived Temporal Worker. +Register Workflows and Activities the same way you would with any other Rust Worker, and Temporal Cloud scales the pool up and down as work arrives and drains. + +A Cloud Run Worker needs no Cloud Run-specific crate. +The one addition to a standard Worker is Worker Versioning, which is required for Serverless Workers. + +For the end-to-end deployment guide covering the Worker Pool, IAM, and compute configuration, see [Deploy a Serverless Worker on GCP Cloud Run](/production-deployment/worker-deployments/serverless-workers/cloud-run). + +## Create a versioned Worker {/* #versioned-worker */} + +Build the Worker as you would any long-running Rust Worker, then set `deployment_options` on `WorkerOptions` to declare the Worker Deployment Version and turn versioning on. + +The following Worker reads its connection settings and Task Queue from the environment, so the same image can run against any Namespace: + +```rust +use std::str::FromStr; + +use temporalio_client::{Client, ClientOptions, Connection, ConnectionOptions}; +use temporalio_common::telemetry::TelemetryOptions; +use temporalio_common::worker::{ + VersioningBehavior, WorkerDeploymentOptions, WorkerDeploymentVersion, +}; +use temporalio_sdk::{Worker, WorkerOptions}; +use temporalio_sdk_core::{CoreRuntime, RuntimeOptions, Url}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let address = std::env::var("TEMPORAL_ADDRESS")?; + let namespace = std::env::var("TEMPORAL_NAMESPACE")?; + let api_key = std::env::var("TEMPORAL_API_KEY")?; + + let runtime = CoreRuntime::new_assume_tokio( + RuntimeOptions::builder() + .telemetry_options(TelemetryOptions::builder().build()) + .build()?, + )?; + + let connection_options = ConnectionOptions::new(Url::from_str(&format!("https://{address}"))?) + .api_key(api_key) + .build(); + let connection = Connection::connect(connection_options).await?; + let client = Client::new(connection, ClientOptions::new(namespace).build())?; + + let worker_options = WorkerOptions::new(std::env::var("TEMPORAL_TASK_QUEUE")?) + .deployment_options(WorkerDeploymentOptions { + version: WorkerDeploymentVersion { + deployment_name: "my-app".to_owned(), + build_id: "build-1".to_owned(), + }, + use_worker_versioning: true, + default_versioning_behavior: Some(VersioningBehavior::Pinned), + }) + .register_workflow::()? + .register_activities(MyActivities) + .build(); + + let mut worker = Worker::new(&runtime, client, worker_options)?; + worker.run().await?; + + Ok(()) +} +``` + +`deployment_name` and `build_id` together identify the Worker Deployment Version. Both values must match the version you create with `temporal worker deployment create-version` in the deployment guide, or the Worker polls under a version the WCI does not manage. + +The Rust SDK sets the versioning behavior on the Worker rather than per Workflow, so `default_versioning_behavior` covers every Workflow the Worker registers. +Setting it to `Some(VersioningBehavior::Unspecified)` is an error at startup. +See [versioning behaviors](/worker-versioning#versioning-behaviors) for what `Pinned` and `AutoUpgrade` mean. + +For general Worker setup and options that are not specific to Cloud Run, see [Run a Worker](/develop/rust/workers/worker-process). + +## Configure the Temporal connection {/* #configure-connection */} + +Read the Namespace, address, and Task Queue from environment variables you set on the Worker Pool, and mount the Temporal Cloud API key or TLS material from Secret Manager rather than passing it in plaintext. +The Worker above reads `TEMPORAL_ADDRESS`, `TEMPORAL_NAMESPACE`, `TEMPORAL_API_KEY`, and `TEMPORAL_TASK_QUEUE`, so the same image can run against any Namespace. + +Setting `api_key` turns TLS on by default, so the connection URL needs an `https://` scheme. +To rotate the key without restarting the Worker, call `set_api_key` on the connected Client. + +For the shared configuration format that other Temporal tools read, see [Environment configuration](/develop/environment-configuration). + +## Package the Worker image {/* #package-image */} + +Compile the Worker in one stage and copy the binary into a runtime image: + +```dockerfile +FROM rust:1.92-slim AS build + +RUN apt-get update \ + && apt-get install -y --no-install-recommends pkg-config libssl-dev protobuf-compiler libprotobuf-dev \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /src +COPY Cargo.toml ./ +COPY src ./src +RUN cargo build --release + +FROM debian:bookworm-slim + +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app +COPY --from=build /src/target/release/my-worker /app/worker +CMD ["/app/worker"] +``` + +The build stage needs `libprotobuf-dev` as well as `protobuf-compiler`. The compiler package alone installs `protoc` without the well-known type definitions, and the build then fails with `google/protobuf/duration.proto: File not found`. + +The runtime stage needs `ca-certificates`. The Worker reads TLS roots from the operating system's certificate store, and `debian:bookworm-slim` ships without one. + +## Keep Activities safe across scale-in {/* #scale-in */} + +The WCI decides when to remove an instance from Task Queue activity, not from what an individual instance is doing. +An instance running a long Activity can be stopped mid-execution. + +Use [Activity Heartbeats](/develop/rust/activities/timeouts#activity-heartbeats) so a retry resumes from the last recorded progress instead of starting over. + +For how scale-in decisions are made, see [Serverless Workers on GCP Cloud Run](/serverless-workers/cloud-run#lifecycle). + +## Add observability {/* #add-observability */} + +A Cloud Run Worker emits the same traces and metrics as a Worker anywhere else. +For how to configure metrics and telemetry, see `TelemetryOptions` on the runtime and the [SDK metrics reference](/references/sdk-metrics). diff --git a/docs/develop/rust/workers/serverless-workers/index.mdx b/docs/develop/rust/workers/serverless-workers/index.mdx new file mode 100644 index 0000000000..a1c57c84ae --- /dev/null +++ b/docs/develop/rust/workers/serverless-workers/index.mdx @@ -0,0 +1,29 @@ +--- +id: index +title: Serverless Workers - Rust SDK +sidebar_label: Serverless Workers +description: Write Temporal Workers that run on serverless compute using the Rust SDK. +slug: /develop/rust/workers/serverless-workers +toc_max_heading_level: 4 +tags: + - Workers + - Rust SDK + - Serverless +--- + +import { ReleaseNoteHeader } from '@site/src/components'; + + + Cloud Run support is in Pre-release, and its APIs may change in backwards-incompatible ways. + Create a [support ticket](/cloud/support#support-ticket) or contact your account team for access, and + [sign up for updates](https://temporal.io/pages/serverless-workers-updates) to hear when Cloud Run reaches Public Preview. + + +Serverless Workers run on compute that Temporal starts and stops for you, rather than on long-lived processes you operate. + +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 + +- [**GCP Cloud Run**](/develop/rust/workers/serverless-workers/cloud-run) - Run a standard Worker on a Cloud Run worker pool. Covers the versioned Worker setup, connection configuration, and handling scale-in. diff --git a/docs/develop/rust/workers/worker-process.mdx b/docs/develop/rust/workers/worker-process.mdx index 53bf0140fe..d8b29d7b1a 100644 --- a/docs/develop/rust/workers/worker-process.mdx +++ b/docs/develop/rust/workers/worker-process.mdx @@ -11,7 +11,7 @@ tags: --- The Rust SDK is in [Public Preview](/evaluate/development-production-features/release-stages#public-preview), and its API can change between releases. -The code on this page is written against `temporalio-sdk` 0.5.0. +The code on this page is written against `temporalio-sdk` 0.6.0. ## Create and run a Worker {/* #run-a-dev-worker */} @@ -20,12 +20,12 @@ The `#[workflow]` and `#[activities]` macros expand to code that refers to the ` ```toml [dependencies] -temporalio-sdk = "0.5.0" -temporalio-client = "0.5.0" -temporalio-sdk-core = "0.5.0" -temporalio-common = "0.5.0" -temporalio-macros = "0.5.0" -temporalio-workflow = "0.5.0" +temporalio-sdk = "0.6.0" +temporalio-client = "0.6.0" +temporalio-sdk-core = "0.6.0" +temporalio-common = "0.6.0" +temporalio-macros = "0.6.0" +temporalio-workflow = "0.6.0" futures = "0.3" tokio = { version = "1", features = ["full"] } url = "2" @@ -107,9 +107,8 @@ To tune these values against real load, see [Worker performance](/develop/worker Set a Worker Deployment Version and enable versioning in `deployment_options`, then set the default versioning behavior for the Workflows on the Worker. ```rust -use temporalio_common::{ - protos::temporal::api::enums::v1::VersioningBehavior, - worker::{WorkerDeploymentOptions, WorkerDeploymentVersion}, +use temporalio_common::worker::{ + VersioningBehavior, WorkerDeploymentOptions, WorkerDeploymentVersion, }; let worker_options = WorkerOptions::new("my-task-queue") diff --git a/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx b/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx new file mode 100644 index 0000000000..ff9b6efcf3 --- /dev/null +++ b/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx @@ -0,0 +1,152 @@ +--- +id: cloud-run +title: Serverless Workers on GCP Cloud Run - TypeScript SDK +sidebar_label: GCP Cloud Run +description: Run a Temporal Worker on a GCP Cloud Run worker pool using the TypeScript SDK. +slug: /develop/typescript/workers/serverless-workers/cloud-run +toc_max_heading_level: 4 +keywords: + - serverless + - cloud run + - gcp + - google cloud + - typescript sdk + - worker + - serverless worker +tags: + - Workers + - TypeScript SDK + - Serverless + - GCP Cloud Run +--- + +import { ReleaseNoteHeader } from '@site/src/components'; + + + Cloud Run support is in Pre-release, and its APIs may change in backwards-incompatible ways. + Create a [support ticket](/cloud/support#support-ticket) or contact your account team for access, and + [sign up for updates](https://temporal.io/pages/serverless-workers-updates) to hear when Cloud Run reaches Public Preview. + + +On a [GCP Cloud Run worker pool](https://cloud.google.com/run/docs/resource-model#worker-pools), you run a standard long-lived Temporal Worker. +Register Workflows and Activities the same way you would with any other TypeScript Worker, and Temporal Cloud scales the pool up and down as work arrives and drains. + +A Cloud Run Worker needs no Cloud Run-specific package. +The one addition to a standard Worker is Worker Versioning, which is required for Serverless Workers. + +For the end-to-end deployment guide covering the Worker Pool, IAM, and compute configuration, see [Deploy a Serverless Worker on GCP Cloud Run](/production-deployment/worker-deployments/serverless-workers/cloud-run). + +## Create a versioned Worker {/* #versioned-worker */} + +Build the Worker as you would any long-running TypeScript Worker, then pass `workerDeploymentOptions` to `Worker.create()` to declare the Worker Deployment Version and turn versioning on. + +The following Worker reads its connection settings and Task Queue from the environment, so the same image can run against any Namespace: + +```ts +import { loadClientConnectConfig } from '@temporalio/envconfig'; +import { NativeConnection, Worker } from '@temporalio/worker'; +import * as activities from './activities'; + +async function run() { + const config = loadClientConnectConfig(); + const connection = await NativeConnection.connect(config.connectionOptions); + + const worker = await Worker.create({ + connection, + namespace: config.namespace, + taskQueue: process.env.TEMPORAL_TASK_QUEUE!, + workflowsPath: require.resolve('./workflows'), + activities, + workerDeploymentOptions: { + version: { deploymentName: 'my-app', buildId: 'build-1' }, + useWorkerVersioning: true, + defaultVersioningBehavior: 'PINNED', + }, + }); + + await worker.run(); +} + +run().catch((err) => { + console.error(err); + process.exit(1); +}); +``` + +`deploymentName` and `buildId` together identify the Worker Deployment Version. Both values must match the version you create with `temporal worker deployment create-version` in the deployment guide, or the Worker polls under a version the WCI does not manage. + +Every Workflow needs a [versioning behavior](/worker-versioning#versioning-behaviors), either `PINNED` or `AUTO_UPGRADE`. +Setting `defaultVersioningBehavior` as shown above covers every Workflow on the Worker. +To set the behavior per Workflow instead, pass the Workflow function to `setWorkflowOptions()` from `@temporalio/workflow`: + +```ts +import { setWorkflowOptions } from '@temporalio/workflow'; + +setWorkflowOptions({ versioningBehavior: 'PINNED' }, myWorkflow); +export async function myWorkflow(): Promise { + // ... +} +``` + +For general Worker setup and options that are not specific to Cloud Run, see [Run a Worker](/develop/typescript/workers/run-worker-process). + +## Configure the Temporal connection {/* #configure-connection */} + +The `@temporalio/envconfig` package loads Temporal Client configuration from environment variables and an optional TOML config file, so the Worker code carries no Namespace or credentials. +Set the non-secret values as environment variables on the Worker Pool, and mount the Temporal Cloud API key or TLS material from Secret Manager. +For the full list of supported variables, the config file format, and profiles, see [Environment configuration](/develop/environment-configuration). + +`loadClientConnectConfig()` returns `connectionOptions` and `namespace`. Pass `connectionOptions` to `NativeConnection.connect()` and `namespace` to `Worker.create()`, as shown above. + +## Package the Worker image {/* #package-image */} + +Two container details are specific to the TypeScript SDK, because its Worker runs on a Rust core rather than on Node.js alone. + +The Rust core reads TLS roots from the operating system's certificate store, and the slim Node.js images ship without one. +On `node:22-slim`, connecting with TLS fails at startup: + +``` +TransportError: tonic::transport::Error(Transport, NativeCertsNotFound) +``` + +Install the certificates in the runtime stage of your Dockerfile: + +```dockerfile +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates \ + && rm -rf /var/lib/apt/lists/* +``` + +Use a glibc-based image such as `node:22-slim` rather than an Alpine image. Alpine replaces glibc with musl, which the +Rust core does not support. See [Do not use Alpine](/develop/typescript/workers/run-worker-process#do-not-use-alpine). + +Node.js also sizes its heap from the host's memory rather than the container limit, so set +`NODE_OPTIONS=--max-old-space-size=` on the Worker Pool to about 80% of the instance's memory limit. A Cloud Run +Worker Pool defaults to 512 MiB per instance, so raise `--memory` if your Worker needs more. See +[Run a Worker on Docker](/develop/typescript/workers/run-worker-process#run-a-worker-on-docker). + +## Keep Activities safe across scale-in {/* #scale-in */} + +The WCI decides when to remove an instance from Task Queue activity, not from what an individual instance is doing. +An instance running a long Activity can be stopped mid-execution. + +Use [Activity Heartbeats](/develop/typescript/activities/timeouts#activity-heartbeats) so a retry resumes from the last recorded progress instead of starting over: + +```ts +import { heartbeat } from '@temporalio/activity'; + +export async function myActivity(items: string[]): Promise { + for (let i = 0; i < items.length; i++) { + heartbeat(i); + // ... process items[i] + } + return 'done'; +} +``` + +For how scale-in decisions are made, see [Serverless Workers on GCP Cloud Run](/serverless-workers/cloud-run#lifecycle). + +## Add observability {/* #add-observability */} + +A Cloud Run Worker emits the same traces and metrics as a Worker anywhere else. +For how to configure metrics export and OpenTelemetry tracing interceptors, see [Observability - TypeScript SDK](/develop/typescript/platform/observability) and the [SDK metrics reference](/references/sdk-metrics). diff --git a/docs/develop/typescript/workers/serverless-workers/index.mdx b/docs/develop/typescript/workers/serverless-workers/index.mdx index 8a60908024..17ec93aefa 100644 --- a/docs/develop/typescript/workers/serverless-workers/index.mdx +++ b/docs/develop/typescript/workers/serverless-workers/index.mdx @@ -18,7 +18,10 @@ tags: import { ReleaseNoteHeader } from '@site/src/components'; - AWS Lambda support is in Public Preview. + AWS Lambda support is in Public Preview. GCP Cloud Run support is in Pre-release, and its APIs may change in + backwards-incompatible ways. To request Cloud Run access, create a [support ticket](/cloud/support#support-ticket) or + contact your account team, and [sign up for updates](https://temporal.io/pages/serverless-workers-updates) to hear + when Cloud Run reaches Public Preview. Serverless Workers run on ephemeral, on-demand compute rather than long-lived processes. @@ -30,3 +33,4 @@ For the end-to-end deployment guide, see [Deploy a Serverless Worker](/productio ## 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. +- [**GCP Cloud Run**](/develop/typescript/workers/serverless-workers/cloud-run) - Run a standard Worker on a Cloud Run worker pool. Covers the versioned Worker setup, connection configuration, container packaging, and handling scale-in. diff --git a/docs/encyclopedia/workers/serverless-workers/cloud-run.mdx b/docs/encyclopedia/workers/serverless-workers/cloud-run.mdx index c3a13abf1f..f9bd9ab1ea 100644 --- a/docs/encyclopedia/workers/serverless-workers/cloud-run.mdx +++ b/docs/encyclopedia/workers/serverless-workers/cloud-run.mdx @@ -36,6 +36,11 @@ On Cloud Run, a Serverless Worker runs in a Worker Pool: a set of long-lived ins Each instance runs standard Worker code and processes Tasks for its whole lifetime. The [Worker Controller Instance (WCI)](/serverless-workers#worker-controller-instance) controls how many instances run; each instance manages its own polling and Task processing. +Because an instance runs an ordinary long-lived Worker, Cloud Run needs no provider-specific handler or package, unlike AWS Lambda. +Any Temporal SDK can run on a Cloud Run Worker Pool. +The one addition to a standard Worker is [Worker Versioning](/worker-versioning), which Serverless Workers require, so an SDK needs Worker Versioning support to run here. +Packaging the Worker into a container image is where the per-language differences show up, and each SDK's Cloud Run page covers them. + ## Autoscaling {/* #autoscaling */} The WCI keeps the Worker Pool sized to the amount of work arriving on the Task Queue. It combines two mechanisms: diff --git a/docs/evaluate/development-production-features/serverless-workers/index.mdx b/docs/evaluate/development-production-features/serverless-workers/index.mdx index 55096b4450..991c0d07c1 100644 --- a/docs/evaluate/development-production-features/serverless-workers/index.mdx +++ b/docs/evaluate/development-production-features/serverless-workers/index.mdx @@ -138,4 +138,8 @@ For the Worker code itself, pick your SDK and provider: | --- | --- | --- | | Go | [Lambda Workers in Go](/develop/go/workers/serverless-workers/aws-lambda) | [Cloud Run Workers in Go](/develop/go/workers/serverless-workers/cloud-run) | | Python | [Lambda Workers in Python](/develop/python/workers/serverless-workers/aws-lambda) | [Cloud Run Workers in Python](/develop/python/workers/serverless-workers/cloud-run) | -| TypeScript | [Lambda Workers in TypeScript](/develop/typescript/workers/serverless-workers/aws-lambda) | | +| TypeScript | [Lambda Workers in TypeScript](/develop/typescript/workers/serverless-workers/aws-lambda) | [Cloud Run Workers in TypeScript](/develop/typescript/workers/serverless-workers/cloud-run) | +| Java | [Lambda Workers in Java](/develop/java/workers/serverless-workers/aws-lambda) | [Cloud Run Workers in Java](/develop/java/workers/serverless-workers/cloud-run) | +| .NET | [Lambda Workers in .NET](/develop/dotnet/workers/serverless-workers/aws-lambda) | [Cloud Run Workers in .NET](/develop/dotnet/workers/serverless-workers/cloud-run) | +| Ruby | | [Cloud Run Workers in Ruby](/develop/ruby/workers/serverless-workers/cloud-run) | +| Rust | | [Cloud Run Workers in Rust](/develop/rust/workers/serverless-workers/cloud-run) | diff --git a/docs/production-deployment/worker-deployments/serverless-workers/cloud-run/index.mdx b/docs/production-deployment/worker-deployments/serverless-workers/cloud-run/index.mdx index 86738847f1..10961fb03e 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/cloud-run/index.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/cloud-run/index.mdx @@ -35,6 +35,10 @@ A Cloud Run Worker Pool runs long-lived instances that poll the Task Queue conti through the Cloud Run admin API as work arrives and drains. For how the pool scales and how instances are shut down, see [Serverless Workers on GCP Cloud Run](/serverless-workers/cloud-run). +Cloud Run runs a standard long-lived Worker, so there is no Cloud Run-specific handler or package and any Temporal SDK +can run on a Worker Pool. The one addition is Worker Versioning, which Serverless Workers require. The tabs below cover +the SDKs with a Cloud Run guide today. + ## Prerequisites {/* #prerequisites */} - A Temporal Cloud account with a GCP-hosted Namespace, or a self-hosted Temporal Service v1.31.0 or later. The @@ -50,8 +54,8 @@ through the Cloud Run admin API as work arrives and drains. For how the pool sca perform the GCP steps, such as the Google Cloud console or Terraform. - [Terraform](https://developer.hashicorp.com/terraform/install) installed. Temporal provides the IAM setup as a Terraform module. -- 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. +- A Temporal SDK with Worker Versioning support. Use the tabs to select your language and the rest of the page will + update accordingly. ## 1. Write Worker code {/* #write-worker-code */} @@ -234,6 +238,209 @@ export async function myWorkflow(): Promise { ``` + + +```java +package example; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowClientOptions; +import io.temporal.common.VersioningBehavior; +import io.temporal.common.WorkerDeploymentVersion; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.serviceclient.WorkflowServiceStubsOptions; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerDeploymentOptions; +import io.temporal.worker.WorkerFactory; +import io.temporal.worker.WorkerOptions; + +public class WorkerMain { + public static void main(String[] args) { + String apiKey = System.getenv("TEMPORAL_API_KEY"); + + WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs( + WorkflowServiceStubsOptions.newBuilder() + .setTarget(System.getenv("TEMPORAL_ADDRESS")) + .setEnableHttps(true) + .addApiKey(() -> apiKey) + .build()); + + WorkflowClient client = + WorkflowClient.newInstance( + service, + WorkflowClientOptions.newBuilder() + .setNamespace(System.getenv("TEMPORAL_NAMESPACE")) + .build()); + + WorkerFactory factory = WorkerFactory.newInstance(client); + + Worker worker = + factory.newWorker( + System.getenv("TEMPORAL_TASK_QUEUE"), + WorkerOptions.newBuilder() + .setDeploymentOptions( + WorkerDeploymentOptions.newBuilder() + .setUseVersioning(true) + .setVersion(new WorkerDeploymentVersion("my-app", "build-1")) + .setDefaultVersioningBehavior(VersioningBehavior.PINNED) + .build()) + .build()); + + worker.registerWorkflowImplementationTypes(MyWorkflowImpl.class); + worker.registerActivitiesImplementations(new MyActivitiesImpl()); + + factory.start(); + } +} +``` + +Each Workflow must have a [versioning behavior](/worker-versioning#versioning-behaviors), either `PINNED` or +`AUTO_UPGRADE`. Set it per Workflow with the `@WorkflowVersioningBehavior` annotation, or set a Worker-level default +with `setDefaultVersioningBehavior` as shown above. + +For the Java Worker setup specific to Cloud Run, see +[Serverless Workers on GCP Cloud Run - Java SDK](/develop/java/workers/serverless-workers/cloud-run). + + + + +```csharp +using Temporalio.Client; +using Temporalio.Worker; + +var client = await TemporalClient.ConnectAsync(new(Environment.GetEnvironmentVariable("TEMPORAL_ADDRESS")!) +{ + Namespace = Environment.GetEnvironmentVariable("TEMPORAL_NAMESPACE")!, + ApiKey = Environment.GetEnvironmentVariable("TEMPORAL_API_KEY"), + Tls = new(), +}); + +var options = new TemporalWorkerOptions(Environment.GetEnvironmentVariable("TEMPORAL_TASK_QUEUE")!) +{ + DeploymentOptions = new(new("my-app", "build-1"), useWorkerVersioning: true) + { + DefaultVersioningBehavior = Temporalio.Common.VersioningBehavior.Pinned, + }, +}; +options.AddWorkflow(); +options.AddActivity(MyActivities.Greet); + +using var worker = new TemporalWorker(client, options); +await worker.ExecuteAsync(CancellationToken.None); +``` + +Each Workflow must have a [versioning behavior](/worker-versioning#versioning-behaviors), either `Pinned` or +`AutoUpgrade`. Set it per Workflow with `[Workflow(VersioningBehavior = ...)]`, or set a Worker-level default with +`DefaultVersioningBehavior` as shown above. + +For the .NET Worker setup specific to Cloud Run, see +[Serverless Workers on GCP Cloud Run - .NET SDK](/develop/dotnet/workers/serverless-workers/cloud-run). + + + + +```ruby +require 'temporalio/client' +require 'temporalio/worker' + +client = Temporalio::Client.connect( + ENV.fetch('TEMPORAL_ADDRESS'), + ENV.fetch('TEMPORAL_NAMESPACE'), + api_key: ENV.fetch('TEMPORAL_API_KEY'), + tls: true +) + +worker = Temporalio::Worker.new( + client:, + task_queue: ENV.fetch('TEMPORAL_TASK_QUEUE'), + workflows: [MyWorkflow], + activities: [Greet], + deployment_options: Temporalio::Worker::DeploymentOptions.new( + version: Temporalio::WorkerDeploymentVersion.new( + deployment_name: 'my-app', + build_id: 'build-1' + ), + use_worker_versioning: true, + default_versioning_behavior: Temporalio::VersioningBehavior::PINNED + ) +) + +worker.run +``` + +Each Workflow must have a [versioning behavior](/worker-versioning#versioning-behaviors), either `PINNED` or +`AUTO_UPGRADE`. Set it per Workflow by calling `workflow_versioning_behavior` in the Workflow class, or set a +Worker-level default with `default_versioning_behavior` as shown above. + +For the Ruby Worker setup specific to Cloud Run, see +[Serverless Workers on GCP Cloud Run - Ruby SDK](/develop/ruby/workers/serverless-workers/cloud-run). + + + + +```rust +use std::str::FromStr; + +use temporalio_client::{Client, ClientOptions, Connection, ConnectionOptions, TlsOptions}; +use temporalio_common::telemetry::TelemetryOptions; +use temporalio_common::worker::{ + VersioningBehavior, WorkerDeploymentOptions, WorkerDeploymentVersion, +}; +use temporalio_sdk::{Worker, WorkerOptions}; +use temporalio_sdk_core::{CoreRuntime, RuntimeOptions, Url}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let address = std::env::var("TEMPORAL_ADDRESS")?; + + let runtime = CoreRuntime::new_assume_tokio( + RuntimeOptions::builder() + .telemetry_options(TelemetryOptions::builder().build()) + .build()?, + )?; + + let connection_options = ConnectionOptions::new(Url::from_str(&format!("https://{address}"))?) + .api_key(std::env::var("TEMPORAL_API_KEY")?) + .tls_options(TlsOptions::default()) + .build(); + let connection = Connection::connect(connection_options).await?; + let client = Client::new( + connection, + ClientOptions::new(std::env::var("TEMPORAL_NAMESPACE")?).build(), + )?; + + let worker_options = WorkerOptions::new(std::env::var("TEMPORAL_TASK_QUEUE")?) + .deployment_options(WorkerDeploymentOptions { + version: WorkerDeploymentVersion { + deployment_name: "my-app".to_owned(), + build_id: "build-1".to_owned(), + }, + use_worker_versioning: true, + default_versioning_behavior: Some(VersioningBehavior::Pinned), + }) + .register_workflow::()? + .register_activities(MyActivities) + .build(); + + let mut worker = Worker::new(&runtime, client, worker_options)?; + worker.run().await?; + + Ok(()) +} +``` + +The Rust SDK sets the versioning behavior on the Worker rather than per Workflow, so `default_versioning_behavior` +covers every Workflow the Worker registers. Setting it to `Some(VersioningBehavior::Unspecified)` is an error at +startup. + +Setting `api_key` does not by itself apply TLS on this connection path, so set `tls_options` as well or the Worker +fails with `Connecting to HTTPS without TLS enabled`. + +For the Rust Worker setup specific to Cloud Run, see +[Serverless Workers on GCP Cloud Run - Rust SDK](/develop/rust/workers/serverless-workers/cloud-run). + + :::tip @@ -306,6 +513,10 @@ RUN npm run build FROM node:22-slim +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates \ + && rm -rf /var/lib/apt/lists/* + WORKDIR /app COPY package*.json ./ RUN npm ci --omit=dev @@ -314,11 +525,108 @@ COPY --from=build /app/lib ./lib CMD ["node", "lib/worker.js"] ``` +`node:22-slim` ships without a CA certificate bundle, and the Rust core of the TypeScript SDK reads TLS roots from the operating system's store. Without the `ca-certificates` step above, the Worker fails at startup with `TransportError: tonic::transport::Error(Transport, NativeCertsNotFound)`. + Use a glibc-based image such as `node:22-slim` rather than an Alpine image. Alpine replaces glibc with musl, which is incompatible with the Rust core of the TypeScript SDK. See [Do not use Alpine](/develop/typescript/workers/run-worker-process#do-not-use-alpine). Set `NODE_OPTIONS=--max-old-space-size=` on the Worker Pool to about 80% of the instance's memory limit. Without it, Node.js sizes its heap from the host's total memory rather than the container limit. See [Run a Worker on Docker](/develop/typescript/workers/run-worker-process#run-a-worker-on-docker). + + +Build a fat jar in one stage and run it on a JRE image: + +```dockerfile +FROM maven:3.9-eclipse-temurin-21 AS build + +WORKDIR /src +COPY pom.xml ./ +RUN mvn -B -q dependency:go-offline +COPY src ./src +RUN mvn -B -q package -DskipTests + +FROM eclipse-temurin:21-jre-noble + +WORKDIR /app +COPY --from=build /src/target/my-worker.jar /app/worker.jar +CMD ["java", "-XX:MaxRAMPercentage=75", "-jar", "/app/worker.jar"] +``` + +The JVM reads the container's memory limit but defaults its maximum heap to 25% of it, so set `-XX:MaxRAMPercentage` to +give the Worker more of the instance. + + + + +Publish in one stage and run on a .NET runtime image: + +```dockerfile +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build + +WORKDIR /src +COPY *.csproj ./ +RUN dotnet restore +COPY . . +RUN dotnet publish -c Release -o /out + +FROM mcr.microsoft.com/dotnet/runtime:9.0 + +WORKDIR /app +COPY --from=build /out ./ +CMD ["dotnet", "MyWorker.dll"] +``` + + + + +Install the precompiled gem rather than building the native extension from source: + +```dockerfile +FROM ruby:3.3-slim + +WORKDIR /app +RUN gem install temporalio --no-document +COPY worker.rb ./ + +CMD ["ruby", "worker.rb"] +``` + +Installing through Bundler in a container can select the source gem, which then fails to build without a Rust +toolchain. If you use Bundler, add the target platform to the lockfile with `bundle lock --add-platform x86_64-linux`. + + + + +Compile the Worker in one stage and copy the binary into a runtime image: + +```dockerfile +FROM rust:1.92-slim AS build + +RUN apt-get update \ + && apt-get install -y --no-install-recommends pkg-config libssl-dev protobuf-compiler libprotobuf-dev \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /src +COPY Cargo.toml ./ +COPY src ./src +RUN cargo build --release + +FROM debian:bookworm-slim + +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app +COPY --from=build /src/target/release/my-worker /app/worker +CMD ["/app/worker"] +``` + +The build stage needs `libprotobuf-dev` alongside `protobuf-compiler`, because the compiler package alone installs +`protoc` without the well-known type definitions. The runtime stage needs `ca-certificates`, which +`debian:bookworm-slim` does not ship. + + ### ii. Build and push the image {/* #build-and-push */} diff --git a/sidebars.js b/sidebars.js index 8f319350bf..54d69cd4c5 100644 --- a/sidebars.js +++ b/sidebars.js @@ -70,6 +70,7 @@ const developDotnetCategory = { }, items: [ 'develop/dotnet/workers/serverless-workers/aws-lambda', + 'develop/dotnet/workers/serverless-workers/cloud-run', ], }, ] @@ -366,6 +367,7 @@ const developJavaCategory = { }, items: [ 'develop/java/workers/serverless-workers/aws-lambda', + 'develop/java/workers/serverless-workers/cloud-run', ], }, ], @@ -750,7 +752,19 @@ const developRubyCategory = { id: 'develop/ruby/workers/index', }, items: [ - 'develop/ruby/workers/run-worker-process' + 'develop/ruby/workers/run-worker-process', + { + type: 'category', + label: 'Serverless Workers', + collapsed: true, + link: { + type: 'doc', + id: 'develop/ruby/workers/serverless-workers/index', + }, + items: [ + 'develop/ruby/workers/serverless-workers/cloud-run', + ], + }, ], }, { @@ -871,7 +885,19 @@ const developRustCategory = { id: 'develop/rust/workers/index', }, items: [ - 'develop/rust/workers/worker-process' + 'develop/rust/workers/worker-process', + { + type: 'category', + label: 'Serverless Workers', + collapsed: true, + link: { + type: 'doc', + id: 'develop/rust/workers/serverless-workers/index', + }, + items: [ + 'develop/rust/workers/serverless-workers/cloud-run', + ], + }, ], }, { @@ -970,6 +996,7 @@ const developTypeScriptCategory = { }, items: [ 'develop/typescript/workers/serverless-workers/aws-lambda', + 'develop/typescript/workers/serverless-workers/cloud-run', ], }, ], diff --git a/vercel.json b/vercel.json index 33279f7763..b08e4281e8 100644 --- a/vercel.json +++ b/vercel.json @@ -47,8 +47,6 @@ { "source": "/llms-api-reference.txt", "destination": "/llms.txt", - "source": "/develop/typescript/workers/serverless-workers/cloud-run", - "destination": "/develop/typescript/workers/serverless-workers", "permanent": true }, { From 2d9d1ae66aea8cd1625892d6c732c7c12437b530 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Fri, 14 Aug 2026 13:42:26 -0700 Subject: [PATCH 2/6] docs: reword the Cloud Run SDK support paragraph and drop the Lambda comparison --- .../encyclopedia/workers/serverless-workers/cloud-run.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/encyclopedia/workers/serverless-workers/cloud-run.mdx b/docs/encyclopedia/workers/serverless-workers/cloud-run.mdx index f9bd9ab1ea..1e0b04f4b3 100644 --- a/docs/encyclopedia/workers/serverless-workers/cloud-run.mdx +++ b/docs/encyclopedia/workers/serverless-workers/cloud-run.mdx @@ -36,10 +36,10 @@ On Cloud Run, a Serverless Worker runs in a Worker Pool: a set of long-lived ins Each instance runs standard Worker code and processes Tasks for its whole lifetime. The [Worker Controller Instance (WCI)](/serverless-workers#worker-controller-instance) controls how many instances run; each instance manages its own polling and Task processing. -Because an instance runs an ordinary long-lived Worker, Cloud Run needs no provider-specific handler or package, unlike AWS Lambda. -Any Temporal SDK can run on a Cloud Run Worker Pool. -The one addition to a standard Worker is [Worker Versioning](/worker-versioning), which Serverless Workers require, so an SDK needs Worker Versioning support to run here. -Packaging the Worker into a container image is where the per-language differences show up, and each SDK's Cloud Run page covers them. +Serverless Workers on Cloud Run use standard long-lived Worker processes, with scaling managed by the WCI. +Some SDKs add GCP-specific conveniences, such as helpers for configuring OpenTelemetry. +These are optional. +Where an SDK provides them, they're documented in the corresponding developer guide for that SDK. ## Autoscaling {/* #autoscaling */} From 36afab4213e7ff530c8f77eecfc1118f6137c676 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Fri, 14 Aug 2026 14:19:33 -0700 Subject: [PATCH 3/6] docs: source the Cloud Run Worker snippets from the features repo The Java, .NET, TypeScript, and Ruby Cloud Run pages now pull their Worker code from features/snippets/worker/ via Snipsync instead of carrying hand-written code that nothing compiles. Snipsync is pinned to the features branch until temporalio/features#861 merges. Rust keeps its hand-written snippet, since the features repo has no Rust harness. --- .../workers/serverless-workers/cloud-run.mdx | 32 ++++--- .../workers/serverless-workers/cloud-run.mdx | 94 ++++++++----------- .../workers/serverless-workers/cloud-run.mdx | 14 +-- .../workers/serverless-workers/cloud-run.mdx | 46 ++++----- snipsync.config.yaml | 2 + 5 files changed, 86 insertions(+), 102 deletions(-) diff --git a/docs/develop/dotnet/workers/serverless-workers/cloud-run.mdx b/docs/develop/dotnet/workers/serverless-workers/cloud-run.mdx index 6cc80847a9..d500aeaf2a 100644 --- a/docs/develop/dotnet/workers/serverless-workers/cloud-run.mdx +++ b/docs/develop/dotnet/workers/serverless-workers/cloud-run.mdx @@ -34,30 +34,32 @@ Build the Worker as you would any long-running .NET Worker, then set `Deployment The following Worker reads its connection settings and Task Queue from the environment, so the same image can run against any Namespace: -```csharp -using Temporalio.Client; -using Temporalio.Worker; - -var client = await TemporalClient.ConnectAsync(new(Environment.GetEnvironmentVariable("TEMPORAL_ADDRESS")!) -{ - Namespace = Environment.GetEnvironmentVariable("TEMPORAL_NAMESPACE")!, - ApiKey = Environment.GetEnvironmentVariable("TEMPORAL_API_KEY"), - Tls = new(), -}); + +[features/snippets/worker/worker.cs](https://github.com/temporalio/features/blob/worker-docs-snippets/features/snippets/worker/worker.cs) +```cs +var client = await TemporalClient.ConnectAsync( + new(Environment.GetEnvironmentVariable("TEMPORAL_ADDRESS")!) + { + Namespace = Environment.GetEnvironmentVariable("TEMPORAL_NAMESPACE")!, + ApiKey = Environment.GetEnvironmentVariable("TEMPORAL_API_KEY"), + Tls = new(), + }); -var options = new TemporalWorkerOptions(Environment.GetEnvironmentVariable("TEMPORAL_TASK_QUEUE")!) +var options = new TemporalWorkerOptions( + Environment.GetEnvironmentVariable("TEMPORAL_TASK_QUEUE")!) { DeploymentOptions = new(new("my-app", "build-1"), useWorkerVersioning: true) { - DefaultVersioningBehavior = Temporalio.Common.VersioningBehavior.Pinned, + DefaultVersioningBehavior = VersioningBehavior.Pinned, }, }; -options.AddWorkflow(); -options.AddActivity(MyActivities.Greet); +options.AddWorkflow(); +options.AddAllActivities(typeof(GreetingActivities), null); using var worker = new TemporalWorker(client, options); await worker.ExecuteAsync(CancellationToken.None); ``` + The two arguments to `WorkerDeploymentVersion` are the deployment name and the build ID, and together they identify the Worker Deployment Version. Both values must match the version you create with `temporal worker deployment create-version` in the deployment guide, or the Worker polls under a version the WCI does not manage. @@ -70,7 +72,7 @@ using Temporalio.Common; using Temporalio.Workflows; [Workflow(VersioningBehavior = VersioningBehavior.Pinned)] -public class MyWorkflow +public class GreetingWorkflow { [WorkflowRun] public async Task RunAsync(string name) => // ... diff --git a/docs/develop/java/workers/serverless-workers/cloud-run.mdx b/docs/develop/java/workers/serverless-workers/cloud-run.mdx index afdb46c7ba..0d3bfd171b 100644 --- a/docs/develop/java/workers/serverless-workers/cloud-run.mdx +++ b/docs/develop/java/workers/serverless-workers/cloud-run.mdx @@ -34,60 +34,46 @@ Build the Worker as you would any long-running Java Worker, then set `WorkerDepl The following Worker reads its connection settings and Task Queue from the environment, so the same image can run against any Namespace: + +[features/snippets/worker/worker.java](https://github.com/temporalio/features/blob/worker-docs-snippets/features/snippets/worker/worker.java) ```java -package example; - -import io.temporal.client.WorkflowClient; -import io.temporal.client.WorkflowClientOptions; -import io.temporal.common.VersioningBehavior; -import io.temporal.common.WorkerDeploymentVersion; -import io.temporal.serviceclient.WorkflowServiceStubs; -import io.temporal.serviceclient.WorkflowServiceStubsOptions; -import io.temporal.worker.Worker; -import io.temporal.worker.WorkerDeploymentOptions; -import io.temporal.worker.WorkerFactory; -import io.temporal.worker.WorkerOptions; - -public class WorkerMain { - public static void main(String[] args) { - String apiKey = System.getenv("TEMPORAL_API_KEY"); - - WorkflowServiceStubs service = - WorkflowServiceStubs.newServiceStubs( - WorkflowServiceStubsOptions.newBuilder() - .setTarget(System.getenv("TEMPORAL_ADDRESS")) - .setEnableHttps(true) - .addApiKey(() -> apiKey) - .build()); - - WorkflowClient client = - WorkflowClient.newInstance( - service, - WorkflowClientOptions.newBuilder() - .setNamespace(System.getenv("TEMPORAL_NAMESPACE")) - .build()); - - WorkerFactory factory = WorkerFactory.newInstance(client); - - Worker worker = - factory.newWorker( - System.getenv("TEMPORAL_TASK_QUEUE"), - WorkerOptions.newBuilder() - .setDeploymentOptions( - WorkerDeploymentOptions.newBuilder() - .setUseVersioning(true) - .setVersion(new WorkerDeploymentVersion("my-app", "build-1")) - .setDefaultVersioningBehavior(VersioningBehavior.PINNED) - .build()) - .build()); - - worker.registerWorkflowImplementationTypes(MyWorkflowImpl.class); - worker.registerActivitiesImplementations(new MyActivitiesImpl()); - - factory.start(); - } -} +String apiKey = System.getenv("TEMPORAL_API_KEY"); + +WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs( + WorkflowServiceStubsOptions.newBuilder() + .setTarget(System.getenv("TEMPORAL_ADDRESS")) + .setEnableHttps(true) + .addApiKey(() -> apiKey) + .build()); + +WorkflowClient client = + WorkflowClient.newInstance( + service, + WorkflowClientOptions.newBuilder() + .setNamespace(System.getenv("TEMPORAL_NAMESPACE")) + .build()); + +WorkerFactory factory = WorkerFactory.newInstance(client); + +Worker worker = + factory.newWorker( + System.getenv("TEMPORAL_TASK_QUEUE"), + WorkerOptions.newBuilder() + .setDeploymentOptions( + WorkerDeploymentOptions.newBuilder() + .setUseVersioning(true) + .setVersion(new WorkerDeploymentVersion("my-app", "build-1")) + .setDefaultVersioningBehavior(VersioningBehavior.PINNED) + .build()) + .build()); + +worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class); +worker.registerActivitiesImplementations(new GreetingActivitiesImpl()); + +factory.start(); ``` + The two arguments to `WorkerDeploymentVersion` are the deployment name and the build ID, and together they identify the Worker Deployment Version. Both values must match the version you create with `temporal worker deployment create-version` in the deployment guide, or the Worker polls under a version the WCI does not manage. @@ -99,7 +85,7 @@ To set the behavior per Workflow instead, annotate the Workflow method with `@Wo import io.temporal.common.VersioningBehavior; import io.temporal.workflow.WorkflowVersioningBehavior; -public class MyWorkflowImpl implements MyWorkflow { +public class GreetingWorkflowImpl implements GreetingWorkflow { @Override @WorkflowVersioningBehavior(VersioningBehavior.PINNED) public String run(String name) { @@ -139,7 +125,7 @@ An instance running a long Activity can be stopped mid-execution. Use [Activity Heartbeats](/develop/java/activities/timeouts#activity-heartbeats) so a retry resumes from the last recorded progress instead of starting over: ```java -public class MyActivitiesImpl implements MyActivities { +public class GreetingActivitiesImpl implements GreetingActivities { @Override public String process(List items) { for (int i = 0; i < items.size(); i++) { diff --git a/docs/develop/ruby/workers/serverless-workers/cloud-run.mdx b/docs/develop/ruby/workers/serverless-workers/cloud-run.mdx index fac0e96aa4..17a7bcdd52 100644 --- a/docs/develop/ruby/workers/serverless-workers/cloud-run.mdx +++ b/docs/develop/ruby/workers/serverless-workers/cloud-run.mdx @@ -34,10 +34,9 @@ Build the Worker as you would any long-running Ruby Worker, then pass `deploymen The following Worker reads its connection settings and Task Queue from the environment, so the same image can run against any Namespace: -```ruby -require 'temporalio/client' -require 'temporalio/worker' - + +[features/snippets/worker/worker.rb](https://github.com/temporalio/features/blob/worker-docs-snippets/features/snippets/worker/worker.rb) +```rb client = Temporalio::Client.connect( ENV.fetch('TEMPORAL_ADDRESS'), ENV.fetch('TEMPORAL_NAMESPACE'), @@ -48,8 +47,8 @@ client = Temporalio::Client.connect( worker = Temporalio::Worker.new( client:, task_queue: ENV.fetch('TEMPORAL_TASK_QUEUE'), - workflows: [MyWorkflow], - activities: [Greet], + workflows: [GreetingWorkflow], + activities: [SayHello], deployment_options: Temporalio::Worker::DeploymentOptions.new( version: Temporalio::WorkerDeploymentVersion.new( deployment_name: 'my-app', @@ -62,6 +61,7 @@ worker = Temporalio::Worker.new( worker.run ``` + `deployment_name` and `build_id` together identify the Worker Deployment Version. Both values must match the version you create with `temporal worker deployment create-version` in the deployment guide, or the Worker polls under a version the WCI does not manage. @@ -70,7 +70,7 @@ Setting `default_versioning_behavior` as shown above covers every Workflow on th To set the behavior per Workflow instead, call `workflow_versioning_behavior` in the Workflow class: ```ruby -class MyWorkflow < Temporalio::Workflow::Definition +class GreetingWorkflow < Temporalio::Workflow::Definition workflow_versioning_behavior Temporalio::VersioningBehavior::PINNED def execute(name) diff --git a/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx b/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx index ff9b6efcf3..6fba613e4c 100644 --- a/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx +++ b/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx @@ -42,36 +42,30 @@ Build the Worker as you would any long-running TypeScript Worker, then pass `wor The following Worker reads its connection settings and Task Queue from the environment, so the same image can run against any Namespace: + +[features/snippets/worker/worker.ts](https://github.com/temporalio/features/blob/worker-docs-snippets/features/snippets/worker/worker.ts) ```ts -import { loadClientConnectConfig } from '@temporalio/envconfig'; -import { NativeConnection, Worker } from '@temporalio/worker'; -import * as activities from './activities'; - -async function run() { - const config = loadClientConnectConfig(); - const connection = await NativeConnection.connect(config.connectionOptions); - - const worker = await Worker.create({ - connection, - namespace: config.namespace, - taskQueue: process.env.TEMPORAL_TASK_QUEUE!, - workflowsPath: require.resolve('./workflows'), - activities, - workerDeploymentOptions: { - version: { deploymentName: 'my-app', buildId: 'build-1' }, - useWorkerVersioning: true, - defaultVersioningBehavior: 'PINNED', - }, - }); - - await worker.run(); -} +const connection = await NativeConnection.connect({ + address: process.env.TEMPORAL_ADDRESS, + apiKey: process.env.TEMPORAL_API_KEY, + tls: true, +}); -run().catch((err) => { - console.error(err); - process.exit(1); +const worker = await Worker.create({ + connection, + namespace: process.env.TEMPORAL_NAMESPACE!, + taskQueue: process.env.TEMPORAL_TASK_QUEUE!, + workflowsPath: require.resolve('./workflows'), + workerDeploymentOptions: { + version: { deploymentName: 'my-app', buildId: 'build-1' }, + useWorkerVersioning: true, + defaultVersioningBehavior: 'PINNED', + }, }); + +await worker.run(); ``` + `deploymentName` and `buildId` together identify the Worker Deployment Version. Both values must match the version you create with `temporal worker deployment create-version` in the deployment guide, or the Worker polls under a version the WCI does not manage. diff --git a/snipsync.config.yaml b/snipsync.config.yaml index a1b6ba5c4f..e1fca3791b 100644 --- a/snipsync.config.yaml +++ b/snipsync.config.yaml @@ -11,6 +11,8 @@ origins: repo: reference-app-orders-go - owner: temporalio repo: features + # TODO: drop this pin once temporalio/features#861 merges. + ref: 'worker-docs-snippets' # Some samples were left in the SDK code itself because it has better testing # capabilities than the samples repo From 327cc0500a78a8a99a06a3747fdfd48449efd333 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Wed, 19 Aug 2026 16:32:15 -0700 Subject: [PATCH 4/6] docs: address review feedback on the Cloud Run pages - Link Worker Versioning on first mention across the SDK pages and the guide. - Drop the prerequisite wording implying only some SDKs support Worker Versioning. - Reword the per-tab SDK page links, which read as though the tab itself were not Cloud Run specific. - Condense the TypeScript container notes in the guide to what to do. - Cut the TypeScript-SDK framing from the packaging section on the TypeScript page. - Restore envconfig in the TypeScript snippet so it matches the page prose and the guide, and add the TypeScript SDK page link the guide was missing. --- .../workers/serverless-workers/cloud-run.mdx | 2 +- .../workers/serverless-workers/cloud-run.mdx | 2 +- .../workers/serverless-workers/cloud-run.mdx | 2 +- .../workers/serverless-workers/cloud-run.mdx | 2 +- .../workers/serverless-workers/cloud-run.mdx | 2 +- .../workers/serverless-workers/cloud-run.mdx | 2 +- .../workers/serverless-workers/cloud-run.mdx | 15 ++++------ .../serverless-workers/cloud-run/index.mdx | 28 ++++++++++--------- 8 files changed, 26 insertions(+), 29 deletions(-) diff --git a/docs/develop/dotnet/workers/serverless-workers/cloud-run.mdx b/docs/develop/dotnet/workers/serverless-workers/cloud-run.mdx index d500aeaf2a..9f13d7acc8 100644 --- a/docs/develop/dotnet/workers/serverless-workers/cloud-run.mdx +++ b/docs/develop/dotnet/workers/serverless-workers/cloud-run.mdx @@ -24,7 +24,7 @@ On a [GCP Cloud Run worker pool](https://cloud.google.com/run/docs/resource-mode Register Workflows and Activities the same way you would with any other .NET Worker, and Temporal Cloud scales the pool up and down as work arrives and drains. A Cloud Run Worker needs no Cloud Run-specific package. -The one addition to a standard Worker is Worker Versioning, which is required for Serverless Workers. +The one addition to a standard Worker is [Worker Versioning](/worker-versioning), which is required for Serverless Workers. For the end-to-end deployment guide covering the Worker Pool, IAM, and compute configuration, see [Deploy a Serverless Worker on GCP Cloud Run](/production-deployment/worker-deployments/serverless-workers/cloud-run). diff --git a/docs/develop/go/workers/serverless-workers/cloud-run.mdx b/docs/develop/go/workers/serverless-workers/cloud-run.mdx index bf5ad54fea..a4b42ea1ff 100644 --- a/docs/develop/go/workers/serverless-workers/cloud-run.mdx +++ b/docs/develop/go/workers/serverless-workers/cloud-run.mdx @@ -32,7 +32,7 @@ On a [GCP Cloud Run worker pool](https://cloud.google.com/run/docs/resource-mode Register Workflows and Activities the same way you would with any other Go Worker, and Temporal Cloud scales the pool up and down as work arrives and drains. A Cloud Run Worker needs no Cloud Run-specific package. -The one addition to a standard Worker is Worker Versioning, which is required for Serverless Workers. +The one addition to a standard Worker is [Worker Versioning](/worker-versioning), which is required for Serverless Workers. For the end-to-end deployment guide covering the Worker Pool, IAM, and compute configuration, see [Deploy a Serverless Worker on GCP Cloud Run](/production-deployment/worker-deployments/serverless-workers/cloud-run). diff --git a/docs/develop/java/workers/serverless-workers/cloud-run.mdx b/docs/develop/java/workers/serverless-workers/cloud-run.mdx index 0d3bfd171b..7dfb45f9c2 100644 --- a/docs/develop/java/workers/serverless-workers/cloud-run.mdx +++ b/docs/develop/java/workers/serverless-workers/cloud-run.mdx @@ -24,7 +24,7 @@ On a [GCP Cloud Run worker pool](https://cloud.google.com/run/docs/resource-mode Register Workflows and Activities the same way you would with any other Java Worker, and Temporal Cloud scales the pool up and down as work arrives and drains. A Cloud Run Worker needs no Cloud Run-specific package. -The one addition to a standard Worker is Worker Versioning, which is required for Serverless Workers. +The one addition to a standard Worker is [Worker Versioning](/worker-versioning), which is required for Serverless Workers. For the end-to-end deployment guide covering the Worker Pool, IAM, and compute configuration, see [Deploy a Serverless Worker on GCP Cloud Run](/production-deployment/worker-deployments/serverless-workers/cloud-run). diff --git a/docs/develop/python/workers/serverless-workers/cloud-run.mdx b/docs/develop/python/workers/serverless-workers/cloud-run.mdx index b54206d7a6..bf42448595 100644 --- a/docs/develop/python/workers/serverless-workers/cloud-run.mdx +++ b/docs/develop/python/workers/serverless-workers/cloud-run.mdx @@ -32,7 +32,7 @@ On a [GCP Cloud Run worker pool](https://cloud.google.com/run/docs/resource-mode Register Workflows and Activities the same way you would with any other Python Worker, and Temporal Cloud scales the pool up and down as work arrives and drains. A Cloud Run Worker needs no Cloud Run-specific package. -The one addition to a standard Worker is Worker Versioning, which is required for Serverless Workers. +The one addition to a standard Worker is [Worker Versioning](/worker-versioning), which is required for Serverless Workers. For the end-to-end deployment guide covering the Worker Pool, IAM, and compute configuration, see [Deploy a Serverless Worker on GCP Cloud Run](/production-deployment/worker-deployments/serverless-workers/cloud-run). diff --git a/docs/develop/ruby/workers/serverless-workers/cloud-run.mdx b/docs/develop/ruby/workers/serverless-workers/cloud-run.mdx index 17a7bcdd52..4c08245fc7 100644 --- a/docs/develop/ruby/workers/serverless-workers/cloud-run.mdx +++ b/docs/develop/ruby/workers/serverless-workers/cloud-run.mdx @@ -24,7 +24,7 @@ On a [GCP Cloud Run worker pool](https://cloud.google.com/run/docs/resource-mode Register Workflows and Activities the same way you would with any other Ruby Worker, and Temporal Cloud scales the pool up and down as work arrives and drains. A Cloud Run Worker needs no Cloud Run-specific gem. -The one addition to a standard Worker is Worker Versioning, which is required for Serverless Workers. +The one addition to a standard Worker is [Worker Versioning](/worker-versioning), which is required for Serverless Workers. For the end-to-end deployment guide covering the Worker Pool, IAM, and compute configuration, see [Deploy a Serverless Worker on GCP Cloud Run](/production-deployment/worker-deployments/serverless-workers/cloud-run). diff --git a/docs/develop/rust/workers/serverless-workers/cloud-run.mdx b/docs/develop/rust/workers/serverless-workers/cloud-run.mdx index 0aa0625791..6e5093c3ac 100644 --- a/docs/develop/rust/workers/serverless-workers/cloud-run.mdx +++ b/docs/develop/rust/workers/serverless-workers/cloud-run.mdx @@ -27,7 +27,7 @@ On a [GCP Cloud Run worker pool](https://cloud.google.com/run/docs/resource-mode Register Workflows and Activities the same way you would with any other Rust Worker, and Temporal Cloud scales the pool up and down as work arrives and drains. A Cloud Run Worker needs no Cloud Run-specific crate. -The one addition to a standard Worker is Worker Versioning, which is required for Serverless Workers. +The one addition to a standard Worker is [Worker Versioning](/worker-versioning), which is required for Serverless Workers. For the end-to-end deployment guide covering the Worker Pool, IAM, and compute configuration, see [Deploy a Serverless Worker on GCP Cloud Run](/production-deployment/worker-deployments/serverless-workers/cloud-run). diff --git a/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx b/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx index 6fba613e4c..b017e9975f 100644 --- a/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx +++ b/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx @@ -32,7 +32,7 @@ On a [GCP Cloud Run worker pool](https://cloud.google.com/run/docs/resource-mode Register Workflows and Activities the same way you would with any other TypeScript Worker, and Temporal Cloud scales the pool up and down as work arrives and drains. A Cloud Run Worker needs no Cloud Run-specific package. -The one addition to a standard Worker is Worker Versioning, which is required for Serverless Workers. +The one addition to a standard Worker is [Worker Versioning](/worker-versioning), which is required for Serverless Workers. For the end-to-end deployment guide covering the Worker Pool, IAM, and compute configuration, see [Deploy a Serverless Worker on GCP Cloud Run](/production-deployment/worker-deployments/serverless-workers/cloud-run). @@ -45,15 +45,12 @@ The following Worker reads its connection settings and Task Queue from the envir [features/snippets/worker/worker.ts](https://github.com/temporalio/features/blob/worker-docs-snippets/features/snippets/worker/worker.ts) ```ts -const connection = await NativeConnection.connect({ - address: process.env.TEMPORAL_ADDRESS, - apiKey: process.env.TEMPORAL_API_KEY, - tls: true, -}); +const config = loadClientConnectConfig(); +const connection = await NativeConnection.connect(config.connectionOptions); const worker = await Worker.create({ connection, - namespace: process.env.TEMPORAL_NAMESPACE!, + namespace: config.namespace, taskQueue: process.env.TEMPORAL_TASK_QUEUE!, workflowsPath: require.resolve('./workflows'), workerDeploymentOptions: { @@ -94,9 +91,7 @@ For the full list of supported variables, the config file format, and profiles, ## Package the Worker image {/* #package-image */} -Two container details are specific to the TypeScript SDK, because its Worker runs on a Rust core rather than on Node.js alone. - -The Rust core reads TLS roots from the operating system's certificate store, and the slim Node.js images ship without one. +The Worker reads TLS roots from the operating system's certificate store, and the slim Node.js images ship without one. On `node:22-slim`, connecting with TLS fails at startup: ``` diff --git a/docs/production-deployment/worker-deployments/serverless-workers/cloud-run/index.mdx b/docs/production-deployment/worker-deployments/serverless-workers/cloud-run/index.mdx index 10961fb03e..728cc54e66 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/cloud-run/index.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/cloud-run/index.mdx @@ -36,7 +36,7 @@ through the Cloud Run admin API as work arrives and drains. For how the pool sca [Serverless Workers on GCP Cloud Run](/serverless-workers/cloud-run). Cloud Run runs a standard long-lived Worker, so there is no Cloud Run-specific handler or package and any Temporal SDK -can run on a Worker Pool. The one addition is Worker Versioning, which Serverless Workers require. The tabs below cover +can run on a Worker Pool. The one addition is [Worker Versioning](/worker-versioning), which Serverless Workers require. The tabs below cover the SDKs with a Cloud Run guide today. ## Prerequisites {/* #prerequisites */} @@ -54,8 +54,7 @@ the SDKs with a Cloud Run guide today. perform the GCP steps, such as the Google Cloud console or Terraform. - [Terraform](https://developer.hashicorp.com/terraform/install) installed. Temporal provides the IAM setup as a Terraform module. -- A Temporal SDK with Worker Versioning support. Use the tabs to select your language and the rest of the page will - update accordingly. +- A Temporal SDK. Use the tabs to select your language and the rest of the page will update accordingly. ## 1. Write Worker code {/* #write-worker-code */} @@ -122,7 +121,7 @@ class MyWorkflow: ... ``` -For the Python Worker setup specific to Cloud Run, see +For more on the Python Worker setup, see [Serverless Workers on GCP Cloud Run - Python SDK](/develop/python/workers/serverless-workers/cloud-run). @@ -187,7 +186,7 @@ w := worker.New(c, os.Getenv("TEMPORAL_TASK_QUEUE"), worker.Options{ If a Version is set and neither is specified, registration panics with `workflow type does not have a versioning behavior`. -For the Go Worker setup specific to Cloud Run, see +For more on the Go Worker setup, see [Serverless Workers on GCP Cloud Run - Go SDK](/develop/go/workers/serverless-workers/cloud-run). @@ -237,6 +236,9 @@ export async function myWorkflow(): Promise { } ``` +For more on the TypeScript Worker setup, see +[Serverless Workers on GCP Cloud Run - TypeScript SDK](/develop/typescript/workers/serverless-workers/cloud-run). + @@ -299,7 +301,7 @@ Each Workflow must have a [versioning behavior](/worker-versioning#versioning-be `AUTO_UPGRADE`. Set it per Workflow with the `@WorkflowVersioningBehavior` annotation, or set a Worker-level default with `setDefaultVersioningBehavior` as shown above. -For the Java Worker setup specific to Cloud Run, see +For more on the Java Worker setup, see [Serverless Workers on GCP Cloud Run - Java SDK](/develop/java/workers/serverless-workers/cloud-run). @@ -334,7 +336,7 @@ Each Workflow must have a [versioning behavior](/worker-versioning#versioning-be `AutoUpgrade`. Set it per Workflow with `[Workflow(VersioningBehavior = ...)]`, or set a Worker-level default with `DefaultVersioningBehavior` as shown above. -For the .NET Worker setup specific to Cloud Run, see +For more on the .NET Worker setup, see [Serverless Workers on GCP Cloud Run - .NET SDK](/develop/dotnet/workers/serverless-workers/cloud-run). @@ -373,7 +375,7 @@ Each Workflow must have a [versioning behavior](/worker-versioning#versioning-be `AUTO_UPGRADE`. Set it per Workflow by calling `workflow_versioning_behavior` in the Workflow class, or set a Worker-level default with `default_versioning_behavior` as shown above. -For the Ruby Worker setup specific to Cloud Run, see +For more on the Ruby Worker setup, see [Serverless Workers on GCP Cloud Run - Ruby SDK](/develop/ruby/workers/serverless-workers/cloud-run). @@ -437,7 +439,7 @@ startup. Setting `api_key` does not by itself apply TLS on this connection path, so set `tls_options` as well or the Worker fails with `Connecting to HTTPS without TLS enabled`. -For the Rust Worker setup specific to Cloud Run, see +For more on the Rust Worker setup, see [Serverless Workers on GCP Cloud Run - Rust SDK](/develop/rust/workers/serverless-workers/cloud-run). @@ -525,11 +527,11 @@ COPY --from=build /app/lib ./lib CMD ["node", "lib/worker.js"] ``` -`node:22-slim` ships without a CA certificate bundle, and the Rust core of the TypeScript SDK reads TLS roots from the operating system's store. Without the `ca-certificates` step above, the Worker fails at startup with `TransportError: tonic::transport::Error(Transport, NativeCertsNotFound)`. - -Use a glibc-based image such as `node:22-slim` rather than an Alpine image. Alpine replaces glibc with musl, which is incompatible with the Rust core of the TypeScript SDK. See [Do not use Alpine](/develop/typescript/workers/run-worker-process#do-not-use-alpine). +Three details are required here: -Set `NODE_OPTIONS=--max-old-space-size=` on the Worker Pool to about 80% of the instance's memory limit. Without it, Node.js sizes its heap from the host's total memory rather than the container limit. See [Run a Worker on Docker](/develop/typescript/workers/run-worker-process#run-a-worker-on-docker). +- Keep the `ca-certificates` step. Without it the Worker fails at startup with `TransportError: tonic::transport::Error(Transport, NativeCertsNotFound)`. +- Use a glibc-based image, not Alpine. See [Do not use Alpine](/develop/typescript/workers/run-worker-process#do-not-use-alpine). +- Set `NODE_OPTIONS=--max-old-space-size=` on the Worker Pool to about 80% of the instance's memory limit. See [Run a Worker on Docker](/develop/typescript/workers/run-worker-process#run-a-worker-on-docker). From 8c3069f922b59a0c256c29d7fee87c3df926a12a Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Wed, 19 Aug 2026 16:39:13 -0700 Subject: [PATCH 5/6] docs: read the TypeScript connection settings from the environment Matches the snippet in the features repo, whose harness cannot depend on @temporalio/envconfig. Both TypeScript samples now agree, and envconfig stays documented as the alternative. --- .../workers/serverless-workers/cloud-run.mdx | 16 +++++++++------- .../serverless-workers/cloud-run/index.mdx | 10 ++++++---- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx b/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx index b017e9975f..6580e2514b 100644 --- a/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx +++ b/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx @@ -45,12 +45,15 @@ The following Worker reads its connection settings and Task Queue from the envir [features/snippets/worker/worker.ts](https://github.com/temporalio/features/blob/worker-docs-snippets/features/snippets/worker/worker.ts) ```ts -const config = loadClientConnectConfig(); -const connection = await NativeConnection.connect(config.connectionOptions); +const connection = await NativeConnection.connect({ + address: process.env.TEMPORAL_ADDRESS, + apiKey: process.env.TEMPORAL_API_KEY, + tls: true, +}); const worker = await Worker.create({ connection, - namespace: config.namespace, + namespace: process.env.TEMPORAL_NAMESPACE!, taskQueue: process.env.TEMPORAL_TASK_QUEUE!, workflowsPath: require.resolve('./workflows'), workerDeploymentOptions: { @@ -83,11 +86,10 @@ For general Worker setup and options that are not specific to Cloud Run, see [Ru ## Configure the Temporal connection {/* #configure-connection */} -The `@temporalio/envconfig` package loads Temporal Client configuration from environment variables and an optional TOML config file, so the Worker code carries no Namespace or credentials. -Set the non-secret values as environment variables on the Worker Pool, and mount the Temporal Cloud API key or TLS material from Secret Manager. -For the full list of supported variables, the config file format, and profiles, see [Environment configuration](/develop/environment-configuration). +Read the Namespace, address, and Task Queue from environment variables you set on the Worker Pool, and mount the Temporal Cloud API key or TLS material from Secret Manager rather than passing it in plaintext. -`loadClientConnectConfig()` returns `connectionOptions` and `namespace`. Pass `connectionOptions` to `NativeConnection.connect()` and `namespace` to `Worker.create()`, as shown above. +To load the connection settings from a TOML config file and profiles instead of reading each variable by hand, use `loadClientConnectConfig()` from `@temporalio/envconfig` and pass its `connectionOptions` and `namespace` to `NativeConnection.connect()` and `Worker.create()`. +For the supported variables and the config file format, see [Environment configuration](/develop/environment-configuration). ## Package the Worker image {/* #package-image */} diff --git a/docs/production-deployment/worker-deployments/serverless-workers/cloud-run/index.mdx b/docs/production-deployment/worker-deployments/serverless-workers/cloud-run/index.mdx index 728cc54e66..2e24c39a9e 100644 --- a/docs/production-deployment/worker-deployments/serverless-workers/cloud-run/index.mdx +++ b/docs/production-deployment/worker-deployments/serverless-workers/cloud-run/index.mdx @@ -193,17 +193,19 @@ For more on the Go Worker setup, see ```ts -import { loadClientConnectConfig } from '@temporalio/envconfig'; import { NativeConnection, Worker } from '@temporalio/worker'; import * as activities from './activities'; async function run() { - const config = loadClientConnectConfig(); - const connection = await NativeConnection.connect(config.connectionOptions); + const connection = await NativeConnection.connect({ + address: process.env.TEMPORAL_ADDRESS, + apiKey: process.env.TEMPORAL_API_KEY, + tls: true, + }); const worker = await Worker.create({ connection, - namespace: config.namespace, + namespace: process.env.TEMPORAL_NAMESPACE!, taskQueue: process.env.TEMPORAL_TASK_QUEUE!, workflowsPath: require.resolve('./workflows'), activities, From 385dbbcc88e8d6d7713e2239518a93335cb28ac1 Mon Sep 17 00:00:00 2001 From: Lenny Chen Date: Fri, 21 Aug 2026 13:44:10 -0700 Subject: [PATCH 6/6] docs: inline the Cloud Run Worker code until the features PR merges Removes the Snipsync markers, the generated source links, and the branch pin in snipsync.config.yaml. The links pointed at temporalio/features#861, which has not merged, so they would 404 once that branch is deleted. The code is unchanged from the snippets. When #861 lands, restore the markers and re-run snipsync. --- .../workers/serverless-workers/cloud-run.mdx | 9 +++++---- .../workers/serverless-workers/cloud-run.mdx | 16 +++++++++++++--- .../workers/serverless-workers/cloud-run.mdx | 8 ++++---- .../workers/serverless-workers/cloud-run.mdx | 5 ++--- snipsync.config.yaml | 2 -- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/docs/develop/dotnet/workers/serverless-workers/cloud-run.mdx b/docs/develop/dotnet/workers/serverless-workers/cloud-run.mdx index 9f13d7acc8..465e5982af 100644 --- a/docs/develop/dotnet/workers/serverless-workers/cloud-run.mdx +++ b/docs/develop/dotnet/workers/serverless-workers/cloud-run.mdx @@ -34,9 +34,11 @@ Build the Worker as you would any long-running .NET Worker, then set `Deployment The following Worker reads its connection settings and Task Queue from the environment, so the same image can run against any Namespace: - -[features/snippets/worker/worker.cs](https://github.com/temporalio/features/blob/worker-docs-snippets/features/snippets/worker/worker.cs) -```cs +```csharp +using Temporalio.Client; +using Temporalio.Common; +using Temporalio.Worker; + var client = await TemporalClient.ConnectAsync( new(Environment.GetEnvironmentVariable("TEMPORAL_ADDRESS")!) { @@ -59,7 +61,6 @@ options.AddAllActivities(typeof(GreetingActivities), null); using var worker = new TemporalWorker(client, options); await worker.ExecuteAsync(CancellationToken.None); ``` - The two arguments to `WorkerDeploymentVersion` are the deployment name and the build ID, and together they identify the Worker Deployment Version. Both values must match the version you create with `temporal worker deployment create-version` in the deployment guide, or the Worker polls under a version the WCI does not manage. diff --git a/docs/develop/java/workers/serverless-workers/cloud-run.mdx b/docs/develop/java/workers/serverless-workers/cloud-run.mdx index 7dfb45f9c2..bc718fa966 100644 --- a/docs/develop/java/workers/serverless-workers/cloud-run.mdx +++ b/docs/develop/java/workers/serverless-workers/cloud-run.mdx @@ -34,9 +34,20 @@ Build the Worker as you would any long-running Java Worker, then set `WorkerDepl The following Worker reads its connection settings and Task Queue from the environment, so the same image can run against any Namespace: - -[features/snippets/worker/worker.java](https://github.com/temporalio/features/blob/worker-docs-snippets/features/snippets/worker/worker.java) ```java +package example; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowClientOptions; +import io.temporal.common.VersioningBehavior; +import io.temporal.common.WorkerDeploymentVersion; +import io.temporal.serviceclient.WorkflowServiceStubs; +import io.temporal.serviceclient.WorkflowServiceStubsOptions; +import io.temporal.worker.Worker; +import io.temporal.worker.WorkerDeploymentOptions; +import io.temporal.worker.WorkerFactory; +import io.temporal.worker.WorkerOptions; + String apiKey = System.getenv("TEMPORAL_API_KEY"); WorkflowServiceStubs service = @@ -73,7 +84,6 @@ worker.registerActivitiesImplementations(new GreetingActivitiesImpl()); factory.start(); ``` - The two arguments to `WorkerDeploymentVersion` are the deployment name and the build ID, and together they identify the Worker Deployment Version. Both values must match the version you create with `temporal worker deployment create-version` in the deployment guide, or the Worker polls under a version the WCI does not manage. diff --git a/docs/develop/ruby/workers/serverless-workers/cloud-run.mdx b/docs/develop/ruby/workers/serverless-workers/cloud-run.mdx index 4c08245fc7..27c9f5c640 100644 --- a/docs/develop/ruby/workers/serverless-workers/cloud-run.mdx +++ b/docs/develop/ruby/workers/serverless-workers/cloud-run.mdx @@ -34,9 +34,10 @@ Build the Worker as you would any long-running Ruby Worker, then pass `deploymen The following Worker reads its connection settings and Task Queue from the environment, so the same image can run against any Namespace: - -[features/snippets/worker/worker.rb](https://github.com/temporalio/features/blob/worker-docs-snippets/features/snippets/worker/worker.rb) -```rb +```ruby +require 'temporalio/client' +require 'temporalio/worker' + client = Temporalio::Client.connect( ENV.fetch('TEMPORAL_ADDRESS'), ENV.fetch('TEMPORAL_NAMESPACE'), @@ -61,7 +62,6 @@ worker = Temporalio::Worker.new( worker.run ``` - `deployment_name` and `build_id` together identify the Worker Deployment Version. Both values must match the version you create with `temporal worker deployment create-version` in the deployment guide, or the Worker polls under a version the WCI does not manage. diff --git a/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx b/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx index 6580e2514b..245997a6e9 100644 --- a/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx +++ b/docs/develop/typescript/workers/serverless-workers/cloud-run.mdx @@ -42,9 +42,9 @@ Build the Worker as you would any long-running TypeScript Worker, then pass `wor The following Worker reads its connection settings and Task Queue from the environment, so the same image can run against any Namespace: - -[features/snippets/worker/worker.ts](https://github.com/temporalio/features/blob/worker-docs-snippets/features/snippets/worker/worker.ts) ```ts +import { NativeConnection, Worker } from '@temporalio/worker'; + const connection = await NativeConnection.connect({ address: process.env.TEMPORAL_ADDRESS, apiKey: process.env.TEMPORAL_API_KEY, @@ -65,7 +65,6 @@ const worker = await Worker.create({ await worker.run(); ``` - `deploymentName` and `buildId` together identify the Worker Deployment Version. Both values must match the version you create with `temporal worker deployment create-version` in the deployment guide, or the Worker polls under a version the WCI does not manage. diff --git a/snipsync.config.yaml b/snipsync.config.yaml index e1fca3791b..a1b6ba5c4f 100644 --- a/snipsync.config.yaml +++ b/snipsync.config.yaml @@ -11,8 +11,6 @@ origins: repo: reference-app-orders-go - owner: temporalio repo: features - # TODO: drop this pin once temporalio/features#861 merges. - ref: 'worker-docs-snippets' # Some samples were left in the SDK code itself because it has better testing # capabilities than the samples repo