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
13 changes: 10 additions & 3 deletions src/NexusSimple/Caller/HelloCallerWorkflow.workflow.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace TemporalioSamples.NexusSimple.Caller;

using Microsoft.Extensions.Logging;
using Temporalio.Workflows;

[Workflow]
Expand All @@ -8,8 +9,14 @@ public class HelloCallerWorkflow
[WorkflowRun]
public async Task<string> RunAsync(string name, IHelloService.HelloLanguage language)
{
var output = await Workflow.CreateNexusWorkflowClient<IHelloService>(NexusEndpoints.HelloService).
ExecuteNexusOperationAsync(svc => svc.SayHello(new(name, language)));
var client = Workflow.CreateNexusWorkflowClient<IHelloService>(NexusEndpoints.HelloService);
var handle = await client.StartNexusOperationAsync(svc => svc.SayHello(new(name, language)));

Workflow.Logger.LogInformation(
"Async SayHello operation started; waiting for the workflow-backed result");
var output = await handle.GetResultAsync();
Workflow.Logger.LogInformation("Async SayHello operation completed");

return output.Message;
}
}
}
13 changes: 10 additions & 3 deletions src/NexusSimple/Handler/HelloHandlerWorkflow.workflow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@ namespace TemporalioSamples.NexusSimple.Handler;
public class HelloHandlerWorkflow
{
[WorkflowRun]
public async Task<IHelloService.HelloOutput> RunAsync(IHelloService.HelloInput input) =>
input.Language switch
public async Task<IHelloService.HelloOutput> RunAsync(IHelloService.HelloInput input)
{
// This durable timer intentionally exceeds the 10-second Nexus request
// deadline in the runnable sample. The workflow-backed operation can continue after its
// start request returns an operation token.
await Workflow.DelayAsync(TimeSpan.FromSeconds(15));

return input.Language switch
{
IHelloService.HelloLanguage.En => new($"Hello {input.Name} 👋"),
IHelloService.HelloLanguage.Fr => new($"Bonjour {input.Name} 👋"),
Expand All @@ -18,4 +24,5 @@ public class HelloHandlerWorkflow
_ => throw new ApplicationFailureException(
$"Unsupported language: {input.Language}", errorType: "UNSUPPORTED_LANGUAGE"),
};
}
}
}
24 changes: 21 additions & 3 deletions src/NexusSimple/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
# Nexus Simple

This sample demonstrates how to use Temporal for authoring a Nexus service and call it from a workflow.
This sample demonstrates how to author a Nexus service and call it from a Workflow. It intentionally
contrasts synchronous and asynchronous Nexus operations:

### Instructions
* `Echo` uses `OperationHandler.Sync` because it is a short, bounded, in-memory operation with no
external calls or side effects.
* `SayHello` is backed by a Workflow that waits on a durable 15-second timer before returning. The
delay intentionally exceeds the 10-second synchronous Nexus request deadline.

Use `OperationHandler.Sync` only for highly reliable, low-latency, bounded operations that complete
well within that short request window. Use an asynchronous operation when latency or
availability is uncertain, the work might exceed the handler deadline, or execution depends on a potentially
unreliable service or database.

An asynchronous handler must still initiate or attach to the underlying work and return an operation
token within the request deadline. The work can continue afterward, and the caller retrieves its
eventual result through the operation handle. In this sample, that work is a Workflow.

## Instructions

To run, first see [README.md](../../README.md) for prerequisites such as starting the Temporal server.

Expand Down Expand Up @@ -35,4 +50,7 @@ In a third terminal, run the caller workflow:

```
dotnet run caller-workflow
```
```

The Echo result returns inline. For SayHello, the caller worker logs that the asynchronous operation
started, waits approximately 15 seconds, and then logs its completion.
18 changes: 18 additions & 0 deletions tests/NexusSimple/CallerWorkflowTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,22 @@ await callerWorker.ExecuteAsync(async () =>
});
});
}

[Fact]
public async Task RunAsync_HelloHandlerWorkflow_DurableDelayCompletes()
{
await using var env = await Temporalio.Testing.WorkflowEnvironment.StartTimeSkippingAsync();
using var worker = new TemporalWorker(
env.Client,
new TemporalWorkerOptions($"tq-{Guid.NewGuid()}").
AddWorkflow<HelloHandlerWorkflow>());
await worker.ExecuteAsync(async () =>
{
var result = await env.Client.ExecuteWorkflowAsync(
(HelloHandlerWorkflow wf) =>
wf.RunAsync(new("some-name", IHelloService.HelloLanguage.Fr)),
new(id: $"wf-{Guid.NewGuid()}", taskQueue: worker.Options.TaskQueue!));
Assert.Equal("Bonjour some-name 👋", result.Message);
});
}
}
Loading