Start caller Workflow from starter program
Use the Temporal Client to execute caller Workflows using `ExecuteWorkflowAsync`. Provide the Workflow method call, a workflow execution ID, and the task queue. Multiple Workflows can be started from the same starter program.
Register caller Workflow in Worker example
```csharp
async Task RunCallerWorkerAsync()
{
logger.LogInformation("Running caller worker");
using var worker = new TemporalWorker(
await ConnectClientAsync("nexus-simple-caller-namespace"),
new TemporalWorkerOptions(taskQueue: "nexus-simple-caller-sample").
AddWorkflow<EchoCallerWorkflow>().
AddWorkflow<HelloCallerWorkflow>());
try
{
await worker.ExecuteAsync(tokenSource.Token);
}
catch (OperationCanceledException)
{
logger.LogInformation("Caller worker cancelled");
}
}
```
This example shows creating a caller Worker connected to the caller Namespace with multiple caller Workflows registered.
Start caller Workflow from starter program example
```csharp
async Task ExecuteCallerWorkflowAsync()
{
logger.LogInformation("Executing caller echo workflow");
var client = await ConnectClientAsync("nexus-simple-caller-namespace");
var result1 = await client.ExecuteWorkflowAsync(
(EchoCallerWorkflow wf) => wf.RunAsync("Nexus Echo 👋"),
new(id: "nexus-simple-echo-id", taskQueue: "nexus-simple-caller-sample"));
logger.LogInformation("Workflow result: {Result}", result1);
logger.LogInformation("Executing caller hello workflow");
var result2 = await client.ExecuteWorkflowAsync(
(HelloCallerWorkflow wf) => wf.RunAsync("Temporal", IHelloService.HelloLanguage.Es),
new(id: "nexus-simple-hello-id", taskQueue: "nexus-simple-caller-sample"));
logger.LogInformation("Workflow result: {Result}", result2);
}
```
This example shows a starter program that executes two caller Workflows and logs their results.
Caller Workflow Nexus Operation example - asynchronous
```csharp
using Temporalio.Workflows;
[Workflow]
public class HelloCallerWorkflow
{
[WorkflowRun]
public async Task<string> RunAsync(string name, IHelloService.HelloLanguage language)
{
var output = await Workflow.CreateNexusWorkflowClient<IHelloService>(IHelloService.EndpointName).
ExecuteNexusOperationAsync(svc => svc.SayHello(new(name, language)));
return output.Message;
}
}
```
This example shows a caller Workflow that calls an asynchronous Nexus Operation (SayHello) with multiple input parameters and returns the output message.
Call Nexus Operation from caller Workflow
Use `Workflow.CreateNexusWorkflowClient<TService>(endpointName)` to create a Nexus client and `ExecuteNexusOperationAsync` to call a Nexus Operation from a caller Workflow. The service interface must be imported to access operation names and type information. The endpoint name should be defined as a static field in the service interface.
Register caller Workflow in Worker
Register caller Workflows in a Worker using `AddWorkflow()`. The caller Worker connects to the caller Namespace and the task queue where the Workflows are executed. Multiple caller Workflows can be registered in the same Worker.
Nexus client in caller workflow
In a caller workflow, create a Nexus client using workflow.NewNexusClient(NexusEndpoint, HelloServiceName) where NexusEndpoint is a string constant matching the endpoint name created on the server, and HelloServiceName is the service name. Call c.ExecuteOperation(ctx, operationName, input, workflow.NexusOperationOptions) to start an operation and receive a future. Use fut.Get(ctx, &result) to block until completion and retrieve the result.
Caller workflow Nexus operation execution example
c := workflow.NewNexusClient(NexusEndpoint, HelloServiceName); fut := c.ExecuteOperation(ctx, HelloOperationName, HelloInput{Name: name}, workflow.NexusOperationOptions{ ScheduleToCloseTimeout: 10 * time.Second, }); var result string; if err := fut.Get(ctx, &result); err != nil { return "", err } - This example shows creating a Nexus client, executing an operation with a timeout, and retrieving the result.
Get operation result code example
var result service.EchoOutput
err = handle.Get(context.Background(), &result)
if err != nil {
log.Fatalln("Operation failed", err)
}
log.Println("Operation result:", result.Message)
CountNexusOperations code example
resp, err := c.CountNexusOperations(context.Background(), client.CountNexusOperationsOptions{
Query: "Endpoint = 'my-nexus-endpoint'",
})
if err != nil {
log.Fatalln("Unable to count Nexus operations", err)
}
log.Println("Total Nexus operations:", resp.Count)
Temporal CLI command to execute Standalone Nexus Operation
./temporal nexus operation execute --namespace my-caller-namespace --endpoint my-nexus-endpoint --service my-hello-service --operation echo --operation-id my-echo-op --input '{"Message":"hello"}'
Temporal CLI command to get Standalone Nexus Operation result
./temporal nexus operation result --namespace my-caller-namespace --operation-id my-echo-op
ExecuteOperation API and return type
ExecuteOperation returns a NexusOperationHandle that you can use to get the result of the Operation. StartNexusOperationOptions requires ID field. ScheduleToCloseTimeout is optional and defaults to the maximum allowed by the Temporal server.
ExecuteOperation code example
nexusClient, err := c.NewNexusClient(client.NexusClientOptions{
Endpoint: "my-nexus-endpoint",
Service: "my-hello-service",
})
handle, err := nexusClient.ExecuteOperation(ctx, operationName, input, client.StartNexusOperationOptions{
ID: "unique-operation-id",
ScheduleToCloseTimeout: 10 * time.Second,
})
Getting Standalone Nexus Operation results
Use NexusOperationHandle.Get() to block until the Operation completes and retrieve its result. This works for both synchronous and asynchronous (Workflow-backed) Operations. If the Operation completed successfully, the result is deserialized into the provided pointer. If the Operation failed, the failure is returned as an error.
ListNexusOperations code example
resp, err := c.ListNexusOperations(context.Background(), client.ListNexusOperationsOptions{
Query: "Endpoint = 'my-nexus-endpoint'",
})
if err != nil {
log.Fatalln("Unable to list Nexus operations", err)
}
for metadata, err := range resp.Results {
if err != nil {
log.Fatalln("Error iterating operations", err)
}
log.Printf("OperationID: %s, Operation: %s, Status: %v\n",
metadata.OperationID, metadata.Operation, metadata.Status)
}
Example: start caller Workflow
c, err := client.Dial(clientOptions)
if err != nil {
log.Fatalln("Unable to create client", err)
}
defer c.Close()
ctx := context.Background()
workflowOptions := client.StartWorkflowOptions{
ID: "nexus_hello_caller_workflow_" + time.Now().Format("20060102150405"),
TaskQueue: caller.TaskQueue,
}
wr, err := c.ExecuteWorkflow(ctx, workflowOptions, caller.EchoCallerWorkflow, "Nexus Echo 👋")
if err != nil {
log.Fatalln("Unable to execute workflow", err)
}
var result string
err = wr.Get(context.Background(), &result)
if err != nil {
log.Fatalln("Unable get workflow result", err)
}
log.Println("Workflow result:", result)
Example: register caller Workflow in Worker
w := worker.New(c, caller.TaskQueue, worker.Options{})
w.RegisterWorkflow(caller.EchoCallerWorkflow)
w.RegisterWorkflow(caller.HelloCallerWorkflow)
err = w.Run(worker.InterruptCh())
Start caller Workflow using client
Create a Temporal client, then use client.ExecuteWorkflow with StartWorkflowOptions to start the caller Workflow. Use client.ExecuteWorkflow().Get() to wait for the workflow result.
Register caller Workflow in a Worker
After developing the caller Workflow, register it with a Worker using w.RegisterWorkflow(). The caller Workflow needs to be in a separate Worker instance from the handler Workflow, typically in a different Namespace.
Create Nexus client in caller Workflow
Import the Service API package with service and operation names and input/output types. Create a Nexus client using workflow.NewNexusClient(endpointName, serviceName), then call ExecuteOperation with the operation name, input, and options. The future returned by ExecuteOperation can be used to wait for the result with Get().
Example: caller Workflow executing Nexus Operation
func EchoCallerWorkflow(ctx workflow.Context, message string) (string, error) {
c := workflow.NewNexusClient(endpointName, service.HelloServiceName)
fut := c.ExecuteOperation(ctx, service.EchoOperationName, service.EchoInput{Message: message}, workflow.NexusOperationOptions{})
var res service.EchoOutput
if err := fut.Get(ctx, &res); err != nil {
return "", err
}
return res.Message, nil
}
Example: wait for async Nexus Operation to start
fut := c.ExecuteOperation(ctx, service.HelloOperationName, service.HelloInput{Name: name, Language: language}, workflow.NexusOperationOptions{})
var res service.HelloOutput
var exec workflow.NexusOperationExecution
if err := fut.GetNexusOperationExecution().Get(ctx, &exec); err != nil {
return "", err
}
if err := fut.Get(ctx, &res); err != nil {
return "", err
}
return res.Message, nil
Start async Nexus Operation and wait for execution
Use Workflow.startNexusOperation to start an asynchronous Nexus Operation and get a NexusOperationHandle. Call handle.getExecution().get() to optionally wait for the operation to be started (NexusOperationExecution will contain the operation token). Call handle.getResult().get() to wait for the operation result.
Example: Caller Workflow invoking Nexus Operation
package helloworkflow;
import io.temporal.workflow.NexusOperationOptions;
import io.temporal.workflow.NexusServiceOptions;
import io.temporal.workflow.Workflow;
import java.time.Duration;
public class NexusCallerWorkflowImpl implements NexusCallerWorkflow {
private final SayHelloNexusService nexusService = Workflow.newNexusServiceStub(
SayHelloNexusService.class,
NexusServiceOptions.newBuilder()
.setOperationOptions(
NexusOperationOptions.newBuilder()
.setScheduleToCloseTimeout(Duration.ofSeconds(10))
.build())
.build()
);
@Override
public String greetThroughNexus(String name) {
return nexusService.sayHello(name);
}
}
This example shows a Workflow creating a Nexus Service stub with a 10-second timeout and invoking a Nexus Operation by calling nexusService.sayHello(name).
Create Nexus Service stub in caller Workflow using Workflow.newNexusServiceStub
The caller Workflow creates a Nexus Service client using Workflow.newNexusServiceStub(SayHelloNexusService.class, NexusServiceOptions). The NexusServiceOptions builder can configure operation options such as setScheduleToCloseTimeout(Duration). The returned stub allows direct invocation of Nexus Operations as if calling a local method. The caller Workflow only depends on the Service contract interface, keeping caller and handler decoupled for separate Namespaces or teams.
NexusServiceOptions builder configuration for caller Workflow
NexusServiceOptions.newBuilder() configures the Nexus Service stub. Use setOperationOptions(NexusOperationOptions) to set default options for all Operations. NexusOperationOptions.newBuilder() supports setScheduleToCloseTimeout(Duration) to specify operation timeout duration.
Call Nexus Operation from caller Workflow
To execute a Nexus Operation from a caller Workflow, first create a Nexus client and then call the operation:
```python
from temporalio import workflow
with workflow.unsafe.imports_passed_through():
from hello_nexus.service import MyInput, MyNexusService, MyOutput
@workflow.defn
class CallerWorkflow:
@workflow.run
async def run(self, name: str) -> tuple[MyOutput, MyOutput]:
nexus_client = workflow.create_nexus_client(
service=MyNexusService,
endpoint=NEXUS_ENDPOINT,
)
# Start the nexus operation and wait for the result in one go
wf_result = await nexus_client.execute_operation(
MyNexusService.my_workflow_run_operation,
MyInput(name),
)
# Alternatively, use start_operation to obtain the operation handle
sync_operation_handle = await nexus_client.start_operation(
MyNexusService.my_sync_operation,
MyInput(name),
)
sync_result = await sync_operation_handle
return sync_result, wf_result
```
Complete Python Nexus quickstart example - caller workflow
To define a caller Workflow in a file called caller.py:
```python
from datetime import timedelta
from temporalio import workflow
from service import MyInput, SayHelloNexusService
NEXUS_ENDPOINT = "my-nexus-endpoint-name"
@workflow.defn
class CallerWorkflow:
@workflow.run
async def run(self, name: str) -> str:
nexus_client = workflow.create_nexus_client(
service=SayHelloNexusService,
endpoint=NEXUS_ENDPOINT,
)
return await nexus_client.execute_operation(
SayHelloNexusService.say_hello,
MyInput(name=name),
schedule_to_close_timeout=timedelta(seconds=10),
)
```
Execute Nexus Operation in caller workflow with execute_operation
In a caller Workflow, call nexus_client.execute_operation(Service.operation_name, input_object, schedule_to_close_timeout=timedelta(...)) to invoke the operation and wait for the result. This starts the operation and blocks until completion or timeout.
Complete Python Nexus quickstart example - caller starter
To run the caller Workflow in a file called caller_starter.py:
```python
import asyncio
import uuid
from temporalio.client import Client
from temporalio.worker import Worker
from caller import CallerWorkflow
CALLER_TASK_QUEUE = "my-caller-task-queue"
NAMESPACE = "my-caller-namespace"
async def main():
client = await Client.connect("localhost:7233", namespace=NAMESPACE)
async with Worker(
client,
task_queue=CALLER_TASK_QUEUE,
workflows=[CallerWorkflow],
):
result = await client.execute_workflow(
CallerWorkflow.run,
"Temporal",
id=f"caller-workflow-{uuid.uuid4()}",
task_queue=CALLER_TASK_QUEUE,
)
print("Workflow result:", result)
if __name__ == "__main__":
asyncio.run(main())
```
NexusOperationOptions parameters
NexusOperationOptions accepts the following parameters: endpoint (string, required, the Nexus endpoint name), service (string, required, the service name), operation (string, required, the operation name), input (Payload, optional, the input payload), start_to_close_timeout (Duration, optional, how long the operation can run).
Call Nexus Operation from workflow
Start a Nexus operation from a Workflow using `ctx.start_nexus_operation()` with NexusOperationOptions. The method returns a result that can be awaited.
Nexus operation example in Rust
This example shows a workflow that calls a Nexus operation with endpoint 'my-endpoint', service 'my-service', operation 'my-operation', a payload containing a name as bytes, and a 10-second start_to_close_timeout:
```rust
use std::time::Duration;
use temporalio_common::protos::{coresdk::nexus, temporal::api::{common::v1::Payload,}};
use temporalio_macros::{workflow, workflow_methods};
use temporalio_sdk::{NexusOperationOptions, WorkflowContext, WorkflowContextView, WorkflowResult};
#[workflow]
pub struct GreetingWorkflow {
pub name: String,
}
#[workflow_methods]
impl GreetingWorkflow {
#[init]
fn new(_ctx: &WorkflowContextView, name: String) -> Self {
Self { name }
}
#[run]
pub async fn run(ctx: &mut WorkflowContext<Self>) -> WorkflowResult<String> {
let name = ctx.state(|s| s.name.clone());
let nexus_started = ctx.start_nexus_operation(NexusOperationOptions {
endpoint: "my-endpoint".to_string(),
service: "my-service".to_string(),
operation: "my-operation".to_string(),
input: Some(Payload {
data: name.as_bytes().to_vec(),
..Default::default()
}),
start_to_close_timeout: Some(Duration::from_secs(10)),
..Default::default()
}).await;
let nexus_result = nexus_started.unwrap();
println!("Nexus result: {:?}", nexus_result);
Ok(format!("nexus result: {:?}", nexus_result))
}
}
```
executeOperation() method for invoking Nexus Operations
The nexusClient.executeOperation() method invokes a Nexus Operation. It takes three parameters: the operation name (string), the input object, and an options object. The options object can include scheduleToCloseTimeout to specify how long the operation can take before timing out.
Create Nexus Service client in caller Workflow
To execute a Nexus Operation from a Workflow, use `@temporalio/workflow`'s `createNexusServiceClient()` to create a client: `const nexusClient = wf.createNexusServiceClient({ service: helloService, endpoint: HELLO_SERVICE_ENDPOINT })`. Then call `nexusClient.executeOperation(operationName, input, options)` to execute the operation. Provide the Nexus Endpoint name that was previously registered.