Skip to content

Add support for Stand Alone Nexus Operations#2280

Merged
Quinn-With-Two-Ns merged 12 commits into
temporalio:mainfrom
Quinn-With-Two-Ns:NEXUS-289
May 19, 2026
Merged

Add support for Stand Alone Nexus Operations#2280
Quinn-With-Two-Ns merged 12 commits into
temporalio:mainfrom
Quinn-With-Two-Ns:NEXUS-289

Conversation

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

@Quinn-With-Two-Ns Quinn-With-Two-Ns commented Apr 8, 2026

Add standalone Nexus operation support

Adds the ability to start, poll, describe, cancel, terminate, list, and count Nexus operations directly from the
client, outside of workflow context. This mirrors the standalone activity pattern and is based on the API we already reviewed the cross SDK design for.

API

  • client.NewNexusClient(options) — creates a NexusClient bound to an endpoint+service
  • NexusClient.ExecuteOperation(ctx, operation, input, options) — starts an operation and returns a handle
  • NexusOperationHandle.GetID() / GetRunID() / Get() / Describe() / Cancel() / Terminate() — handle operations
  • client.GetNexusOperationHandle(options) — creates a handle to an existing operation (no network call)
  • client.ListNexusOperations(ctx, options) — lists operations via visibility query
  • client.CountNexusOperations(ctx, options) — counts operations via visibility query

Interceptor support

Adds 6 methods to ClientOutboundInterceptor: ExecuteNexusOperation, GetNexusOperationHandle, CancelNexusOperation,
TerminateNexusOperation, DescribeNexusOperation, PollNexusOperationResult. List and Count bypass the interceptor,
consistent with standalone activities.

Testing

  • Unit tests for interceptor header propagation, client validation, and operation name resolution
  • Integration tests covering execute+get, describe, get handle, cancel, terminate, list, count, and validation

Note

Medium Risk
Adds new experimental client APIs and interceptor hooks for starting/polling/canceling Nexus operations, which touches core client surface area and gRPC request handling. Risk is mitigated by new unit/integration coverage but may impact compatibility for custom interceptors/mocks.

Overview
Adds experimental standalone Nexus operation support to the public client API, including NewNexusClient, NexusClient.ExecuteOperation, NexusOperationHandle (get/describe/cancel/terminate), plus ListNexusOperations and CountNexusOperations visibility queries.

Implements the feature end-to-end in internal/internal_nexus_client.go with new gRPC calls, typed options/metadata structs, operation-name resolution, and long-poll result retrieval; extends ClientOutboundInterceptor with Nexus-related methods and updates mocks/tests accordingly.

Updates integration/unit tests to cover the new standalone flow (including endpoint provisioning, handle behaviors, cancel/terminate, list/count) and adjusts CI/dev-server config to use a Nexus-capable dev server and to optionally disable the new tests.

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

@Quinn-With-Two-Ns Quinn-With-Two-Ns marked this pull request as ready for review April 8, 2026 17:16
@Quinn-With-Two-Ns Quinn-With-Two-Ns requested a review from a team as a code owner April 8, 2026 17:16
Comment thread mocks/Client.go
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3fe42e708a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +30 to +33
// ID - The business identifier of the operation.
//
// Mandatory: No default.
ID string
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Rename start option field to OperationID for API consistency

ClientStartNexusOperationOptions introduces an ID field while the rest of the new Nexus API uses OperationID (GetNexusOperationHandleOptions, metadata structs, and the integration test callsites). This inconsistency makes normal usage patterns fail at compile time (unknown field OperationID) and effectively breaks the newly added standalone Nexus start API for callers who follow the surrounding API naming. Aligning this field name now avoids shipping an immediately incompatible public surface.

Useful? React with 👍 / 👎.

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.

This is to be consistent with Stand alone activities naming approach

Comment thread internal/internal_nexus_client.go
Comment thread internal/internal_nexus_client.go
Comment thread internal/internal_nexus_client.go
Comment thread internal/internal_nexus_client.go
Comment thread internal/internal_nexus_client.go
Comment thread mocks/Client.go Outdated
Comment thread client/client.go
Comment thread internal/internal_nexus_client.go
Comment thread client/client.go Outdated
Comment thread internal/internal_nexus_client_test.go
Comment thread internal/internal_nexus_client.go
Comment thread test/integration_test.go
Comment thread test/integration_test.go
@Quinn-With-Two-Ns
Copy link
Copy Markdown
Contributor Author

Note this PR is missing support for otel I was planning on addressing that in a separate PR to keep the scope down

@chrsmith chrsmith self-assigned this Apr 23, 2026
@Quinn-With-Two-Ns Quinn-With-Two-Ns force-pushed the NEXUS-289 branch 2 times, most recently from e77a1be to 0fb81e4 Compare May 14, 2026 17:33
Comment thread internal/internal_nexus_client.go
Comment thread internal/internal_nexus_client.go Outdated
}
}

func (w *workflowClientInterceptor) DescribeNexusOperation(
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.

Should cancel, describe, and terminate check that the operation ID is not empty?

Copy link
Copy Markdown

@VegetarianOrc VegetarianOrc left a comment

Choose a reason for hiding this comment

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

Couple of questions, but looks good!

Comment thread .github/workflows/ci.yml
DISABLE_SERVER_1_27_TESTS: "1"
DISABLE_PRIORITY_TESTS: "1"
DISABLE_STANDALONE_ACTIVITY_TESTS: "1"
DISABLE_STANDALONE_NEXUS_TESTS: "1"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This is following the existing pattern, but should we be defaulting to exclude all these tests in CI? Or maybe I am misunderstanding the setup.

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.

We should definitely revisit how we do this, last time I checked there was definitely some that could be removed at this point. I can add to TODO for myself

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.

The logic here just excludes when we are using docker to test since the docker tests don't use the pre-release CLI

Comment thread test/nexus_test.go
_, err := nexusclient.ExecuteOperation(ctx, nc, syncOp, "timeout", nexus.StartOperationOptions{
// Force shorter timeout to speed up the test and get a response back.
Header: nexus.Header{nexus.HeaderRequestTimeout: "300ms"},
Header: nexus.Header{nexus.HeaderRequestTimeout: "5s"},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Is this change needed/related? Was 300ms too aggressive and causing flakes?

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.

Yeah, specifically the endpoint registry is eventually consistent right now so under load it can take too long for the endpoint to become visible

Comment thread internal/internal_nexus_client.go
Comment thread client/client.go

// NexusClient is the client for starting Nexus operations bound to a specific endpoint and service.
// This is for standalone Nexus operations outside of workflow context.
// For Nexus operations within workflows, use workflow.NexusClient.
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.

Do we want to also mention in workflow.NexusClient that we have client.NexusClient for standalone operations?

Comment thread internal/internal_nexus_client.go Outdated
Comment thread internal/internal_nexus_client.go Outdated
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 mode and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit fe11924. Configure here.

Comment thread internal/internal_nexus_client.go
@Quinn-With-Two-Ns Quinn-With-Two-Ns enabled auto-merge (squash) May 19, 2026 17:46
@Quinn-With-Two-Ns Quinn-With-Two-Ns merged commit edfc506 into temporalio:main May 19, 2026
56 of 59 checks passed
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.

5 participants