From e3449f560f9d68b99584ec6a0cac9d2cce927773 Mon Sep 17 00:00:00 2001 From: seanbollin Date: Thu, 13 Aug 2026 17:08:48 -0700 Subject: [PATCH 1/6] Initial samples for Cloud Run public preview --- Directory.Packages.props | 1 + src/CloudRunWorker/.gitignore | 3 + src/CloudRunWorker/CloudRunWorkerSample.cs | 20 +++++ src/CloudRunWorker/Dockerfile | 22 +++++ src/CloudRunWorker/GreetingActivities.cs | 14 +++ .../GreetingWorkflow.workflow.cs | 19 ++++ src/CloudRunWorker/Program.cs | 75 ++++++++++++++++ .../TemporalioSamples.CloudRunWorker.csproj | 11 +++ src/CloudRunWorker/collector-config.yaml | 88 +++++++++++++++++++ src/CloudRunWorker/worker-pool.yaml | 62 +++++++++++++ 10 files changed, 315 insertions(+) create mode 100644 src/CloudRunWorker/.gitignore create mode 100644 src/CloudRunWorker/CloudRunWorkerSample.cs create mode 100644 src/CloudRunWorker/Dockerfile create mode 100644 src/CloudRunWorker/GreetingActivities.cs create mode 100644 src/CloudRunWorker/GreetingWorkflow.workflow.cs create mode 100644 src/CloudRunWorker/Program.cs create mode 100644 src/CloudRunWorker/TemporalioSamples.CloudRunWorker.csproj create mode 100644 src/CloudRunWorker/collector-config.yaml create mode 100644 src/CloudRunWorker/worker-pool.yaml diff --git a/Directory.Packages.props b/Directory.Packages.props index 38177b2..4123496 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -24,6 +24,7 @@ + diff --git a/src/CloudRunWorker/.gitignore b/src/CloudRunWorker/.gitignore new file mode 100644 index 0000000..f2850e0 --- /dev/null +++ b/src/CloudRunWorker/.gitignore @@ -0,0 +1,3 @@ +# Temporary test scaffolding for the unpublished GCP Cloud Run package (remove once published). +local-packages/ +nuget.config diff --git a/src/CloudRunWorker/CloudRunWorkerSample.cs b/src/CloudRunWorker/CloudRunWorkerSample.cs new file mode 100644 index 0000000..f3e5bd6 --- /dev/null +++ b/src/CloudRunWorker/CloudRunWorkerSample.cs @@ -0,0 +1,20 @@ +namespace TemporalioSamples.CloudRunWorker; + +using Temporalio.Worker; + +/// +/// Shared worker configuration so both the entrypoint and the tests register the same +/// workflow and activities. +/// +public static class CloudRunWorkerSample +{ + /// + /// Register the sample workflow and activities on the given worker options. + /// + /// Worker options to configure. + /// The same options, for chaining. + public static TemporalWorkerOptions ConfigureOptions(TemporalWorkerOptions options) => + options. + AddWorkflow(). + AddActivity(GreetingActivities.SayHello); +} diff --git a/src/CloudRunWorker/Dockerfile b/src/CloudRunWorker/Dockerfile new file mode 100644 index 0000000..c08e991 --- /dev/null +++ b/src/CloudRunWorker/Dockerfile @@ -0,0 +1,22 @@ +# syntax=docker/dockerfile:1 +# +# Builds the Cloud Run worker image. Temporalio (with its bundled native bridge for linux) is +# restored from NuGet; the GCP Cloud Run OpenTelemetry package is restored from the local folder +# feed under this sample until it is published (see nuget.config / local-packages). No SDK-from- +# source or Rust build is needed. +# +# Build context is the samples-dotnet repo root (so the shared Directory.*.props / global.json are +# available): +# docker build -f src/CloudRunWorker/Dockerfile -t . +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +WORKDIR /src +COPY global.json Directory.Build.props Directory.Packages.props .editorconfig ./ +COPY src/CloudRunWorker/ ./src/CloudRunWorker/ +RUN dotnet publish src/CloudRunWorker/TemporalioSamples.CloudRunWorker.csproj -c Release -o /app + +FROM mcr.microsoft.com/dotnet/runtime:8.0 +RUN useradd --create-home --uid 10001 worker +WORKDIR /app +COPY --from=build --chown=worker:worker /app ./ +USER 10001 +ENTRYPOINT ["dotnet", "TemporalioSamples.CloudRunWorker.dll"] diff --git a/src/CloudRunWorker/GreetingActivities.cs b/src/CloudRunWorker/GreetingActivities.cs new file mode 100644 index 0000000..6f71c1d --- /dev/null +++ b/src/CloudRunWorker/GreetingActivities.cs @@ -0,0 +1,14 @@ +namespace TemporalioSamples.CloudRunWorker; + +using Microsoft.Extensions.Logging; +using Temporalio.Activities; + +public static class GreetingActivities +{ + [Activity] + public static string SayHello(string name) + { + ActivityExecutionContext.Current.Logger.LogInformation("SayHello activity: {Name}", name); + return $"Hello, {name}!"; + } +} diff --git a/src/CloudRunWorker/GreetingWorkflow.workflow.cs b/src/CloudRunWorker/GreetingWorkflow.workflow.cs new file mode 100644 index 0000000..e52a7a5 --- /dev/null +++ b/src/CloudRunWorker/GreetingWorkflow.workflow.cs @@ -0,0 +1,19 @@ +namespace TemporalioSamples.CloudRunWorker; + +using Microsoft.Extensions.Logging; +using Temporalio.Workflows; + +[Workflow] +public class GreetingWorkflow +{ + [WorkflowRun] + public async Task RunAsync(string name) + { + Workflow.Logger.LogInformation("GreetingWorkflow started: {Name}", name); + var result = await Workflow.ExecuteActivityAsync( + () => GreetingActivities.SayHello(name), + new() { StartToCloseTimeout = TimeSpan.FromSeconds(10) }); + Workflow.Logger.LogInformation("GreetingWorkflow completed: {Result}", result); + return result; + } +} diff --git a/src/CloudRunWorker/Program.cs b/src/CloudRunWorker/Program.cs new file mode 100644 index 0000000..baf343b --- /dev/null +++ b/src/CloudRunWorker/Program.cs @@ -0,0 +1,75 @@ +using System.Runtime.InteropServices; +using Microsoft.Extensions.Logging; +using Temporalio.Client; +using Temporalio.Common.EnvConfig; +using Temporalio.Extensions.Gcp.CloudRun.OpenTelemetry; +using Temporalio.Worker; +using TemporalioSamples.CloudRunWorker; + +// Build client connection options from environment configuration (TEMPORAL_ADDRESS, +// TEMPORAL_NAMESPACE, TEMPORAL_API_KEY, ...). With no API key and no TLS block this connects in +// plaintext, which is what a local dev server (reached over an ngrok TCP tunnel) needs. +var connectOptions = ClientEnvConfig.LoadClientConnectOptions(); +connectOptions.TargetHost ??= "localhost:7233"; + +// Send all Temporal logs to stdout so Cloud Run captures them in Cloud Logging. +connectOptions.LoggerFactory = LoggerFactory.Create(builder => + builder. + AddSimpleConsole(options => options.TimestampFormat = "[HH:mm:ss] "). + SetMinimumLevel(LogLevel.Information)); + +var taskQueue = Environment.GetEnvironmentVariable("TEMPORAL_TASK_QUEUE") ?? "cloud-run-worker"; + +// The --starter mode runs a single workflow (useful for kicking off work locally against the same +// server the deployed worker polls). Applying the defaults here too propagates a trace context into +// the workflow so the deployed worker's spans join the same distributed trace. +if (args.Contains("--starter")) +{ + using var starterTelemetry = connectOptions.ApplyGoogleCloudRunOpenTelemetryDefaults(); + var starterClient = await TemporalClient.ConnectAsync(connectOptions); + var greeting = await starterClient.ExecuteWorkflowAsync( + (GreetingWorkflow wf) => wf.RunAsync("Temporal"), + new($"cloud-run-worker-{Guid.NewGuid():N}", taskQueue)); + Console.WriteLine("Workflow result: {0}", greeting); + await starterTelemetry.FlushAsync(TimeSpan.FromSeconds(2)); + return; +} + +// Apply the Google Cloud Run OpenTelemetry defaults: adds the tracing interceptor and configures a +// Temporal runtime that exports Core metrics + traces over OTLP to the local collector sidecar. The +// returned handle owns the tracer provider and is flushed on shutdown. +using var telemetry = connectOptions.ApplyGoogleCloudRunOpenTelemetryDefaults(); + +var client = await TemporalClient.ConnectAsync(connectOptions); + +using var cts = new CancellationTokenSource(); +Console.CancelKeyPress += (_, eventArgs) => +{ + eventArgs.Cancel = true; + cts.Cancel(); +}; + +// Cloud Run signals shutdown with SIGTERM (about 10 seconds before SIGKILL). +using var sigterm = PosixSignalRegistration.Create(PosixSignal.SIGTERM, _ => cts.Cancel()); + +using var worker = new TemporalWorker( + client, CloudRunWorkerSample.ConfigureOptions(new(taskQueue))); + +Console.WriteLine( + "Worker running: taskQueue={0} address={1} namespace={2}", + taskQueue, + connectOptions.TargetHost, + connectOptions.Namespace ?? "default"); +try +{ + await worker.ExecuteAsync(cts.Token); +} +catch (OperationCanceledException) +{ + Console.WriteLine("Worker shutting down"); +} + +// Flush buffered traces within the Cloud Run shutdown grace window. Core metrics are exported +// periodically by the runtime and have no explicit flush. +await telemetry.FlushAsync(TimeSpan.FromSeconds(2)); +Console.WriteLine("Worker stopped"); diff --git a/src/CloudRunWorker/TemporalioSamples.CloudRunWorker.csproj b/src/CloudRunWorker/TemporalioSamples.CloudRunWorker.csproj new file mode 100644 index 0000000..bec8e3e --- /dev/null +++ b/src/CloudRunWorker/TemporalioSamples.CloudRunWorker.csproj @@ -0,0 +1,11 @@ + + + + Exe + + + + + + + diff --git a/src/CloudRunWorker/collector-config.yaml b/src/CloudRunWorker/collector-config.yaml new file mode 100644 index 0000000..2fa7df6 --- /dev/null +++ b/src/CloudRunWorker/collector-config.yaml @@ -0,0 +1,88 @@ +# Google-Built OpenTelemetry Collector config for the Cloud Run worker-pool sidecar. +# metrics -> Google Managed Service for Prometheus (googlemanagedprometheus) +# traces -> Cloud Trace via the Telemetry API (OTLP), authenticated with the runtime SA (ADC) +# The worker exports OTLP/gRPC to localhost:4317; the collector detects GCP resource attributes and +# fans out. Auth uses the worker-pool service account's Application Default Credentials via the +# googleclientauth extension (no key files). +receivers: + otlp: + protocols: + grpc: + endpoint: localhost:4317 + +processors: + # Batch traces for throughput. Do NOT add a batch processor to the cumulative-metrics pipeline: a + # shutdown flush could be batched with a recent periodic export of the same series and rejected as + # a duplicate time series. + batch/traces: + send_batch_max_size: 200 + send_batch_size: 200 + timeout: 5s + memory_limiter: + check_interval: 1s + limit_percentage: 65 + spike_limit_percentage: 20 + resourcedetection: + detectors: [gcp] + timeout: 10s + # Rename Temporal datapoint labels that collide with the target labels Google Managed Service for + # Prometheus injects (e.g. Temporal emits a `namespace` label). + transform/collision: + metric_statements: + - context: datapoint + statements: + - set(attributes["exported_location"], attributes["location"]) + - delete_key(attributes, "location") + - set(attributes["exported_cluster"], attributes["cluster"]) + - delete_key(attributes, "cluster") + - set(attributes["exported_namespace"], attributes["namespace"]) + - delete_key(attributes, "namespace") + - set(attributes["exported_job"], attributes["job"]) + - delete_key(attributes, "job") + - set(attributes["exported_instance"], attributes["instance"]) + - delete_key(attributes, "instance") + - set(attributes["exported_project_id"], attributes["project_id"]) + - delete_key(attributes, "project_id") + # The Telemetry API expects the Google Cloud project in gcp.project_id. + transform/set_project_id: + error_mode: ignore + trace_statements: + - set(resource.attributes["gcp.project_id"], resource.attributes["gcp.project.id"]) where resource.attributes["gcp.project.id"] != nil + - set(resource.attributes["gcp.project_id"], resource.attributes["cloud.account.id"]) where resource.attributes["gcp.project_id"] == nil and resource.attributes["cloud.account.id"] != nil + +exporters: + googlemanagedprometheus: + otlp: + endpoint: telemetry.googleapis.com:443 + compression: none + balancer_name: pick_first + auth: + authenticator: googleclientauth + +extensions: + health_check: + endpoint: 0.0.0.0:13133 + googleclientauth: + +service: + extensions: + - health_check + - googleclientauth + pipelines: + metrics: + receivers: [otlp] + processors: [memory_limiter, resourcedetection, transform/collision] + exporters: [googlemanagedprometheus] + traces: + receivers: [otlp] + processors: [memory_limiter, resourcedetection, transform/set_project_id, batch/traces] + exporters: [otlp] + telemetry: + metrics: + readers: + - periodic: + exporter: + otlp: + protocol: grpc + endpoint: http://localhost:4317 + insecure: true diff --git a/src/CloudRunWorker/worker-pool.yaml b/src/CloudRunWorker/worker-pool.yaml new file mode 100644 index 0000000..8dd3d69 --- /dev/null +++ b/src/CloudRunWorker/worker-pool.yaml @@ -0,0 +1,62 @@ +# Cloud Run WorkerPool: a continuously-polling Temporal worker + a Google-Built OpenTelemetry +# Collector sidecar. Render placeholders with `envsubst` (see README) then apply with +# `gcloud run worker-pools replace`. +# +# This sample connects to a Temporal server over TEMPORAL_ADDRESS with no API key / no TLS (e.g. a +# local dev server exposed via an ngrok TCP tunnel). For Temporal Cloud, add a TEMPORAL_API_KEY env +# var sourced from a Secret Manager secretKeyRef (see the Java/Python samples). +apiVersion: run.googleapis.com/v1 +kind: WorkerPool +metadata: + name: "${WORKER_POOL}" + labels: + cloud.googleapis.com/location: "${REGION}" + annotations: + run.googleapis.com/scalingMode: manual + run.googleapis.com/manualInstanceCount: "${INSTANCE_COUNT}" +spec: + template: + metadata: + annotations: + run.googleapis.com/container-dependencies: '{"worker":["collector"]}' + run.googleapis.com/execution-environment: gen2 + spec: + containerConcurrency: 0 + serviceAccountName: "${SERVICE_ACCOUNT_EMAIL}" + containers: + - name: worker + image: "${WORKER_IMAGE}" + env: + - name: TEMPORAL_ADDRESS + value: "${TEMPORAL_ADDRESS}" + - name: TEMPORAL_NAMESPACE + value: "${TEMPORAL_NAMESPACE}" + - name: TEMPORAL_TASK_QUEUE + value: "${TEMPORAL_TASK_QUEUE}" + - name: OTEL_EXPORTER_OTLP_ENDPOINT + value: http://localhost:4317 + resources: + limits: + cpu: "1" + memory: 512Mi + - name: collector + image: us-docker.pkg.dev/cloud-ops-agents-artifacts/google-cloud-opentelemetry-collector/otelcol-google:0.156.0 + args: + - --config=env:OTELCOL_CONFIG + env: + - name: OTELCOL_CONFIG + valueFrom: + secretKeyRef: + key: "${COLLECTOR_CONFIG_SECRET_VERSION}" + name: "${COLLECTOR_CONFIG_SECRET}" + startupProbe: + httpGet: + path: / + port: 13133 + timeoutSeconds: 1 + periodSeconds: 2 + failureThreshold: 30 + resources: + limits: + cpu: "1" + memory: 512Mi From 00d329d8b0ac470b515448d30871f488aae3c193 Mon Sep 17 00:00:00 2001 From: seanbollin Date: Fri, 14 Aug 2026 10:42:49 -0700 Subject: [PATCH 2/6] Initial OpenTelemetry .NET SDK Samples --- README.md | 1 + TemporalioSamples.sln | 15 ++++++++++ nuget.config | 22 ++++++++++++++ tests/CloudRunWorker/CloudRunWorkerTests.cs | 33 +++++++++++++++++++++ tests/TemporalioSamples.Tests.csproj | 1 + 5 files changed, 72 insertions(+) create mode 100644 nuget.config create mode 100644 tests/CloudRunWorker/CloudRunWorkerTests.cs diff --git a/README.md b/README.md index a09c161..89fb57c 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Prerequisites: * [AspNet](src/AspNet) - Demonstration of a generic host worker and an ASP.NET workflow starter. * [Bedrock](src/Bedrock) - Orchestrate a chatbot with Amazon Bedrock. * [ClientMtls](src/ClientMtls) - How to use client certificate authentication, e.g. for Temporal Cloud. +* [CloudRunWorker](src/CloudRunWorker) - Run a continuously-polling worker in a Google Cloud Run worker pool, exporting OpenTelemetry metrics and traces to a collector sidecar. * [ContextPropagation](src/ContextPropagation) - Context propagation via interceptors. * [CounterInterceptor](src/CounterInterceptor/) - Simple Workflow and Client Interceptors example. * [DependencyInjection](src/DependencyInjection) - How to inject dependencies in activities and use generic hosts for workers diff --git a/TemporalioSamples.sln b/TemporalioSamples.sln index c945182..81d545e 100644 --- a/TemporalioSamples.sln +++ b/TemporalioSamples.sln @@ -7,6 +7,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{1A647B41-53D EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TemporalioSamples.ActivityWorker", "src\ActivityWorker\TemporalioSamples.ActivityWorker.csproj", "{7AECC7C6-9A21-4B8A-84D9-AFC4F5840CAF}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TemporalioSamples.CloudRunWorker", "src\CloudRunWorker\TemporalioSamples.CloudRunWorker.csproj", "{E0F934F9-10A7-41A0-A85E-EE6D0E267367}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TemporalioSamples.Tests", "tests\TemporalioSamples.Tests.csproj", "{3FA7E5DF-03B7-4586-A980-85C155B376C5}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AspNet", "AspNet", "{E431D279-E02B-4670-B934-3DB9F15D8CCC}" @@ -167,6 +169,18 @@ Global {7AECC7C6-9A21-4B8A-84D9-AFC4F5840CAF}.Release|x64.Build.0 = Release|Any CPU {7AECC7C6-9A21-4B8A-84D9-AFC4F5840CAF}.Release|x86.ActiveCfg = Release|Any CPU {7AECC7C6-9A21-4B8A-84D9-AFC4F5840CAF}.Release|x86.Build.0 = Release|Any CPU + {E0F934F9-10A7-41A0-A85E-EE6D0E267367}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E0F934F9-10A7-41A0-A85E-EE6D0E267367}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0F934F9-10A7-41A0-A85E-EE6D0E267367}.Debug|x64.ActiveCfg = Debug|Any CPU + {E0F934F9-10A7-41A0-A85E-EE6D0E267367}.Debug|x64.Build.0 = Debug|Any CPU + {E0F934F9-10A7-41A0-A85E-EE6D0E267367}.Debug|x86.ActiveCfg = Debug|Any CPU + {E0F934F9-10A7-41A0-A85E-EE6D0E267367}.Debug|x86.Build.0 = Debug|Any CPU + {E0F934F9-10A7-41A0-A85E-EE6D0E267367}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0F934F9-10A7-41A0-A85E-EE6D0E267367}.Release|Any CPU.Build.0 = Release|Any CPU + {E0F934F9-10A7-41A0-A85E-EE6D0E267367}.Release|x64.ActiveCfg = Release|Any CPU + {E0F934F9-10A7-41A0-A85E-EE6D0E267367}.Release|x64.Build.0 = Release|Any CPU + {E0F934F9-10A7-41A0-A85E-EE6D0E267367}.Release|x86.ActiveCfg = Release|Any CPU + {E0F934F9-10A7-41A0-A85E-EE6D0E267367}.Release|x86.Build.0 = Release|Any CPU {3FA7E5DF-03B7-4586-A980-85C155B376C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3FA7E5DF-03B7-4586-A980-85C155B376C5}.Debug|Any CPU.Build.0 = Debug|Any CPU {3FA7E5DF-03B7-4586-A980-85C155B376C5}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -821,6 +835,7 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {7AECC7C6-9A21-4B8A-84D9-AFC4F5840CAF} = {1A647B41-53D0-4638-AE5A-6630BAAE45FC} + {E0F934F9-10A7-41A0-A85E-EE6D0E267367} = {1A647B41-53D0-4638-AE5A-6630BAAE45FC} {E431D279-E02B-4670-B934-3DB9F15D8CCC} = {1A647B41-53D0-4638-AE5A-6630BAAE45FC} {31EC2647-6A5A-42D1-B7B5-02804B340726} = {E431D279-E02B-4670-B934-3DB9F15D8CCC} {AFFA4143-DC28-4FBE-A33B-D6414F541EA4} = {E431D279-E02B-4670-B934-3DB9F15D8CCC} diff --git a/nuget.config b/nuget.config new file mode 100644 index 0000000..84fe21f --- /dev/null +++ b/nuget.config @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff --git a/tests/CloudRunWorker/CloudRunWorkerTests.cs b/tests/CloudRunWorker/CloudRunWorkerTests.cs new file mode 100644 index 0000000..ab33500 --- /dev/null +++ b/tests/CloudRunWorker/CloudRunWorkerTests.cs @@ -0,0 +1,33 @@ +namespace TemporalioSamples.Tests.CloudRunWorker; + +using Temporalio.Client; +using Temporalio.Testing; +using Temporalio.Worker; +using TemporalioSamples.CloudRunWorker; +using Xunit; +using Xunit.Abstractions; + +public class CloudRunWorkerTests : TestBase +{ + public CloudRunWorkerTests(ITestOutputHelper output) + : base(output) + { + } + + [TimeSkippingServerFact] + public async Task GreetingWorkflow_SimpleRun_Succeeds() + { + await using var env = await WorkflowEnvironment.StartTimeSkippingAsync(); + using var worker = new TemporalWorker( + env.Client, + CloudRunWorkerSample.ConfigureOptions( + new TemporalWorkerOptions("cloud-run-worker-test-task-queue"))); + await worker.ExecuteAsync(async () => + { + var result = await env.Client.ExecuteWorkflowAsync( + (GreetingWorkflow wf) => wf.RunAsync("Cloud Run"), + new(id: $"workflow-{Guid.NewGuid()}", taskQueue: worker.Options.TaskQueue!)); + Assert.Equal("Hello, Cloud Run!", result); + }); + } +} diff --git a/tests/TemporalioSamples.Tests.csproj b/tests/TemporalioSamples.Tests.csproj index 66b6b0a..7bdffd4 100644 --- a/tests/TemporalioSamples.Tests.csproj +++ b/tests/TemporalioSamples.Tests.csproj @@ -22,6 +22,7 @@ + From 69055492370265a519fd31bfce4255bcac7d9b7e Mon Sep 17 00:00:00 2001 From: seanbollin Date: Wed, 9 Sep 2026 14:59:47 -0700 Subject: [PATCH 3/6] Restructure Cloud Run OTel sample to src/Gcp/CloudRun/OpenTelemetry Move the sample from src/CloudRunWorker to src/Gcp/CloudRun/OpenTelemetry (and its test to tests/Gcp/CloudRun/OpenTelemetry) so the layout mirrors the merged SDK package Temporalio.Extensions.Gcp.CloudRun.OpenTelemetry and the other SDKs' Cloud Run samples, leaving room for additional Cloud Run samples (e.g. worker ID) under src/Gcp/CloudRun/. - Rename the project/namespace to TemporalioSamples.Gcp.CloudRun.OpenTelemetry (updating the .sln, the tests project reference, and the Dockerfile paths and output dll name). - Bump the Temporalio package family to 1.18.0 (the release that introduces the GCP Cloud Run OpenTelemetry package) and, as its required companion, NexusRpc to 0.4.0. The shared test project references this sample, so the whole repo must move together. - Point the temporary local-feed nuget.config at the new sample path. Verified with the merged package packed into the local feed: the full solution restores and builds at 1.18.0/NexusRpc 0.4.0, the sample emits TemporalioSamples.Gcp.CloudRun.OpenTelemetry.dll, and the test is discovered under the new namespace. Co-Authored-By: Claude Opus 4.8 --- README.md | 2 +- TemporalioSamples.sln | 2 +- nuget.config | 6 +++--- .../CloudRun/OpenTelemetry}/.gitignore | 0 .../CloudRun/OpenTelemetry}/CloudRunWorkerSample.cs | 2 +- .../CloudRun/OpenTelemetry}/Dockerfile | 8 ++++---- .../CloudRun/OpenTelemetry}/GreetingActivities.cs | 2 +- .../CloudRun/OpenTelemetry}/GreetingWorkflow.workflow.cs | 2 +- .../CloudRun/OpenTelemetry}/Program.cs | 2 +- .../TemporalioSamples.Gcp.CloudRun.OpenTelemetry.csproj} | 0 .../CloudRun/OpenTelemetry}/collector-config.yaml | 0 .../CloudRun/OpenTelemetry}/worker-pool.yaml | 0 .../CloudRun/OpenTelemetry}/CloudRunWorkerTests.cs | 4 ++-- tests/TemporalioSamples.Tests.csproj | 2 +- 14 files changed, 16 insertions(+), 16 deletions(-) rename src/{CloudRunWorker => Gcp/CloudRun/OpenTelemetry}/.gitignore (100%) rename src/{CloudRunWorker => Gcp/CloudRun/OpenTelemetry}/CloudRunWorkerSample.cs (92%) rename src/{CloudRunWorker => Gcp/CloudRun/OpenTelemetry}/Dockerfile (69%) rename src/{CloudRunWorker => Gcp/CloudRun/OpenTelemetry}/GreetingActivities.cs (84%) rename src/{CloudRunWorker => Gcp/CloudRun/OpenTelemetry}/GreetingWorkflow.workflow.cs (91%) rename src/{CloudRunWorker => Gcp/CloudRun/OpenTelemetry}/Program.cs (98%) rename src/{CloudRunWorker/TemporalioSamples.CloudRunWorker.csproj => Gcp/CloudRun/OpenTelemetry/TemporalioSamples.Gcp.CloudRun.OpenTelemetry.csproj} (100%) rename src/{CloudRunWorker => Gcp/CloudRun/OpenTelemetry}/collector-config.yaml (100%) rename src/{CloudRunWorker => Gcp/CloudRun/OpenTelemetry}/worker-pool.yaml (100%) rename tests/{CloudRunWorker => Gcp/CloudRun/OpenTelemetry}/CloudRunWorkerTests.cs (89%) diff --git a/README.md b/README.md index 89fb57c..e95a2c7 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Prerequisites: * [AspNet](src/AspNet) - Demonstration of a generic host worker and an ASP.NET workflow starter. * [Bedrock](src/Bedrock) - Orchestrate a chatbot with Amazon Bedrock. * [ClientMtls](src/ClientMtls) - How to use client certificate authentication, e.g. for Temporal Cloud. -* [CloudRunWorker](src/CloudRunWorker) - Run a continuously-polling worker in a Google Cloud Run worker pool, exporting OpenTelemetry metrics and traces to a collector sidecar. +* [Gcp/CloudRun/OpenTelemetry](src/Gcp/CloudRun/OpenTelemetry) - Run a continuously-polling worker in a Google Cloud Run worker pool, exporting OpenTelemetry metrics and traces to a collector sidecar. * [ContextPropagation](src/ContextPropagation) - Context propagation via interceptors. * [CounterInterceptor](src/CounterInterceptor/) - Simple Workflow and Client Interceptors example. * [DependencyInjection](src/DependencyInjection) - How to inject dependencies in activities and use generic hosts for workers diff --git a/TemporalioSamples.sln b/TemporalioSamples.sln index 81d545e..f6dbf08 100644 --- a/TemporalioSamples.sln +++ b/TemporalioSamples.sln @@ -7,7 +7,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{1A647B41-53D EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TemporalioSamples.ActivityWorker", "src\ActivityWorker\TemporalioSamples.ActivityWorker.csproj", "{7AECC7C6-9A21-4B8A-84D9-AFC4F5840CAF}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TemporalioSamples.CloudRunWorker", "src\CloudRunWorker\TemporalioSamples.CloudRunWorker.csproj", "{E0F934F9-10A7-41A0-A85E-EE6D0E267367}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TemporalioSamples.Gcp.CloudRun.OpenTelemetry", "src\Gcp\CloudRun\OpenTelemetry\TemporalioSamples.Gcp.CloudRun.OpenTelemetry.csproj", "{E0F934F9-10A7-41A0-A85E-EE6D0E267367}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TemporalioSamples.Tests", "tests\TemporalioSamples.Tests.csproj", "{3FA7E5DF-03B7-4586-A980-85C155B376C5}" EndProject diff --git a/nuget.config b/nuget.config index 84fe21f..dddb33b 100644 --- a/nuget.config +++ b/nuget.config @@ -2,14 +2,14 @@ - + diff --git a/src/CloudRunWorker/.gitignore b/src/Gcp/CloudRun/OpenTelemetry/.gitignore similarity index 100% rename from src/CloudRunWorker/.gitignore rename to src/Gcp/CloudRun/OpenTelemetry/.gitignore diff --git a/src/CloudRunWorker/CloudRunWorkerSample.cs b/src/Gcp/CloudRun/OpenTelemetry/CloudRunWorkerSample.cs similarity index 92% rename from src/CloudRunWorker/CloudRunWorkerSample.cs rename to src/Gcp/CloudRun/OpenTelemetry/CloudRunWorkerSample.cs index f3e5bd6..502dd26 100644 --- a/src/CloudRunWorker/CloudRunWorkerSample.cs +++ b/src/Gcp/CloudRun/OpenTelemetry/CloudRunWorkerSample.cs @@ -1,4 +1,4 @@ -namespace TemporalioSamples.CloudRunWorker; +namespace TemporalioSamples.Gcp.CloudRun.OpenTelemetry; using Temporalio.Worker; diff --git a/src/CloudRunWorker/Dockerfile b/src/Gcp/CloudRun/OpenTelemetry/Dockerfile similarity index 69% rename from src/CloudRunWorker/Dockerfile rename to src/Gcp/CloudRun/OpenTelemetry/Dockerfile index c08e991..4d2037b 100644 --- a/src/CloudRunWorker/Dockerfile +++ b/src/Gcp/CloudRun/OpenTelemetry/Dockerfile @@ -7,16 +7,16 @@ # # Build context is the samples-dotnet repo root (so the shared Directory.*.props / global.json are # available): -# docker build -f src/CloudRunWorker/Dockerfile -t . +# docker build -f src/Gcp/CloudRun/OpenTelemetry/Dockerfile -t . FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY global.json Directory.Build.props Directory.Packages.props .editorconfig ./ -COPY src/CloudRunWorker/ ./src/CloudRunWorker/ -RUN dotnet publish src/CloudRunWorker/TemporalioSamples.CloudRunWorker.csproj -c Release -o /app +COPY src/Gcp/CloudRun/OpenTelemetry/ ./src/Gcp/CloudRun/OpenTelemetry/ +RUN dotnet publish src/Gcp/CloudRun/OpenTelemetry/TemporalioSamples.Gcp.CloudRun.OpenTelemetry.csproj -c Release -o /app FROM mcr.microsoft.com/dotnet/runtime:8.0 RUN useradd --create-home --uid 10001 worker WORKDIR /app COPY --from=build --chown=worker:worker /app ./ USER 10001 -ENTRYPOINT ["dotnet", "TemporalioSamples.CloudRunWorker.dll"] +ENTRYPOINT ["dotnet", "TemporalioSamples.Gcp.CloudRun.OpenTelemetry.dll"] diff --git a/src/CloudRunWorker/GreetingActivities.cs b/src/Gcp/CloudRun/OpenTelemetry/GreetingActivities.cs similarity index 84% rename from src/CloudRunWorker/GreetingActivities.cs rename to src/Gcp/CloudRun/OpenTelemetry/GreetingActivities.cs index 6f71c1d..a04bf65 100644 --- a/src/CloudRunWorker/GreetingActivities.cs +++ b/src/Gcp/CloudRun/OpenTelemetry/GreetingActivities.cs @@ -1,4 +1,4 @@ -namespace TemporalioSamples.CloudRunWorker; +namespace TemporalioSamples.Gcp.CloudRun.OpenTelemetry; using Microsoft.Extensions.Logging; using Temporalio.Activities; diff --git a/src/CloudRunWorker/GreetingWorkflow.workflow.cs b/src/Gcp/CloudRun/OpenTelemetry/GreetingWorkflow.workflow.cs similarity index 91% rename from src/CloudRunWorker/GreetingWorkflow.workflow.cs rename to src/Gcp/CloudRun/OpenTelemetry/GreetingWorkflow.workflow.cs index e52a7a5..98e4463 100644 --- a/src/CloudRunWorker/GreetingWorkflow.workflow.cs +++ b/src/Gcp/CloudRun/OpenTelemetry/GreetingWorkflow.workflow.cs @@ -1,4 +1,4 @@ -namespace TemporalioSamples.CloudRunWorker; +namespace TemporalioSamples.Gcp.CloudRun.OpenTelemetry; using Microsoft.Extensions.Logging; using Temporalio.Workflows; diff --git a/src/CloudRunWorker/Program.cs b/src/Gcp/CloudRun/OpenTelemetry/Program.cs similarity index 98% rename from src/CloudRunWorker/Program.cs rename to src/Gcp/CloudRun/OpenTelemetry/Program.cs index baf343b..c8a5856 100644 --- a/src/CloudRunWorker/Program.cs +++ b/src/Gcp/CloudRun/OpenTelemetry/Program.cs @@ -4,7 +4,7 @@ using Temporalio.Common.EnvConfig; using Temporalio.Extensions.Gcp.CloudRun.OpenTelemetry; using Temporalio.Worker; -using TemporalioSamples.CloudRunWorker; +using TemporalioSamples.Gcp.CloudRun.OpenTelemetry; // Build client connection options from environment configuration (TEMPORAL_ADDRESS, // TEMPORAL_NAMESPACE, TEMPORAL_API_KEY, ...). With no API key and no TLS block this connects in diff --git a/src/CloudRunWorker/TemporalioSamples.CloudRunWorker.csproj b/src/Gcp/CloudRun/OpenTelemetry/TemporalioSamples.Gcp.CloudRun.OpenTelemetry.csproj similarity index 100% rename from src/CloudRunWorker/TemporalioSamples.CloudRunWorker.csproj rename to src/Gcp/CloudRun/OpenTelemetry/TemporalioSamples.Gcp.CloudRun.OpenTelemetry.csproj diff --git a/src/CloudRunWorker/collector-config.yaml b/src/Gcp/CloudRun/OpenTelemetry/collector-config.yaml similarity index 100% rename from src/CloudRunWorker/collector-config.yaml rename to src/Gcp/CloudRun/OpenTelemetry/collector-config.yaml diff --git a/src/CloudRunWorker/worker-pool.yaml b/src/Gcp/CloudRun/OpenTelemetry/worker-pool.yaml similarity index 100% rename from src/CloudRunWorker/worker-pool.yaml rename to src/Gcp/CloudRun/OpenTelemetry/worker-pool.yaml diff --git a/tests/CloudRunWorker/CloudRunWorkerTests.cs b/tests/Gcp/CloudRun/OpenTelemetry/CloudRunWorkerTests.cs similarity index 89% rename from tests/CloudRunWorker/CloudRunWorkerTests.cs rename to tests/Gcp/CloudRun/OpenTelemetry/CloudRunWorkerTests.cs index ab33500..a24889c 100644 --- a/tests/CloudRunWorker/CloudRunWorkerTests.cs +++ b/tests/Gcp/CloudRun/OpenTelemetry/CloudRunWorkerTests.cs @@ -1,9 +1,9 @@ -namespace TemporalioSamples.Tests.CloudRunWorker; +namespace TemporalioSamples.Tests.Gcp.CloudRun.OpenTelemetry; using Temporalio.Client; using Temporalio.Testing; using Temporalio.Worker; -using TemporalioSamples.CloudRunWorker; +using TemporalioSamples.Gcp.CloudRun.OpenTelemetry; using Xunit; using Xunit.Abstractions; diff --git a/tests/TemporalioSamples.Tests.csproj b/tests/TemporalioSamples.Tests.csproj index 7bdffd4..988d31d 100644 --- a/tests/TemporalioSamples.Tests.csproj +++ b/tests/TemporalioSamples.Tests.csproj @@ -22,7 +22,7 @@ - + From 0ddf8b992ee94b013111492c7c15773f94f8468a Mon Sep 17 00:00:00 2001 From: seanbollin Date: Fri, 18 Sep 2026 10:36:36 -0700 Subject: [PATCH 4/6] Pin to 1.19.0, restore extension from committed local feed, trim verbosity --- README.md | 2 +- nuget.config | 7 +-- src/Gcp/CloudRun/OpenTelemetry/.gitignore | 3 - .../OpenTelemetry/CloudRunWorkerSample.cs | 10 +--- src/Gcp/CloudRun/OpenTelemetry/Dockerfile | 12 +--- src/Gcp/CloudRun/OpenTelemetry/Program.cs | 20 ++----- src/Gcp/CloudRun/OpenTelemetry/README.md | 52 ++++++++++++++++++ .../OpenTelemetry/collector-config.yaml | 10 +--- ...ns.Gcp.CloudRun.OpenTelemetry.1.19.0.nupkg | Bin 0 -> 13403 bytes .../CloudRun/OpenTelemetry/worker-pool.yaml | 8 +-- 10 files changed, 66 insertions(+), 58 deletions(-) delete mode 100644 src/Gcp/CloudRun/OpenTelemetry/.gitignore create mode 100644 src/Gcp/CloudRun/OpenTelemetry/README.md create mode 100644 src/Gcp/CloudRun/OpenTelemetry/local-packages/Temporalio.Extensions.Gcp.CloudRun.OpenTelemetry.1.19.0.nupkg diff --git a/README.md b/README.md index e95a2c7..6069664 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,6 @@ Prerequisites: * [AspNet](src/AspNet) - Demonstration of a generic host worker and an ASP.NET workflow starter. * [Bedrock](src/Bedrock) - Orchestrate a chatbot with Amazon Bedrock. * [ClientMtls](src/ClientMtls) - How to use client certificate authentication, e.g. for Temporal Cloud. -* [Gcp/CloudRun/OpenTelemetry](src/Gcp/CloudRun/OpenTelemetry) - Run a continuously-polling worker in a Google Cloud Run worker pool, exporting OpenTelemetry metrics and traces to a collector sidecar. * [ContextPropagation](src/ContextPropagation) - Context propagation via interceptors. * [CounterInterceptor](src/CounterInterceptor/) - Simple Workflow and Client Interceptors example. * [DependencyInjection](src/DependencyInjection) - How to inject dependencies in activities and use generic hosts for workers @@ -26,6 +25,7 @@ Prerequisites: * [EagerWorkflowStart](src/EagerWorkflowStart) - Demonstrates usage of Eager Workflow Start to reduce latency for workflows that start with a local activity. * [Encryption](src/Encryption) - End-to-end encryption with Temporal payload codecs. * [EnvConfig](src/EnvConfig) - Load client configuration from TOML files with programmatic overrides +* [Gcp/CloudRun/OpenTelemetry](src/Gcp/CloudRun/OpenTelemetry) - Run a polling worker on a Google Cloud Run worker pool, exporting OpenTelemetry metrics and traces to a collector sidecar. * [LambdaWorker](src/LambdaWorker) - Run a Temporal Worker inside an AWS Lambda function. * [Mutex](src/Mutex) - How to implement a mutex as a workflow. Demonstrates how to avoid race conditions or parallel mutually exclusive operations on the same resource. * [NexusCancellation](src/NexusCancellation) - Demonstrates how to cancel a running Nexus operation from a caller workflow. diff --git a/nuget.config b/nuget.config index dddb33b..fc9f9a7 100644 --- a/nuget.config +++ b/nuget.config @@ -1,10 +1,5 @@ - + diff --git a/src/Gcp/CloudRun/OpenTelemetry/.gitignore b/src/Gcp/CloudRun/OpenTelemetry/.gitignore deleted file mode 100644 index f2850e0..0000000 --- a/src/Gcp/CloudRun/OpenTelemetry/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Temporary test scaffolding for the unpublished GCP Cloud Run package (remove once published). -local-packages/ -nuget.config diff --git a/src/Gcp/CloudRun/OpenTelemetry/CloudRunWorkerSample.cs b/src/Gcp/CloudRun/OpenTelemetry/CloudRunWorkerSample.cs index 502dd26..de5c3b5 100644 --- a/src/Gcp/CloudRun/OpenTelemetry/CloudRunWorkerSample.cs +++ b/src/Gcp/CloudRun/OpenTelemetry/CloudRunWorkerSample.cs @@ -2,17 +2,9 @@ namespace TemporalioSamples.Gcp.CloudRun.OpenTelemetry; using Temporalio.Worker; -/// -/// Shared worker configuration so both the entrypoint and the tests register the same -/// workflow and activities. -/// +// Shared so the entrypoint and tests register the same workflow and activities. public static class CloudRunWorkerSample { - /// - /// Register the sample workflow and activities on the given worker options. - /// - /// Worker options to configure. - /// The same options, for chaining. public static TemporalWorkerOptions ConfigureOptions(TemporalWorkerOptions options) => options. AddWorkflow(). diff --git a/src/Gcp/CloudRun/OpenTelemetry/Dockerfile b/src/Gcp/CloudRun/OpenTelemetry/Dockerfile index 4d2037b..59c32f2 100644 --- a/src/Gcp/CloudRun/OpenTelemetry/Dockerfile +++ b/src/Gcp/CloudRun/OpenTelemetry/Dockerfile @@ -1,16 +1,8 @@ # syntax=docker/dockerfile:1 -# -# Builds the Cloud Run worker image. Temporalio (with its bundled native bridge for linux) is -# restored from NuGet; the GCP Cloud Run OpenTelemetry package is restored from the local folder -# feed under this sample until it is published (see nuget.config / local-packages). No SDK-from- -# source or Rust build is needed. -# -# Build context is the samples-dotnet repo root (so the shared Directory.*.props / global.json are -# available): -# docker build -f src/Gcp/CloudRun/OpenTelemetry/Dockerfile -t . +# Build from the repo root: docker build -f src/Gcp/CloudRun/OpenTelemetry/Dockerfile -t . FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src -COPY global.json Directory.Build.props Directory.Packages.props .editorconfig ./ +COPY global.json Directory.Build.props Directory.Packages.props .editorconfig nuget.config ./ COPY src/Gcp/CloudRun/OpenTelemetry/ ./src/Gcp/CloudRun/OpenTelemetry/ RUN dotnet publish src/Gcp/CloudRun/OpenTelemetry/TemporalioSamples.Gcp.CloudRun.OpenTelemetry.csproj -c Release -o /app diff --git a/src/Gcp/CloudRun/OpenTelemetry/Program.cs b/src/Gcp/CloudRun/OpenTelemetry/Program.cs index c8a5856..03cd7df 100644 --- a/src/Gcp/CloudRun/OpenTelemetry/Program.cs +++ b/src/Gcp/CloudRun/OpenTelemetry/Program.cs @@ -6,13 +6,9 @@ using Temporalio.Worker; using TemporalioSamples.Gcp.CloudRun.OpenTelemetry; -// Build client connection options from environment configuration (TEMPORAL_ADDRESS, -// TEMPORAL_NAMESPACE, TEMPORAL_API_KEY, ...). With no API key and no TLS block this connects in -// plaintext, which is what a local dev server (reached over an ngrok TCP tunnel) needs. +// Connect from environment config (TEMPORAL_ADDRESS, TEMPORAL_NAMESPACE, TEMPORAL_API_KEY, ...). var connectOptions = ClientEnvConfig.LoadClientConnectOptions(); connectOptions.TargetHost ??= "localhost:7233"; - -// Send all Temporal logs to stdout so Cloud Run captures them in Cloud Logging. connectOptions.LoggerFactory = LoggerFactory.Create(builder => builder. AddSimpleConsole(options => options.TimestampFormat = "[HH:mm:ss] "). @@ -20,9 +16,7 @@ var taskQueue = Environment.GetEnvironmentVariable("TEMPORAL_TASK_QUEUE") ?? "cloud-run-worker"; -// The --starter mode runs a single workflow (useful for kicking off work locally against the same -// server the deployed worker polls). Applying the defaults here too propagates a trace context into -// the workflow so the deployed worker's spans join the same distributed trace. +// --starter runs a single workflow, e.g. to kick off work against the same server the worker polls. if (args.Contains("--starter")) { using var starterTelemetry = connectOptions.ApplyGoogleCloudRunOpenTelemetryDefaults(); @@ -35,9 +29,8 @@ return; } -// Apply the Google Cloud Run OpenTelemetry defaults: adds the tracing interceptor and configures a -// Temporal runtime that exports Core metrics + traces over OTLP to the local collector sidecar. The -// returned handle owns the tracer provider and is flushed on shutdown. +// Adds the tracing interceptor and a runtime exporting Core metrics + traces over OTLP to the +// collector sidecar; the returned handle owns the tracer provider. using var telemetry = connectOptions.ApplyGoogleCloudRunOpenTelemetryDefaults(); var client = await TemporalClient.ConnectAsync(connectOptions); @@ -49,7 +42,7 @@ cts.Cancel(); }; -// Cloud Run signals shutdown with SIGTERM (about 10 seconds before SIGKILL). +// Cloud Run sends SIGTERM ~10s before SIGKILL. using var sigterm = PosixSignalRegistration.Create(PosixSignal.SIGTERM, _ => cts.Cancel()); using var worker = new TemporalWorker( @@ -69,7 +62,6 @@ Console.WriteLine("Worker shutting down"); } -// Flush buffered traces within the Cloud Run shutdown grace window. Core metrics are exported -// periodically by the runtime and have no explicit flush. +// Flush traces within the shutdown grace window (Core metrics export periodically, no explicit flush). await telemetry.FlushAsync(TimeSpan.FromSeconds(2)); Console.WriteLine("Worker stopped"); diff --git a/src/Gcp/CloudRun/OpenTelemetry/README.md b/src/Gcp/CloudRun/OpenTelemetry/README.md new file mode 100644 index 0000000..cf9d3ea --- /dev/null +++ b/src/Gcp/CloudRun/OpenTelemetry/README.md @@ -0,0 +1,52 @@ +# Cloud Run OpenTelemetry Worker + +Run a continuously-polling Temporal Worker on a +[Google Cloud Run worker pool](https://cloud.google.com/run/docs/deploy-worker-pools) that exports +Core SDK metrics and traces to a +[Google-Built OpenTelemetry Collector](https://cloud.google.com/stackdriver/docs/instrumentation/opentelemetry-collector-cloud-run) +sidecar (metrics to Managed Service for Prometheus, traces to Cloud Trace) via the +`Temporalio.Extensions.Gcp.CloudRun.OpenTelemetry` extension. + +`Program.cs` calls `ApplyGoogleCloudRunOpenTelemetryDefaults()`, which adds the tracing interceptor +and an OTLP exporter aimed at the sidecar, then runs a greeting workflow and activity until SIGTERM. + +> The extension is not on nuget.org yet, so the sample restores it from the committed +> `local-packages/` feed (see `nuget.config`) until it ships. + +## Prerequisites + +- A Temporal server the worker pool can reach (`TEMPORAL_ADDRESS` / `TEMPORAL_NAMESPACE`) +- A Google Cloud project with the Cloud Run and Artifact Registry APIs enabled +- [`gcloud`](https://cloud.google.com/sdk/docs/install), authenticated with the project set +- The [Temporal CLI](https://docs.temporal.io/cli) and .NET 8 + +## Deploy + +Set the placeholders used by `worker-pool.yaml`, then build the image, store the collector config as +a secret, and deploy. Run from the repo root: + +```bash +export REGION=us-central1 WORKER_POOL=temporal-otel-worker INSTANCE_COUNT=1 +export SERVICE_ACCOUNT_EMAIL=@.iam.gserviceaccount.com +export WORKER_IMAGE=$REGION-docker.pkg.dev/$(gcloud config get-value project)/samples/cloud-run-otel +export TEMPORAL_ADDRESS= TEMPORAL_NAMESPACE= TEMPORAL_TASK_QUEUE=cloud-run-worker +export COLLECTOR_CONFIG_SECRET=otel-collector-config COLLECTOR_CONFIG_SECRET_VERSION=latest + +docker build -f src/Gcp/CloudRun/OpenTelemetry/Dockerfile -t "$WORKER_IMAGE" . && docker push "$WORKER_IMAGE" +gcloud secrets create "$COLLECTOR_CONFIG_SECRET" --data-file=src/Gcp/CloudRun/OpenTelemetry/collector-config.yaml + +envsubst < src/Gcp/CloudRun/OpenTelemetry/worker-pool.yaml > /tmp/worker-pool.yaml +gcloud run worker-pools replace /tmp/worker-pool.yaml --region "$REGION" +``` + +The service account needs the `monitoring.metricWriter`, `cloudtrace.agent`, and +`secretmanager.secretAccessor` roles. + +## Run a workflow + +```bash +temporal workflow execute --task-queue cloud-run-worker --type GreetingWorkflow --input '"Temporal"' +``` + +Metrics appear in Metrics Explorer and traces in Trace Explorer. Delete the pool with +`gcloud run worker-pools delete "$WORKER_POOL" --region "$REGION"`. diff --git a/src/Gcp/CloudRun/OpenTelemetry/collector-config.yaml b/src/Gcp/CloudRun/OpenTelemetry/collector-config.yaml index 2fa7df6..dc7f7fe 100644 --- a/src/Gcp/CloudRun/OpenTelemetry/collector-config.yaml +++ b/src/Gcp/CloudRun/OpenTelemetry/collector-config.yaml @@ -1,9 +1,4 @@ -# Google-Built OpenTelemetry Collector config for the Cloud Run worker-pool sidecar. -# metrics -> Google Managed Service for Prometheus (googlemanagedprometheus) -# traces -> Cloud Trace via the Telemetry API (OTLP), authenticated with the runtime SA (ADC) -# The worker exports OTLP/gRPC to localhost:4317; the collector detects GCP resource attributes and -# fans out. Auth uses the worker-pool service account's Application Default Credentials via the -# googleclientauth extension (no key files). +# Google-Built OpenTelemetry Collector config for the sidecar: metrics -> Managed Service for Prometheus, traces -> Cloud Trace. Auth via the worker-pool service account (ADC). receivers: otlp: protocols: @@ -25,8 +20,7 @@ processors: resourcedetection: detectors: [gcp] timeout: 10s - # Rename Temporal datapoint labels that collide with the target labels Google Managed Service for - # Prometheus injects (e.g. Temporal emits a `namespace` label). + # Rename Temporal datapoint labels that collide with the target labels Managed Service for Prometheus injects (e.g. `namespace`). transform/collision: metric_statements: - context: datapoint diff --git a/src/Gcp/CloudRun/OpenTelemetry/local-packages/Temporalio.Extensions.Gcp.CloudRun.OpenTelemetry.1.19.0.nupkg b/src/Gcp/CloudRun/OpenTelemetry/local-packages/Temporalio.Extensions.Gcp.CloudRun.OpenTelemetry.1.19.0.nupkg new file mode 100644 index 0000000000000000000000000000000000000000..36b749818d1cc720ea9fa568516e7babcf2ebf0f GIT binary patch literal 13403 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 Date: Fri, 18 Sep 2026 16:25:26 -0700 Subject: [PATCH 5/6] Drop continuously-polling wording from Cloud Run OpenTelemetry sample --- src/Gcp/CloudRun/OpenTelemetry/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Gcp/CloudRun/OpenTelemetry/README.md b/src/Gcp/CloudRun/OpenTelemetry/README.md index cf9d3ea..786088b 100644 --- a/src/Gcp/CloudRun/OpenTelemetry/README.md +++ b/src/Gcp/CloudRun/OpenTelemetry/README.md @@ -1,6 +1,6 @@ # Cloud Run OpenTelemetry Worker -Run a continuously-polling Temporal Worker on a +Run a Temporal Worker on a [Google Cloud Run worker pool](https://cloud.google.com/run/docs/deploy-worker-pools) that exports Core SDK metrics and traces to a [Google-Built OpenTelemetry Collector](https://cloud.google.com/stackdriver/docs/instrumentation/opentelemetry-collector-cloud-run) From 220d4e50cb6c791738bc6fbfa3b8e87ab5f8cf51 Mon Sep 17 00:00:00 2001 From: seanbollin Date: Fri, 18 Sep 2026 16:28:47 -0700 Subject: [PATCH 6/6] Say Temporal Worker instead of polling worker --- README.md | 2 +- src/Gcp/CloudRun/OpenTelemetry/worker-pool.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6069664..125eaaf 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Prerequisites: * [EagerWorkflowStart](src/EagerWorkflowStart) - Demonstrates usage of Eager Workflow Start to reduce latency for workflows that start with a local activity. * [Encryption](src/Encryption) - End-to-end encryption with Temporal payload codecs. * [EnvConfig](src/EnvConfig) - Load client configuration from TOML files with programmatic overrides -* [Gcp/CloudRun/OpenTelemetry](src/Gcp/CloudRun/OpenTelemetry) - Run a polling worker on a Google Cloud Run worker pool, exporting OpenTelemetry metrics and traces to a collector sidecar. +* [Gcp/CloudRun/OpenTelemetry](src/Gcp/CloudRun/OpenTelemetry) - Run a Temporal Worker on a Google Cloud Run worker pool, exporting OpenTelemetry metrics and traces to a collector sidecar. * [LambdaWorker](src/LambdaWorker) - Run a Temporal Worker inside an AWS Lambda function. * [Mutex](src/Mutex) - How to implement a mutex as a workflow. Demonstrates how to avoid race conditions or parallel mutually exclusive operations on the same resource. * [NexusCancellation](src/NexusCancellation) - Demonstrates how to cancel a running Nexus operation from a caller workflow. diff --git a/src/Gcp/CloudRun/OpenTelemetry/worker-pool.yaml b/src/Gcp/CloudRun/OpenTelemetry/worker-pool.yaml index b81cfaf..8688311 100644 --- a/src/Gcp/CloudRun/OpenTelemetry/worker-pool.yaml +++ b/src/Gcp/CloudRun/OpenTelemetry/worker-pool.yaml @@ -1,4 +1,4 @@ -# Cloud Run WorkerPool: a polling Temporal worker + a Collector sidecar. Render placeholders with `envsubst` (see README) then `gcloud run worker-pools replace`. For Temporal Cloud, add TEMPORAL_API_KEY from a Secret Manager secretKeyRef. +# Cloud Run WorkerPool: a Temporal Worker + a Collector sidecar. Render placeholders with `envsubst` (see README) then `gcloud run worker-pools replace`. For Temporal Cloud, add TEMPORAL_API_KEY from a Secret Manager secretKeyRef. apiVersion: run.googleapis.com/v1 kind: WorkerPool metadata: