Skip to content

Add Standalone Callbacks (rebase)#774

Open
chrsmith wants to merge 4 commits into
masterfrom
chrsmith/standalone-callbacks
Open

Add Standalone Callbacks (rebase)#774
chrsmith wants to merge 4 commits into
masterfrom
chrsmith/standalone-callbacks

Conversation

@chrsmith
Copy link
Copy Markdown

@chrsmith chrsmith commented Apr 27, 2026

ℹ️ This PR is the same as #753, only squashed and rebased. It's the same set of changes, modulo trivial edits to doc comments.

What changed?

Add the API for standalone callbacks. (AKA Manual Completions for Nexus.)

Why?

Standalone callbacks support connecting non-Temporal services to Nexus. e.g. supporting a way for, say, a Slackbot directly complete a Nexus operation rather than needing to add an intermediary workflow.

Breaking changes

None, this is purely additive.

Server PR

These changes also require updates in the api-go package as well, since the use of oneof requires some minor codegen tweaks.
temporalio/api-go#255

The server-side changes are here:
temporalio/temporal#10192

@chrsmith chrsmith changed the title [WIP] Add Stand Alone Callbacks (rebase) [WIP] Add Standalone Callbacks (rebase) Apr 27, 2026
@chrsmith chrsmith force-pushed the chrsmith/standalone-callbacks branch 3 times, most recently from a5588a7 to 1064b19 Compare April 30, 2026 21:29
@chrsmith chrsmith force-pushed the chrsmith/standalone-callbacks branch 2 times, most recently from 89e0db0 to cd67565 Compare May 7, 2026 21:49
@chrsmith chrsmith changed the title [WIP] Add Standalone Callbacks (rebase) Add Standalone Callbacks (rebase) May 11, 2026
@chrsmith chrsmith marked this pull request as ready for review May 11, 2026 21:56
@chrsmith chrsmith requested review from a team, Quinn-With-Two-Ns and stephanos May 11, 2026 21:56
Copy link
Copy Markdown
Member

@bergundy bergundy left a comment

Choose a reason for hiding this comment

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

Mostly LGTM

Comment thread temporal/api/callback/v1/message.proto Outdated
temporal.api.enums.v1.CallbackState state = 5;

// The number of attempts made to deliver the callback.
// This number represents a minimum bound since the attempt is incremented after the callback request completes.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should take a pass at this docstring both here and for Nexus ops. I changed the behavior for Nexus to start from attempt 1 and have a better explanation here:

https://github.com/temporalio/temporal/blob/a05038cf9993ebe043466d3597952e0e29622467/chasm/lib/nexusoperation/proto/v1/operation.proto#L44-L47

Comment thread temporal/api/callback/v1/message.proto Outdated
string blocked_reason = 11;

// Time when the callback transitioned to a terminal state.
google.protobuf.Timestamp close_time = 12;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: could you put this next to create_time? Logically those should be grouped.

string url = 1;
// Header to attach to callback request.
map<string, string> header = 2;
// Standard token to use for identifying the callback, used for completion.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe put a comment here that implementations should also populate the token header field for compatibility with older servers?

// Callback has failed.
CALLBACK_EXECUTION_STATUS_FAILED = 3;
// Callback was terminated via TerminateCallbackExecution.
CALLBACK_EXECUTION_STATUS_TERMINATED = 4;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What about timed out?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

If the callback times out, we just use the STATUS_FAILED state, and set the TimeoutFailureInfo field in the terminal failure proto.

But I'm assuming you'd like to add it, and I cannot think of a compelling argument not to. 😄

// Callback is blocked (eg: by circuit breaker).
CALLBACK_STATE_BLOCKED = 6;
// Callback was terminated via TerminateCallbackExecution. Only possible for standalone callbacks.
CALLBACK_STATE_TERMINATED = 7;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What about timed out?

message CallbackExecutionAlreadyStartedFailure {
string start_request_id = 1;
string run_id = 2;
string callback_id = 3;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The other already started failures don't include the business ID, let's not add that here.

map<string, string> callback_header = 6;
// Links contain caller information and can be attached to the operations started by the handler.
repeated Link links = 7;
// Callback token, to uniquely identify the callback as applicable.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: document the semantics of when to use this field and when to populate the header value.

// Identifier for the callback
string callback_id = 2;
// Run ID of the callback execution to describe. If empty, the latest run will be described.
string run_id = 3;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you check what the semantics of a request with an empty run ID with a long poll token? Is that valid in the SAA code?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

That comment is incorrect. Looking at the implementation and doc comments for SAA, it checks that run_id is present if long_poll_token is set. And it's also called out in the doc comment. Will fix.


message DescribeCallbackExecutionRequest {
string namespace = 1;
// Identifier for the callback
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: All other fields have a punctuation. I see this is missing in other messages for the callback_id field too.

Suggested change
// Identifier for the callback
// Identifier for the callback.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Nice catch, fixed.

int32 page_size = 2;
// Token returned in ListCallbackExecutionsResponse.
bytes next_page_token = 3;
// Visibility query, see https://docs.temporal.io/list-filter for the syntax.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please document which search attributes are valid here (and for the count API).

@chrsmith chrsmith force-pushed the chrsmith/standalone-callbacks branch from cd67565 to 7c4b67e Compare May 13, 2026 19:55
@chrsmith
Copy link
Copy Markdown
Author

@bergundy PTAL. I rebased with master, so the diff from the earlier review is commit
7c4b67e.

@chrsmith chrsmith requested a review from bergundy May 13, 2026 19:58
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