From 31e92f84e0a10292fd78d1575e708d6d70d6b0bc Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Mon, 13 Jul 2026 14:06:37 -0700 Subject: [PATCH 1/3] Improve SANO Sample --- nexus_standalone_operations/README.md | 100 ++++++++++++++++++------- nexus_standalone_operations/starter.py | 2 +- nexus_standalone_operations/worker.py | 2 +- tests/conftest.py | 2 +- 4 files changed, 77 insertions(+), 29 deletions(-) diff --git a/nexus_standalone_operations/README.md b/nexus_standalone_operations/README.md index ddddadf45..d511d10c4 100644 --- a/nexus_standalone_operations/README.md +++ b/nexus_standalone_operations/README.md @@ -2,12 +2,17 @@ This sample demonstrates how to execute Nexus operations directly from client co without wrapping them in a workflow. It shows both synchronous and asynchronous (workflow-backed) operations, plus listing and counting operations. +The starter and worker connect to two different namespaces (a "caller" namespace and a "handler" +namespace) — this mirrors how Nexus is typically used to cross namespace boundaries. The client is +configured via the SDK's [environment configuration](https://docs.temporal.io/develop/environment-configuration) +support (`ClientConfig.load_client_connect_config()`), which reads `TEMPORAL_NAMESPACE`, +`TEMPORAL_ADDRESS`, etc. from the environment (and optionally profiles from `temporal.toml`). ### Temporal Python SDK support for Standalone Nexus Operations is at [Pre-release](https://docs.temporal.io/evaluate/development-production-features/release-stages#pre-release). All APIs are experimental and may be subject to backwards-incompatible changes. -Standalone Nexus operations require a server version that supports this feature. Use the dev server build at https://github.com/temporalio/cli/releases/tag/v1.7.3-standalone-nexus-operations. +Standalone Nexus operations require a server version that supports this feature. Use the dev server build at https://github.com/temporalio/cli/releases/tag/v1.7.4-standalone-nexus-operations. ### Sample directory structure @@ -16,38 +21,37 @@ Standalone Nexus operations require a server version that supports this feature. - [worker.py](./worker.py) - Temporal worker that hosts the Nexus service - [starter.py](./starter.py) - Client that executes standalone Nexus operations +## Run locally against a dev server -### Instructions +1. Start the [Temporal dev server build that supports standalone Nexus operations](https://docs.temporal.io/standalone-nexus-operation#temporal-cli-support) + with the required namespaces pre-created (this command is blocking; run it in its own terminal): -Run the [Temporal dev server build that supports standalone Nexus operations](https://github.com/temporalio/cli/releases/tag/v1.7.3-standalone-nexus-operations). -(If you are going to run locally, you will want to start it in another terminal; this command is blocking and runs until it receives a SIGINT (Ctrl + C) command.) + ```bash + temporal server start-dev \ + --namespace my-caller-namespace \ + --namespace my-handler-namespace + ``` -Start a Temporal dev server with the dynamic config flags required for standalone Nexus operations: +2. Create a Nexus endpoint that routes to the handler namespace and the worker's task queue: -```bash -temporal server start-dev \ - --dynamic-config-value "nexusoperation.enableStandalone=true" \ - --dynamic-config-value "history.enableChasmCallbacks=true" -``` + ```bash + temporal operator nexus endpoint create \ + --name my-nexus-endpoint \ + --target-namespace my-handler-namespace \ + --target-task-queue nexus-handler-queue + ``` -Create the Nexus endpoint: +3. In a second terminal, start the worker in the handler namespace: -``` -temporal operator nexus endpoint create \ - --name nexus-standalone-operations-endpoint \ - --target-namespace default \ - --target-task-queue nexus-standalone-operations -``` + ```bash + TEMPORAL_NAMESPACE=my-handler-namespace uv run nexus_standalone_operations/worker.py + ``` -In one terminal, start the worker: -``` -uv run nexus_standalone_operations/worker.py -``` +4. In a third terminal, run the starter in the caller namespace: -In another terminal, run the starter: -``` -uv run nexus_standalone_operations/starter.py -``` + ```bash + TEMPORAL_NAMESPACE=my-caller-namespace uv run nexus_standalone_operations/starter.py + ``` ### Expected output @@ -66,4 +70,48 @@ Total Nexus operations: 2 ``` If you run the starter code multiple times, you should see additional operations in the listing results, as more operations are run. -The same goes for the total number of operations. \ No newline at end of file +The same goes for the total number of operations. + +## Run against Temporal Cloud + +1. Create two namespaces in Temporal Cloud (for example `my-caller-namespace.` and + `my-handler-namespace.`) and generate an API key (or mTLS cert) that can access both. + +2. Create a Nexus endpoint that targets the handler namespace and the worker's task queue. See the + Temporal Cloud instructions at https://docs.temporal.io/nexus/registry#create-a-nexus-endpoint. + Use: + - Endpoint name: `my-nexus-endpoint` + - Target namespace: `my-handler-namespace.` + - Target task queue: `nexus-handler-queue` + - Allowed caller namespaces: include `my-caller-namespace.` (endpoints reject callers + that are not on this list) + +3. Add two profiles to your [environment configuration file](https://docs.temporal.io/develop/environment-configuration), + one per namespace. Using API keys: + + ```toml + [profile.handler] + address = "..api.temporal.io:7233" + namespace = "my-handler-namespace." + api_key = "" + + [profile.caller] + address = "..api.temporal.io:7233" + namespace = "my-caller-namespace." + api_key = "" + ``` + + For mTLS instead of API keys, set `tls.client_cert_path` and `tls.client_key_path` on each profile + (see the [docs](https://docs.temporal.io/develop/environment-configuration) for the full schema). + +4. Run the worker and starter in separate terminals, selecting the appropriate profile in each: + + ```bash + # terminal 1 (worker, handler namespace) + TEMPORAL_PROFILE=handler uv run nexus_standalone_operations/worker.py + ``` + + ```bash + # terminal 2 (starter, caller namespace) + TEMPORAL_PROFILE=caller uv run nexus_standalone_operations/starter.py + ``` diff --git a/nexus_standalone_operations/starter.py b/nexus_standalone_operations/starter.py index 8bb235b2d..df001cab7 100644 --- a/nexus_standalone_operations/starter.py +++ b/nexus_standalone_operations/starter.py @@ -19,7 +19,7 @@ MyNexusService, ) -ENDPOINT_NAME = "nexus-standalone-operations-endpoint" +ENDPOINT_NAME = "my-nexus-endpoint" async def main() -> None: diff --git a/nexus_standalone_operations/worker.py b/nexus_standalone_operations/worker.py index 0de4ac3b1..2adcbdd90 100644 --- a/nexus_standalone_operations/worker.py +++ b/nexus_standalone_operations/worker.py @@ -11,7 +11,7 @@ interrupt_event = asyncio.Event() -TASK_QUEUE = "nexus-standalone-operations" +TASK_QUEUE = "nexus-handler-queue" async def main() -> None: diff --git a/tests/conftest.py b/tests/conftest.py index 8009ac6b9..e0abe4646 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -42,7 +42,7 @@ async def env(request) -> AsyncGenerator[WorkflowEnvironment, None]: env_type = request.config.getoption("--workflow-environment") if env_type == "local": env = await WorkflowEnvironment.start_local( - dev_server_download_version="v1.7.3-standalone-nexus-operations", + dev_server_download_version="v1.7.4-standalone-nexus-operations", dev_server_extra_args=[ "--dynamic-config-value", "frontend.enableExecuteMultiOperation=true", From 39a3e946645c4789f23549abf0004cbd6c3aff8c Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Mon, 13 Jul 2026 14:07:27 -0700 Subject: [PATCH 2/3] Remove extra dev server args --- tests/conftest.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index e0abe4646..b857e0d96 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -43,16 +43,6 @@ async def env(request) -> AsyncGenerator[WorkflowEnvironment, None]: if env_type == "local": env = await WorkflowEnvironment.start_local( dev_server_download_version="v1.7.4-standalone-nexus-operations", - dev_server_extra_args=[ - "--dynamic-config-value", - "frontend.enableExecuteMultiOperation=true", - "--dynamic-config-value", - "system.enableEagerWorkflowStart=true", - "--dynamic-config-value", - "nexusoperation.enableStandalone=true", - "--dynamic-config-value", - "history.enableChasmCallbacks=true", - ], ) elif env_type == "time-skipping": env = await WorkflowEnvironment.start_time_skipping() From 55367e0f8c3f21880dd8492ba685481cde8925b1 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Mon, 13 Jul 2026 14:29:00 -0700 Subject: [PATCH 3/3] fixup readme --- nexus_standalone_operations/README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/nexus_standalone_operations/README.md b/nexus_standalone_operations/README.md index d511d10c4..63a04b5ac 100644 --- a/nexus_standalone_operations/README.md +++ b/nexus_standalone_operations/README.md @@ -23,11 +23,10 @@ Standalone Nexus operations require a server version that supports this feature. ## Run locally against a dev server -1. Start the [Temporal dev server build that supports standalone Nexus operations](https://docs.temporal.io/standalone-nexus-operation#temporal-cli-support) - with the required namespaces pre-created (this command is blocking; run it in its own terminal): +1. Start the [Temporal dev server build that supports standalone Nexus operations](https://docs.temporal.io/standalone-nexus-operation#temporal-cli-support) with the required namespaces pre-created: ```bash - temporal server start-dev \ + ./temporal server start-dev \ --namespace my-caller-namespace \ --namespace my-handler-namespace ``` @@ -35,7 +34,7 @@ Standalone Nexus operations require a server version that supports this feature. 2. Create a Nexus endpoint that routes to the handler namespace and the worker's task queue: ```bash - temporal operator nexus endpoint create \ + ./temporal operator nexus endpoint create \ --name my-nexus-endpoint \ --target-namespace my-handler-namespace \ --target-task-queue nexus-handler-queue