Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/NexusStandaloneOperations/IHelloService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace TemporalioSamples.NexusStandaloneOperations;
[NexusService]
public interface IHelloService
{
static readonly string EndpointName = "nexus-standalone-operations-endpoint";
static readonly string EndpointName = "my-nexus-endpoint";

[NexusOperation]
EchoOutput Echo(EchoInput input);
Expand Down
2 changes: 1 addition & 1 deletion src/NexusStandaloneOperations/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using TemporalioSamples.NexusStandaloneOperations;
using TemporalioSamples.NexusStandaloneOperations.Handler;

const string taskQueue = "nexus-standalone-operations";
const string taskQueue = "nexus-handler-queue";

using var loggerFactory = LoggerFactory.Create(builder =>
builder.
Expand Down
101 changes: 68 additions & 33 deletions src/NexusStandaloneOperations/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,48 @@ from client code without wrapping them in a Workflow). It shows both sync and as
(workflow-backed) operations, and how to use the `ListNexusOperationsAsync` and
`CountNexusOperationsAsync` APIs.

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 (`ClientEnvConfig.LoadClientConnectOptions()`), which reads `TEMPORAL_NAMESPACE`,
`TEMPORAL_ADDRESS`, etc. from the environment (and optionally profiles from `temporal.toml`).

> [!NOTE]
> 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.

### Steps to run this sample
> https://github.com/temporalio/cli/releases/tag/v1.7.4-standalone-nexus-operations.

1. 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.)
## Run locally against a dev server

Start the dev server with the dynamic config flags required for standalone Nexus operations:
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 \
--dynamic-config-value "nexusoperation.enableStandalone=true" \
--dynamic-config-value "history.enableChasmCallbacks=true"
```

You should see a line about the CLI, Server and UI versions, and one line each for the Server
URL, UI URL and Metrics endpoint. It should look something like this:

./temporal server start-dev \
--namespace my-caller-namespace \
--namespace my-handler-namespace
```
Temporal CLI 1.7.3-standalone-nexus-operations (Server 1.32.0-158.0, UI 2.52.0)

Temporal Server: localhost:7233
Temporal UI: http://localhost:8233
Temporal Metrics: http://localhost:61951/metrics
```

2. Create a Nexus endpoint that routes to the worker's task queue. In a second terminal, run:
2. Create a Nexus endpoint that routes to the handler namespace and the worker's task queue:

```bash
temporal operator nexus endpoint create \
--name nexus-standalone-operations-endpoint \
--target-namespace default \
--target-task-queue nexus-standalone-operations
./temporal operator nexus endpoint create \
--name my-nexus-endpoint \
--target-namespace my-handler-namespace \
--target-task-queue nexus-handler-queue
```

3. Then run the following command from this directory to start the worker. The worker is a
blocking process that runs until it receives a SIGINT (Ctrl + C) command.
3. In a second terminal, start the worker in the handler namespace:

```bash
dotnet run worker
TEMPORAL_NAMESPACE=my-handler-namespace dotnet run worker
```

You should see a log line that the worker has started on the `nexus-standalone-operations` task
queue.
You should see a log line that the worker has started on the `nexus-handler-queue` task queue.

4. In a third terminal, run the following command from this directory to start the example:
4. In a third terminal, run the starter in the caller namespace:

```bash
dotnet run starter
TEMPORAL_NAMESPACE=my-caller-namespace dotnet run starter
```

You should see something similar to the following output:
Expand All @@ -71,5 +62,49 @@ from client code without wrapping them in a Workflow). It shows both sync and as
[09:00:30] Total Nexus operations: 2
```

If you run the starter multiple times, you should see additional `ListNexusOperations` results,
as more operations are run. The same goes for the number from `CountNexusOperations`.
If you run the starter multiple times, additional entries will appear in the `ListNexusOperations`
output and the `CountNexusOperations` total will grow.

## Run against Temporal Cloud

1. Create two namespaces in Temporal Cloud (for example `my-caller-namespace.<account>` and
`my-handler-namespace.<account>`) 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.<account>`
- Target task queue: `nexus-handler-queue`
- Allowed caller namespaces: include `my-caller-namespace.<account>` (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 = "<region>.<cloud>.api.temporal.io:7233"
namespace = "my-handler-namespace.<account>"
api_key = "<your-api-key>"

[profile.caller]
address = "<region>.<cloud>.api.temporal.io:7233"
namespace = "my-caller-namespace.<account>"
api_key = "<your-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 from this directory, selecting the appropriate profile in each:

```bash
# terminal 1 (worker, handler namespace)
TEMPORAL_PROFILE=handler dotnet run worker
```

```bash
# terminal 2 (starter, caller namespace)
TEMPORAL_PROFILE=caller dotnet run starter
```
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,7 @@ public async Task RunAsync_StandaloneOperations_Succeeds()
{
DevServerOptions = new()
{
DownloadVersion = "v1.7.3-standalone-nexus-operations",
ExtraArgs =
[
"--dynamic-config-value",
"nexusoperation.enableStandalone=true",
"--dynamic-config-value",
"history.enableChasmCallbacks=true",
],
DownloadVersion = "v1.7.4-standalone-nexus-operations",
},
});

Expand Down
Loading