Skip to content

Generic Temporal Nexus Operation Handler#690

Open
Quinn-With-Two-Ns wants to merge 7 commits into
temporalio:mainfrom
Quinn-With-Two-Ns:nexus-generic-handler
Open

Generic Temporal Nexus Operation Handler#690
Quinn-With-Two-Ns wants to merge 7 commits into
temporalio:mainfrom
Quinn-With-Two-Ns:nexus-generic-handler

Conversation

@Quinn-With-Two-Ns
Copy link
Copy Markdown
Contributor

@Quinn-With-Two-Ns Quinn-With-Two-Ns commented May 13, 2026

What was changed

Added a generic Nexus operation handler that consolidates the common pattern of "either return a synchronous
result or start a workflow as an async operation."

Why?

The existing WorkflowRun / SyncOperation split forces users to pick the operation shape up front, which is awkward when:

  • The start handler decides at runtime whether to respond sync or async.
  • The handler needs access to the Temporal client.
  • The user wants a custom cancel implementation (e.g. terminate instead of cancel).
  • Difficult to extend as we add new operations

The new TemporalOperation unifies these cases behind one API and makes the common path much shorter.

Checklist

  1. Closes

  2. How was this tested:

  1. Any docs updates needed?

Note

Medium Risk
Touches experimental Nexus start/cancel and callback/token paths shared with existing workflow-run handlers; behavior is well covered by new tests but affects cross-service operation semantics.

Overview
Introduces TemporalNexusOperationHandler.FromHandleFactory, a single Nexus handler path where the start delegate returns TemporalOperationResult<TResult>—either an immediate value or an async workflow-run token—instead of choosing up front between workflow-run and sync handler shapes.

Handlers receive ITemporalNexusClient / TemporalNexusClient to start workflows (with links, callbacks, request ID, and Nexus-Operation-Token header wiring) or use TemporalClient for sync work like signals. Workflow-start plumbing is centralized in NexusWorkflowStartHelper; WorkflowRunOperationContext now delegates to it. NexusWorkflowRunHandle gains ParseToken, typed OperationToken, and cancel routing by token type with overridable CancelWorkflowRunAsync.

Unit and worker integration tests cover tokens, sync/async results, cancel behavior, links, conflict policy, and no-input overloads.

Reviewed by Cursor Bugbot for commit ab83e06. Bugbot is set up for automated code reviews on this repo. Configure here.

@Quinn-With-Two-Ns Quinn-With-Two-Ns changed the title Nexus generic handler Generic Temporal Nexus Operation Handler May 13, 2026
@Quinn-With-Two-Ns Quinn-With-Two-Ns marked this pull request as ready for review May 13, 2026 23:46
@Quinn-With-Two-Ns Quinn-With-Two-Ns requested a review from a team as a code owner May 13, 2026 23:46
Copy link
Copy Markdown
Contributor

@jmaeagle99 jmaeagle99 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still reviewing but wanted to leave my initial comments.

Comment thread src/Temporalio/Nexus/TemporalNexusOperationHandler.cs Outdated
Comment thread src/Temporalio/Nexus/NexusWorkflowStartHelper.cs
Comment thread src/Temporalio/Nexus/TemporalNexusClient.cs Outdated
/// <para>WARNING: Nexus support is experimental.</para>
/// <para>This class supports inheritance to customize cancel behavior. Override
/// <see cref="CancelWorkflowRunAsync"/> to change how workflow-run cancellations are handled.
/// The <see cref="StartAsync"/> and <see cref="CancelAsync"/> methods should not be
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These methods cannot be overridden because they are not virtual. I would drop this comment.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is some specific concern that derivations of the class will shadow these methods (and callers are not directly invoking these methods via the TemporalNexusOperationHandler class itself), then make them explicit interface implementations e.g. async Task<OperationStartResult<TResult>> IOperationHandler<TInput, TResult>.StartAsync(...)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to keep it to doc comments, I would suggest adding these to each of the methods instead. They should compose with the inheritdoc, especially since the interface methods do not use <remarks>.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah okay I think I was a bit confused about dotnets behaviour if a user made a subclass

Comment thread src/Temporalio/Nexus/TemporalNexusClient.cs Outdated
Comment thread src/Temporalio/Nexus/TemporalOperationResult.cs Outdated
Comment thread src/Temporalio/Nexus/TemporalOperationResult.cs Outdated
/// Gets the synchronous result value. Only meaningful when <see cref="IsSyncResult"/> is
/// true.
/// </summary>
internal TResult? SyncValue { get; }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than these be auto-generated properties, should we stored them in backing fields and have the properties throw an exception if IsSyncResult is not the expected state?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure can do

/// <param name="workflowId">The workflow ID extracted from the operation token.</param>
/// <returns>Task for cancel completion.</returns>
protected virtual Task CancelWorkflowRunAsync(
OperationCancelContext context, string workflowId) =>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The context parameter is not used at all in this default implementation. Is this desired? How does user cancellation flow into the cancel gesture?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are run by the worker so users don't cancel these methods and the server doesn't have a way cancel these method either. It is assumed they are fast (<10s)

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 9eb951c. Configure here.

Comment thread tests/Temporalio.Tests/Nexus/NexusWorkflowStartHelperTests.cs Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants