From 1af88d70fcfb48ce7180001443cf03221ccd5e2e Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Mon, 20 Jul 2026 16:31:55 -0700 Subject: [PATCH 1/8] API surface area for worker callbacks --- openapi/openapiv2.json | 65 ++++++++++++++----- openapi/openapiv3.yaml | 43 ++++++++++++ temporal/api/common/v1/message.proto | 31 +++++++++ .../v1/request_response.proto | 57 ++++++++++++++++ .../workflowservice/v1/request_response.proto | 3 + 5 files changed, 184 insertions(+), 15 deletions(-) create mode 100644 temporal/api/notificationservice/v1/request_response.proto diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 97ff181c9..ef77333cf 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -10834,20 +10834,6 @@ }, "description": "Target an external server by URL.\nAt a later point, this will support providing credentials, in the meantime, an http.RoundTripper can be injected\ninto the server to modify the request." }, - "EndpointTargetWorker": { - "type": "object", - "properties": { - "namespace": { - "type": "string", - "description": "Namespace to route requests to." - }, - "taskQueue": { - "type": "string", - "description": "Nexus task queue to route requests to." - } - }, - "description": "Target a worker polling on a Nexus task queue in a specific namespace." - }, "EventGroupMarkerInboundEvent": { "type": "object", "properties": { @@ -12469,6 +12455,14 @@ "userMetadata": { "$ref": "#/definitions/v1UserMetadata", "description": "Metadata for use by user interfaces to display the fixed as-of-start summary and details of the operation." + }, + "completionCallbacks": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Callback" + }, + "description": "Completion callbacks to be invoked once the Nexus operation reaches a terminal state." } } }, @@ -14406,6 +14400,9 @@ "internal": { "$ref": "#/definitions/CallbackInternal" }, + "worker": { + "$ref": "#/definitions/v1CallbackWorker" + }, "links": { "type": "array", "items": { @@ -14431,6 +14428,30 @@ "default": "CALLBACK_STATE_UNSPECIFIED", "description": "State of a callback.\n\n - CALLBACK_STATE_UNSPECIFIED: Default value, unspecified state.\n - CALLBACK_STATE_STANDBY: Callback is standing by, waiting to be triggered.\n - CALLBACK_STATE_SCHEDULED: Callback is in the queue waiting to be executed or is currently executing.\n - CALLBACK_STATE_BACKING_OFF: Callback has failed with a retryable error and is backing off before the next attempt.\n - CALLBACK_STATE_FAILED: Callback has failed.\n - CALLBACK_STATE_SUCCEEDED: Callback has succeeded.\n - CALLBACK_STATE_BLOCKED: Callback is blocked (eg: by circuit breaker)." }, + "v1CallbackWorker": { + "type": "object", + "properties": { + "taskqueueName": { + "type": "string", + "description": "Nexus task queue the Temporal worker is listening on.\n\nNOTE: This is not a temporal.api.taskqueue.v1.TaskQueue to avoid a circular dependency." + }, + "service": { + "type": "string", + "description": "Target Nexus service, e.g. \"temporal.api.notificationservice.v1.NotificationService\"." + }, + "operation": { + "type": "string", + "description": "Target operation, e.g. \"OnComplete\"." + }, + "sourceContext": { + "$ref": "#/definitions/v1Payload", + "description": "There is a relatively small maximum size the source context can be, e.g. 32KiB.", + "title": "Arbitrary user-supplied data from the source operation's callsite. (As applicable, not all operations\nsupport attaching context data.)" + } + }, + "description": "The targeted Nexus service must be registered within the same namespace as the source operation\nthe callback is attached to. (While Nexus allows for cross-namespace operations, worker callbacks\nare purely \"caller-side\".)\n\nWorker callbacks are only supported for certain types of operations, e.g. standalone Nexus operations.\nAttempting to attach a Worker callback for an unsupported operation will result in an INVALID_ARGUMENT\nerror from the server.", + "title": "Worker callbacks are requests to invoke a specific shape of Nexus operation on a Temporal worker.\nThe specified Nexus operation must have the following:\n- Input: temporal.api.notificationservice.v1.OnCompleteRequest\n- Output: temporal.api.notificationservice.v1.OnCompleteResponse" + }, "v1CancelExternalWorkflowExecutionFailedCause": { "type": "string", "enum": [ @@ -15591,7 +15612,7 @@ "type": "object", "properties": { "worker": { - "$ref": "#/definitions/EndpointTargetWorker" + "$ref": "#/definitions/v1EndpointTargetWorker" }, "external": { "$ref": "#/definitions/EndpointTargetExternal" @@ -15599,6 +15620,20 @@ }, "description": "Target to route requests to." }, + "v1EndpointTargetWorker": { + "type": "object", + "properties": { + "namespace": { + "type": "string", + "description": "Namespace to route requests to." + }, + "taskQueue": { + "type": "string", + "description": "Nexus task queue to route requests to." + } + }, + "description": "Target a worker polling on a Nexus task queue in a specific namespace." + }, "v1EventGroupMarker": { "type": "object", "properties": { diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index f2081bd9b..cae7e8759 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -10748,6 +10748,8 @@ components: $ref: '#/components/schemas/Callback_Nexus' internal: $ref: '#/components/schemas/Callback_Internal' + worker: + $ref: '#/components/schemas/Callback_Worker' links: type: array items: @@ -10824,6 +10826,42 @@ components: additionalProperties: type: string description: Header to attach to callback request. + Callback_Worker: + type: object + properties: + taskqueueName: + type: string + description: |- + Nexus task queue the Temporal worker is listening on. + + NOTE: This is not a temporal.api.taskqueue.v1.TaskQueue to avoid a circular dependency. + service: + type: string + description: Target Nexus service, e.g. "temporal.api.notificationservice.v1.NotificationService". + operation: + type: string + description: Target operation, e.g. "OnComplete". + sourceContext: + allOf: + - $ref: '#/components/schemas/Payload' + description: |- + Arbitrary user-supplied data from the source operation's callsite. (As applicable, not all operations + support attaching context data.) + + There is a relatively small maximum size the source context can be, e.g. 32KiB. + description: |- + Worker callbacks are requests to invoke a specific shape of Nexus operation on a Temporal worker. + The specified Nexus operation must have the following: + - Input: temporal.api.notificationservice.v1.OnCompleteRequest + - Output: temporal.api.notificationservice.v1.OnCompleteResponse + + The targeted Nexus service must be registered within the same namespace as the source operation + the callback is attached to. (While Nexus allows for cross-namespace operations, worker callbacks + are purely "caller-side".) + + Worker callbacks are only supported for certain types of operations, e.g. standalone Nexus operations. + Attempting to attach a Worker callback for an unsupported operation will result in an INVALID_ARGUMENT + error from the server. CanceledFailureInfo: type: object properties: @@ -17060,6 +17098,11 @@ components: allOf: - $ref: '#/components/schemas/UserMetadata' description: Metadata for use by user interfaces to display the fixed as-of-start summary and details of the operation. + completionCallbacks: + type: array + items: + $ref: '#/components/schemas/Callback' + description: Completion callbacks to be invoked once the Nexus operation reaches a terminal state. StartNexusOperationExecutionResponse: type: object properties: diff --git a/temporal/api/common/v1/message.proto b/temporal/api/common/v1/message.proto index 1af5b4acc..08e26dc74 100644 --- a/temporal/api/common/v1/message.proto +++ b/temporal/api/common/v1/message.proto @@ -201,10 +201,41 @@ message Callback { bytes data = 1; } + // Worker callbacks are requests to invoke a specific shape of Nexus operation on a Temporal worker. + // The specified Nexus operation must have the following: + // - Input: temporal.api.notificationservice.v1.OnCompleteRequest + // - Output: temporal.api.notificationservice.v1.OnCompleteResponse + // + // The targeted Nexus service must be registered within the same namespace as the source operation + // the callback is attached to. (While Nexus allows for cross-namespace operations, worker callbacks + // are purely "caller-side".) + // + // Worker callbacks are only supported for certain types of operations, e.g. standalone Nexus operations. + // Attempting to attach a Worker callback for an unsupported operation will result in an INVALID_ARGUMENT + // error from the server. + message Worker { + // Nexus task queue the Temporal worker is listening on. + // + // NOTE: This is not a temporal.api.taskqueue.v1.TaskQueue to avoid a circular dependency. + string taskqueue_name = 1; + + // Target Nexus service, e.g. "temporal.api.notificationservice.v1.NotificationService". + string service = 2; + // Target operation, e.g. "OnComplete". + string operation = 3; + + // Arbitrary user-supplied data from the source operation's callsite. (As applicable, not all operations + // support attaching context data.) + // + // There is a relatively small maximum size the source context can be, e.g. 32KiB. + temporal.api.common.v1.Payload source_context = 4; + } + reserved 1; // For a generic callback mechanism to be added later. oneof variant { Nexus nexus = 2; Internal internal = 3; + Worker worker = 4; } // Links associated with the callback. It can be used to link to underlying resources of the diff --git a/temporal/api/notificationservice/v1/request_response.proto b/temporal/api/notificationservice/v1/request_response.proto new file mode 100644 index 000000000..26e9d53dc --- /dev/null +++ b/temporal/api/notificationservice/v1/request_response.proto @@ -0,0 +1,57 @@ +syntax = "proto3"; + +package temporal.api.notificationservice.v1; + +option go_package = "go.temporal.io/api/notificationservice/v1;notificationservice"; +option java_package = "io.temporal.api.notificationservice.v1"; +option java_multiple_files = true; +option java_outer_classname = "RequestResponseProto"; +option ruby_package = "Temporalio::Api::NotificationService::V1"; +option csharp_namespace = "Temporalio.Api.NotificationService.V1"; + +import "temporal/api/common/v1/message.proto"; +import "temporal/api/failure/v1/message.proto"; + +// OnCompleteRequest is the request type to the NotificationService's OnComplete operation, +// allowing for defining completion handlers for arbitrary asynchronous operations. +message OnCompleteRequest { + + // The source Nexus operation that the OnComplete invocation is reporting. + message NexusOperation { + // The Nexus endpoint. + string endpoint = 1; + // The Nexus service. + string service = 2; + // The Nexus operation. + string operation = 3; + + // The token the operation produced. (If it was an asynchronous Nexus operation.) + string operation_token = 4; + } + + // The source asynchronous operation. + message SourceOperation { + oneof variant { + NexusOperation nexus_operation = 1; + } + } + + // The outcome of the source operation. + message Outcome { + oneof result { + // The operation was successful, and resulted in the given payload(s). + temporal.api.common.v1.Payloads success = 1; + // The operation failed. Includes timeout, cancellation, and application errors. + temporal.api.failure.v1.Failure failure = 2; + } + } + + SourceOperation source_operation = 1; + Outcome outcome = 2; + + // User-supplied data which was added to the source invocation. (As applicable.) + temporal.api.common.v1.Payload source_context = 3; +} + +// OnCompleteResponse is the return type of the OnComplete operation. +message OnCompleteResponse {} diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index 66f478c5c..7e4f3ecc3 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -3393,6 +3393,9 @@ message StartNexusOperationExecutionRequest { map nexus_header = 15; // Metadata for use by user interfaces to display the fixed as-of-start summary and details of the operation. temporal.api.sdk.v1.UserMetadata user_metadata = 16; + + // Completion callbacks to be invoked once the Nexus operation reaches a terminal state. + repeated temporal.api.common.v1.Callback completion_callbacks = 17; } message StartNexusOperationExecutionResponse { From c074ae0be8cb5fbd62b4982d37fa726b3fb4759b Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Tue, 21 Jul 2026 13:25:34 -0700 Subject: [PATCH 2/8] Expose CallbackExecutionInfo from DescribeNexusOperationExecutionResponse --- openapi/openapiv2.json | 97 ++++++++++++++++++- openapi/openapiv3.yaml | 92 +++++++++++++++++- temporal/api/common/v1/message.proto | 2 +- temporal/api/enums/v1/common.proto | 2 +- temporal/api/workflowservice/v1/message.proto | 74 ++++++++++++++ .../workflowservice/v1/request_response.proto | 5 + 6 files changed, 266 insertions(+), 6 deletions(-) create mode 100644 temporal/api/workflowservice/v1/message.proto diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index ef77333cf..35b4e3ec9 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "title": "temporal/api/workflowservice/v1/request_response.proto", + "title": "temporal/api/workflowservice/v1/message.proto", "version": "version not set" }, "tags": [ @@ -14414,6 +14414,89 @@ }, "description": "Callback to attach to various events in the system, e.g. workflow run completion." }, + "v1CallbackExecutionInfo": { + "type": "object", + "properties": { + "callbackId": { + "type": "string", + "description": "Identifier of the callback's execution. Unique within the containing namespace." + }, + "runId": { + "type": "string", + "description": "Run ID of the callback execution." + }, + "callback": { + "$ref": "#/definitions/v1Callback", + "description": "The Callback being described." + }, + "state": { + "$ref": "#/definitions/v1CallbackState", + "description": "The detailed state of the callback." + }, + "stateReason": { + "type": "string", + "description": "Human friendly context describing the state, if applicable.\ne.g. if the state is BLOCKED, provides an explanation why." + }, + "outcome": { + "$ref": "#/definitions/v1CallbackExecutionOutcome", + "description": "The outcome of the callback's execution, as applicable." + }, + "attempt": { + "type": "integer", + "format": "int32", + "description": "The number of attempts made to deliver/execute callback.\n\nThis number is approximate. There could be more attempts if the server crashes before recording the attempt's completion, or fewer\nif the callback was terminated or timed out after the counter has been incremented and before an attempt could be made." + }, + "createTime": { + "type": "string", + "format": "date-time", + "title": "The time when the callback was created. (But not necessarily scheduled.)" + }, + "closeTime": { + "type": "string", + "format": "date-time", + "description": "Time when the callback transitioned to a terminal state." + }, + "lastAttemptCompleteTime": { + "type": "string", + "format": "date-time", + "description": "The time when the last attempt completed." + }, + "lastAttemptFailure": { + "$ref": "#/definitions/v1Failure", + "description": "The last attempt's failure, if any." + }, + "nextAttemptScheduleTime": { + "type": "string", + "format": "date-time", + "description": "The time when the next attempt is scheduled (only set when state is BACKING_OFF)." + }, + "scheduleToCloseTimeout": { + "type": "string", + "description": "Schedule-to-close timeout for this callback." + }, + "stateTransitionCount": { + "type": "string", + "format": "int64", + "description": "Incremented each time the callback's state is mutated in persistence." + } + }, + "description": "Information about a callback's execution." + }, + "v1CallbackExecutionOutcome": { + "type": "object", + "properties": { + "success": { + "type": "object", + "properties": {}, + "title": "The callback completed successfully. (Which may include delivering a \"failed\" result successfully.)" + }, + "failure": { + "$ref": "#/definitions/v1Failure", + "description": "The failure if the callback was not able to complete successfully. e.g. timed out, received an\nunretriable error, etc." + } + }, + "description": "The outcome of a callback's execution, either success or a failure." + }, "v1CallbackState": { "type": "string", "enum": [ @@ -14426,12 +14509,12 @@ "CALLBACK_STATE_BLOCKED" ], "default": "CALLBACK_STATE_UNSPECIFIED", - "description": "State of a callback.\n\n - CALLBACK_STATE_UNSPECIFIED: Default value, unspecified state.\n - CALLBACK_STATE_STANDBY: Callback is standing by, waiting to be triggered.\n - CALLBACK_STATE_SCHEDULED: Callback is in the queue waiting to be executed or is currently executing.\n - CALLBACK_STATE_BACKING_OFF: Callback has failed with a retryable error and is backing off before the next attempt.\n - CALLBACK_STATE_FAILED: Callback has failed.\n - CALLBACK_STATE_SUCCEEDED: Callback has succeeded.\n - CALLBACK_STATE_BLOCKED: Callback is blocked (eg: by circuit breaker)." + "description": "State of a callback.\n\n - CALLBACK_STATE_UNSPECIFIED: Default value, unspecified state.\n - CALLBACK_STATE_STANDBY: Callback is standing by, waiting to be triggered.\n - CALLBACK_STATE_SCHEDULED: Callback is in the queue waiting to be executed or is currently executing.\n - CALLBACK_STATE_BACKING_OFF: Callback has failed with a retryable error and is backing off before the next attempt.\n - CALLBACK_STATE_FAILED: Callback has failed.\n - CALLBACK_STATE_SUCCEEDED: Callback has succeeded.\n - CALLBACK_STATE_BLOCKED: Callback is blocked, e.g. by circuit breaker." }, "v1CallbackWorker": { "type": "object", "properties": { - "taskqueueName": { + "taskQueueName": { "type": "string", "description": "Nexus task queue the Temporal worker is listening on.\n\nNOTE: This is not a temporal.api.taskqueue.v1.TaskQueue to avoid a circular dependency." }, @@ -15375,6 +15458,14 @@ "type": "string", "format": "byte", "description": "Token for follow-on long-poll requests. Absent only if the operation is complete." + }, + "completionCallbacks": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1CallbackExecutionInfo" + }, + "description": "Completion callbacks to be invoked once the Nexus operation reaches a terminal state.\nThey will remain in the CALLBACK_STATE_STANDBY state until the Nexus operation is finished." } } }, diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index cae7e8759..51949d6cc 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -10758,6 +10758,89 @@ components: Links associated with the callback. It can be used to link to underlying resources of the callback. description: Callback to attach to various events in the system, e.g. workflow run completion. + CallbackExecutionInfo: + type: object + properties: + callbackId: + type: string + description: Identifier of the callback's execution. Unique within the containing namespace. + runId: + type: string + description: Run ID of the callback execution. + callback: + allOf: + - $ref: '#/components/schemas/Callback' + description: The Callback being described. + state: + enum: + - CALLBACK_STATE_UNSPECIFIED + - CALLBACK_STATE_STANDBY + - CALLBACK_STATE_SCHEDULED + - CALLBACK_STATE_BACKING_OFF + - CALLBACK_STATE_FAILED + - CALLBACK_STATE_SUCCEEDED + - CALLBACK_STATE_BLOCKED + type: string + description: The detailed state of the callback. + format: enum + stateReason: + type: string + description: |- + Human friendly context describing the state, if applicable. + e.g. if the state is BLOCKED, provides an explanation why. + outcome: + allOf: + - $ref: '#/components/schemas/CallbackExecutionOutcome' + description: The outcome of the callback's execution, as applicable. + attempt: + type: integer + description: |- + The number of attempts made to deliver/execute callback. + + This number is approximate. There could be more attempts if the server crashes before recording the attempt's completion, or fewer + if the callback was terminated or timed out after the counter has been incremented and before an attempt could be made. + format: int32 + createTime: + type: string + description: The time when the callback was created. (But not necessarily scheduled.) + format: date-time + closeTime: + type: string + description: Time when the callback transitioned to a terminal state. + format: date-time + lastAttemptCompleteTime: + type: string + description: The time when the last attempt completed. + format: date-time + lastAttemptFailure: + allOf: + - $ref: '#/components/schemas/Failure' + description: The last attempt's failure, if any. + nextAttemptScheduleTime: + type: string + description: The time when the next attempt is scheduled (only set when state is BACKING_OFF). + format: date-time + scheduleToCloseTimeout: + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + type: string + description: |- + Schedule-to-close timeout for this callback. + (-- api-linter: core::0140::prepositions=disabled + aip.dev/not-precedent: "to" is used to indicate interval. --) + stateTransitionCount: + type: string + description: Incremented each time the callback's state is mutated in persistence. + description: Information about a callback's execution. + CallbackExecutionOutcome: + type: object + properties: + failure: + allOf: + - $ref: '#/components/schemas/Failure' + description: |- + The failure if the callback was not able to complete successfully. e.g. timed out, received an + unretriable error, etc. + description: The outcome of a callback's execution, either success or a failure. CallbackInfo: type: object properties: @@ -10829,7 +10912,7 @@ components: Callback_Worker: type: object properties: - taskqueueName: + taskQueueName: type: string description: |- Nexus task queue the Temporal worker is listening on. @@ -11846,6 +11929,13 @@ components: type: string description: Token for follow-on long-poll requests. Absent only if the operation is complete. format: bytes + completionCallbacks: + type: array + items: + $ref: '#/components/schemas/CallbackExecutionInfo' + description: |- + Completion callbacks to be invoked once the Nexus operation reaches a terminal state. + They will remain in the CALLBACK_STATE_STANDBY state until the Nexus operation is finished. DescribeScheduleResponse: type: object properties: diff --git a/temporal/api/common/v1/message.proto b/temporal/api/common/v1/message.proto index 08e26dc74..bc5e54411 100644 --- a/temporal/api/common/v1/message.proto +++ b/temporal/api/common/v1/message.proto @@ -217,7 +217,7 @@ message Callback { // Nexus task queue the Temporal worker is listening on. // // NOTE: This is not a temporal.api.taskqueue.v1.TaskQueue to avoid a circular dependency. - string taskqueue_name = 1; + string task_queue_name = 1; // Target Nexus service, e.g. "temporal.api.notificationservice.v1.NotificationService". string service = 2; diff --git a/temporal/api/enums/v1/common.proto b/temporal/api/enums/v1/common.proto index cdc387173..e2929337e 100644 --- a/temporal/api/enums/v1/common.proto +++ b/temporal/api/enums/v1/common.proto @@ -47,7 +47,7 @@ enum CallbackState { CALLBACK_STATE_FAILED = 4; // Callback has succeeded. CALLBACK_STATE_SUCCEEDED = 5; - // Callback is blocked (eg: by circuit breaker). + // Callback is blocked, e.g. by circuit breaker. CALLBACK_STATE_BLOCKED = 6; } diff --git a/temporal/api/workflowservice/v1/message.proto b/temporal/api/workflowservice/v1/message.proto new file mode 100644 index 000000000..73d12f90b --- /dev/null +++ b/temporal/api/workflowservice/v1/message.proto @@ -0,0 +1,74 @@ +syntax = "proto3"; + +package temporal.api.workflowservice.v1; + +option go_package = "go.temporal.io/api/workflowservice/v1;workflowservice"; +option java_package = "io.temporal.api.workflowservice.v1"; +option java_multiple_files = true; +option java_outer_classname = "MessageProto"; +option ruby_package = "Temporalio::Api::WorkflowService::V1"; +option csharp_namespace = "Temporalio.Api.WorkflowService.V1"; + +import "google/protobuf/duration.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/timestamp.proto"; + +import "temporal/api/common/v1/message.proto"; +import "temporal/api/enums/v1/common.proto"; +import "temporal/api/failure/v1/message.proto"; + +// The outcome of a callback's execution, either success or a failure. +message CallbackExecutionOutcome { + oneof value { + // The callback completed successfully. (Which may include delivering a "failed" result successfully.) + google.protobuf.Empty success = 1; + // The failure if the callback was not able to complete successfully. e.g. timed out, received an + // unretriable error, etc. + temporal.api.failure.v1.Failure failure = 2; + } +} + +// Information about a callback's execution. +message CallbackExecutionInfo { + // Identifier of the callback's execution. Unique within the containing namespace. + string callback_id = 1; + // Run ID of the callback execution. + string run_id = 2; + + // The Callback being described. + temporal.api.common.v1.Callback callback = 3; + // The detailed state of the callback. + temporal.api.enums.v1.CallbackState state = 4; + // Human friendly context describing the state, if applicable. + // e.g. if the state is BLOCKED, provides an explanation why. + string state_reason = 5; + + // The outcome of the callback's execution, as applicable. + CallbackExecutionOutcome outcome = 6; + + // The number of attempts made to deliver/execute callback. + // + // This number is approximate. There could be more attempts if the server crashes before recording the attempt's completion, or fewer + // if the callback was terminated or timed out after the counter has been incremented and before an attempt could be made. + int32 attempt = 7; + + // The time when the callback was created. (But not necessarily scheduled.) + google.protobuf.Timestamp create_time = 8; + // Time when the callback transitioned to a terminal state. + google.protobuf.Timestamp close_time = 9; + + // The time when the last attempt completed. + google.protobuf.Timestamp last_attempt_complete_time = 10; + // The last attempt's failure, if any. + temporal.api.failure.v1.Failure last_attempt_failure = 11; + // The time when the next attempt is scheduled (only set when state is BACKING_OFF). + google.protobuf.Timestamp next_attempt_schedule_time = 12; + + // Schedule-to-close timeout for this callback. + // (-- api-linter: core::0140::prepositions=disabled + // aip.dev/not-precedent: "to" is used to indicate interval. --) + google.protobuf.Duration schedule_to_close_timeout = 13; + + // Incremented each time the callback's state is mutated in persistence. + int64 state_transition_count = 14; +} diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index 7e4f3ecc3..e6864d3c9 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -45,6 +45,7 @@ import "temporal/api/sdk/v1/task_complete_metadata.proto"; import "temporal/api/sdk/v1/user_metadata.proto"; import "temporal/api/nexus/v1/message.proto"; import "temporal/api/worker/v1/message.proto"; +import "temporal/api/workflowservice/v1/message.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/field_mask.proto"; @@ -3444,6 +3445,10 @@ message DescribeNexusOperationExecutionResponse { // Token for follow-on long-poll requests. Absent only if the operation is complete. bytes long_poll_token = 6; + + // Completion callbacks to be invoked once the Nexus operation reaches a terminal state. + // They will remain in the CALLBACK_STATE_STANDBY state until the Nexus operation is finished. + repeated CallbackExecutionInfo completion_callbacks = 7; } message PollNexusOperationExecutionRequest { From f6b3d1c57da3ce1b529185d7ea39a65b38aada57 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Tue, 21 Jul 2026 19:31:12 -0700 Subject: [PATCH 3/8] Add new Callback variant of Link --- temporal/api/common/v1/message.proto | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/temporal/api/common/v1/message.proto b/temporal/api/common/v1/message.proto index bc5e54411..6b8098286 100644 --- a/temporal/api/common/v1/message.proto +++ b/temporal/api/common/v1/message.proto @@ -304,12 +304,28 @@ message Link { string reason = 4; } + // A link to a callback or completion handler for an operation. e.g. not a link to a standalone Nexus operation, + // but the callback that was executed once that operation finished. + message Callback { + message NexusOperationCompletion { + string operation_id = 1; + string run_id = 2; + string request_id = 3; + } + + string callback_id = 1; + oneof variant { + NexusOperationCompletion nexus_operation_completion = 2; + } + } + oneof variant { WorkflowEvent workflow_event = 1; BatchJob batch_job = 2; Activity activity = 3; NexusOperation nexus_operation = 4; Workflow workflow = 5; + Callback callback = 6; } } From c176d77986cdfdc7286c0fe65517d778661743c4 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Fri, 24 Jul 2026 13:18:27 -0700 Subject: [PATCH 4/8] Address PR feedback --- openapi/openapiv2.json | 165 ++++++++---------- openapi/openapiv3.yaml | 95 +++------- temporal/api/callback/v1/message.proto | 22 ++- temporal/api/common/v1/message.proto | 4 +- .../v1/request_response.proto | 31 +--- temporal/api/workflowservice/v1/message.proto | 74 -------- .../workflowservice/v1/request_response.proto | 4 +- 7 files changed, 128 insertions(+), 267 deletions(-) delete mode 100644 temporal/api/workflowservice/v1/message.proto diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 35b4e3ec9..b596d4312 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "title": "temporal/api/workflowservice/v1/message.proto", + "title": "temporal/api/workflowservice/v1/request_response.proto", "version": "version not set" }, "tags": [ @@ -10757,6 +10757,20 @@ } } }, + "CallbackNexusOperationCompletion": { + "type": "object", + "properties": { + "operationId": { + "type": "string" + }, + "runId": { + "type": "string" + }, + "requestId": { + "type": "string" + } + } + }, "ComputeStatusProviderValidationStatus": { "type": "object", "properties": { @@ -11276,7 +11290,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Callback" + "$ref": "#/definitions/commonV1Callback" }, "description": "Completion callbacks attached to the running workflow update." } @@ -12302,7 +12316,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Callback" + "$ref": "#/definitions/commonV1Callback" }, "description": "Callbacks to be called by the server when this activity reaches a terminal state.\nCallback addresses must be whitelisted in the server's dynamic configuration." }, @@ -12460,7 +12474,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Callback" + "$ref": "#/definitions/commonV1Callback" }, "description": "Completion callbacks to be invoked once the Nexus operation reaches a terminal state." } @@ -12543,7 +12557,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Callback" + "$ref": "#/definitions/commonV1Callback" }, "description": "Callbacks to be called by the server when this workflow reaches a terminal state.\nIf the workflow continues-as-new, these callbacks will be carried over to the new execution.\nCallback addresses must be whitelisted in the server's dynamic configuration." }, @@ -13087,7 +13101,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Callback" + "$ref": "#/definitions/commonV1Callback" }, "description": "Callbacks to be called by the server when this update reaches a terminal state." }, @@ -13187,7 +13201,7 @@ "type": "object", "properties": { "callback": { - "$ref": "#/definitions/v1Callback", + "$ref": "#/definitions/commonV1Callback", "description": "Information on how this callback should be invoked (e.g. its URL and type)." }, "registrationTime": { @@ -13247,7 +13261,7 @@ "type": "object", "properties": { "callback": { - "$ref": "#/definitions/v1Callback", + "$ref": "#/definitions/commonV1Callback", "description": "Information on how this callback should be invoked (e.g. its URL and type)." }, "trigger": { @@ -13317,6 +13331,29 @@ }, "description": "When StartWorkflowExecution uses the conflict policy WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING and\nthere is already an existing running workflow, OnConflictOptions defines actions to be taken on\nthe existing running workflow. In this case, it will create a WorkflowExecutionOptionsUpdatedEvent\nhistory event in the running workflow with the changes requested in this object." }, + "commonV1Callback": { + "type": "object", + "properties": { + "nexus": { + "$ref": "#/definitions/CallbackNexus" + }, + "internal": { + "$ref": "#/definitions/CallbackInternal" + }, + "worker": { + "$ref": "#/definitions/v1CallbackWorker" + }, + "links": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Link" + }, + "description": "Links associated with the callback. It can be used to link to underlying resources of the\ncallback." + } + }, + "description": "Callback to attach to various events in the system, e.g. workflow run completion." + }, "protobufAny": { "type": "object", "properties": { @@ -14391,29 +14428,6 @@ }, "description": "CalendarSpec describes an event specification relative to the calendar,\nsimilar to a traditional cron specification, but with labeled fields. Each\nfield can be one of:\n *: matches always\n x: matches when the field equals x\n x/y : matches when the field equals x+n*y where n is an integer\n x-z: matches when the field is between x and z inclusive\n w,x,y,...: matches when the field is one of the listed values\nEach x, y, z, ... is either a decimal integer, or a month or day of week name\nor abbreviation (in the appropriate fields).\nA timestamp matches if all fields match.\nNote that fields have different default values, for convenience.\nNote that the special case that some cron implementations have for treating\nday_of_month and day_of_week as \"or\" instead of \"and\" when both are set is\nnot implemented.\nday_of_week can accept 0 or 7 as Sunday\nCalendarSpec gets compiled into StructuredCalendarSpec, which is what will be\nreturned if you describe the schedule." }, - "v1Callback": { - "type": "object", - "properties": { - "nexus": { - "$ref": "#/definitions/CallbackNexus" - }, - "internal": { - "$ref": "#/definitions/CallbackInternal" - }, - "worker": { - "$ref": "#/definitions/v1CallbackWorker" - }, - "links": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Link" - }, - "description": "Links associated with the callback. It can be used to link to underlying resources of the\ncallback." - } - }, - "description": "Callback to attach to various events in the system, e.g. workflow run completion." - }, "v1CallbackExecutionInfo": { "type": "object", "properties": { @@ -14421,66 +14435,13 @@ "type": "string", "description": "Identifier of the callback's execution. Unique within the containing namespace." }, - "runId": { - "type": "string", - "description": "Run ID of the callback execution." - }, - "callback": { - "$ref": "#/definitions/v1Callback", - "description": "The Callback being described." - }, - "state": { - "$ref": "#/definitions/v1CallbackState", - "description": "The detailed state of the callback." - }, - "stateReason": { - "type": "string", - "description": "Human friendly context describing the state, if applicable.\ne.g. if the state is BLOCKED, provides an explanation why." + "info": { + "$ref": "#/definitions/apiCallbackV1CallbackInfo" }, "outcome": { - "$ref": "#/definitions/v1CallbackExecutionOutcome", - "description": "The outcome of the callback's execution, as applicable." - }, - "attempt": { - "type": "integer", - "format": "int32", - "description": "The number of attempts made to deliver/execute callback.\n\nThis number is approximate. There could be more attempts if the server crashes before recording the attempt's completion, or fewer\nif the callback was terminated or timed out after the counter has been incremented and before an attempt could be made." - }, - "createTime": { - "type": "string", - "format": "date-time", - "title": "The time when the callback was created. (But not necessarily scheduled.)" - }, - "closeTime": { - "type": "string", - "format": "date-time", - "description": "Time when the callback transitioned to a terminal state." - }, - "lastAttemptCompleteTime": { - "type": "string", - "format": "date-time", - "description": "The time when the last attempt completed." - }, - "lastAttemptFailure": { - "$ref": "#/definitions/v1Failure", - "description": "The last attempt's failure, if any." - }, - "nextAttemptScheduleTime": { - "type": "string", - "format": "date-time", - "description": "The time when the next attempt is scheduled (only set when state is BACKING_OFF)." - }, - "scheduleToCloseTimeout": { - "type": "string", - "description": "Schedule-to-close timeout for this callback." - }, - "stateTransitionCount": { - "type": "string", - "format": "int64", - "description": "Incremented each time the callback's state is mutated in persistence." + "$ref": "#/definitions/v1CallbackExecutionOutcome" } - }, - "description": "Information about a callback's execution." + } }, "v1CallbackExecutionOutcome": { "type": "object", @@ -14494,8 +14455,7 @@ "$ref": "#/definitions/v1Failure", "description": "The failure if the callback was not able to complete successfully. e.g. timed out, received an\nunretriable error, etc." } - }, - "description": "The outcome of a callback's execution, either success or a failure." + } }, "v1CallbackState": { "type": "string", @@ -14520,11 +14480,11 @@ }, "service": { "type": "string", - "description": "Target Nexus service, e.g. \"temporal.api.notificationservice.v1.NotificationService\"." + "description": "Target Nexus service, e.g. \"HTTPAdaptor\"." }, "operation": { "type": "string", - "description": "Target operation, e.g. \"OnComplete\"." + "description": "Target operation, e.g. \"DeliverAsWebhook\"." }, "sourceContext": { "$ref": "#/definitions/v1Payload", @@ -16553,10 +16513,25 @@ }, "workflow": { "$ref": "#/definitions/LinkWorkflow" + }, + "callback": { + "$ref": "#/definitions/v1LinkCallback" } }, "description": "Link can be associated with history events. It might contain information about an external entity\nrelated to the history event. For example, workflow A makes a Nexus call that starts workflow B:\nin this case, a history event in workflow A could contain a Link to the workflow started event in\nworkflow B, and vice-versa." }, + "v1LinkCallback": { + "type": "object", + "properties": { + "callbackId": { + "type": "string" + }, + "nexusOperationCompletion": { + "$ref": "#/definitions/CallbackNexusOperationCompletion" + } + }, + "description": "A link to a callback or completion handler for an operation. e.g. not a link to a standalone Nexus operation,\nbut the callback that was executed once that operation finished." + }, "v1ListActivityExecutionsResponse": { "type": "object", "properties": { @@ -18536,7 +18511,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Callback" + "$ref": "#/definitions/commonV1Callback" }, "description": "Callbacks to be called by the server when this update reaches a terminal state." }, @@ -21376,7 +21351,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Callback" + "$ref": "#/definitions/commonV1Callback" }, "description": "Completion callbacks attached to the running workflow execution." }, @@ -21592,7 +21567,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Callback" + "$ref": "#/definitions/commonV1Callback" }, "description": "Completion callbacks attached when this workflow was started." }, diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 51949d6cc..ad214c8d8 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -10764,73 +10764,10 @@ components: callbackId: type: string description: Identifier of the callback's execution. Unique within the containing namespace. - runId: - type: string - description: Run ID of the callback execution. - callback: - allOf: - - $ref: '#/components/schemas/Callback' - description: The Callback being described. - state: - enum: - - CALLBACK_STATE_UNSPECIFIED - - CALLBACK_STATE_STANDBY - - CALLBACK_STATE_SCHEDULED - - CALLBACK_STATE_BACKING_OFF - - CALLBACK_STATE_FAILED - - CALLBACK_STATE_SUCCEEDED - - CALLBACK_STATE_BLOCKED - type: string - description: The detailed state of the callback. - format: enum - stateReason: - type: string - description: |- - Human friendly context describing the state, if applicable. - e.g. if the state is BLOCKED, provides an explanation why. + info: + $ref: '#/components/schemas/CallbackInfo' outcome: - allOf: - - $ref: '#/components/schemas/CallbackExecutionOutcome' - description: The outcome of the callback's execution, as applicable. - attempt: - type: integer - description: |- - The number of attempts made to deliver/execute callback. - - This number is approximate. There could be more attempts if the server crashes before recording the attempt's completion, or fewer - if the callback was terminated or timed out after the counter has been incremented and before an attempt could be made. - format: int32 - createTime: - type: string - description: The time when the callback was created. (But not necessarily scheduled.) - format: date-time - closeTime: - type: string - description: Time when the callback transitioned to a terminal state. - format: date-time - lastAttemptCompleteTime: - type: string - description: The time when the last attempt completed. - format: date-time - lastAttemptFailure: - allOf: - - $ref: '#/components/schemas/Failure' - description: The last attempt's failure, if any. - nextAttemptScheduleTime: - type: string - description: The time when the next attempt is scheduled (only set when state is BACKING_OFF). - format: date-time - scheduleToCloseTimeout: - pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ - type: string - description: |- - Schedule-to-close timeout for this callback. - (-- api-linter: core::0140::prepositions=disabled - aip.dev/not-precedent: "to" is used to indicate interval. --) - stateTransitionCount: - type: string - description: Incremented each time the callback's state is mutated in persistence. - description: Information about a callback's execution. + $ref: '#/components/schemas/CallbackExecutionOutcome' CallbackExecutionOutcome: type: object properties: @@ -10840,7 +10777,6 @@ components: description: |- The failure if the callback was not able to complete successfully. e.g. timed out, received an unretriable error, etc. - description: The outcome of a callback's execution, either success or a failure. CallbackInfo: type: object properties: @@ -10909,6 +10845,15 @@ components: additionalProperties: type: string description: Header to attach to callback request. + Callback_NexusOperationCompletion: + type: object + properties: + operationId: + type: string + runId: + type: string + requestId: + type: string Callback_Worker: type: object properties: @@ -10920,10 +10865,10 @@ components: NOTE: This is not a temporal.api.taskqueue.v1.TaskQueue to avoid a circular dependency. service: type: string - description: Target Nexus service, e.g. "temporal.api.notificationservice.v1.NotificationService". + description: Target Nexus service, e.g. "HTTPAdaptor". operation: type: string - description: Target operation, e.g. "OnComplete". + description: Target operation, e.g. "DeliverAsWebhook". sourceContext: allOf: - $ref: '#/components/schemas/Payload' @@ -12969,6 +12914,8 @@ components: $ref: '#/components/schemas/Link_NexusOperation' workflow: $ref: '#/components/schemas/Link_Workflow' + callback: + $ref: '#/components/schemas/Link_Callback' description: |- Link can be associated with history events. It might contain information about an external entity related to the history event. For example, workflow A makes a Nexus call that starts workflow B: @@ -12993,6 +12940,16 @@ components: A link to a built-in batch job. Batch jobs can be used to perform operations on a set of workflows (e.g. terminate, signal, cancel, etc). This link can be put on workflow history events generated by actions taken by a batch job. + Link_Callback: + type: object + properties: + callbackId: + type: string + nexusOperationCompletion: + $ref: '#/components/schemas/Callback_NexusOperationCompletion' + description: |- + A link to a callback or completion handler for an operation. e.g. not a link to a standalone Nexus operation, + but the callback that was executed once that operation finished. Link_NexusOperation: type: object properties: diff --git a/temporal/api/callback/v1/message.proto b/temporal/api/callback/v1/message.proto index f881a4eef..47cc020c8 100644 --- a/temporal/api/callback/v1/message.proto +++ b/temporal/api/callback/v1/message.proto @@ -9,6 +9,7 @@ option java_outer_classname = "MessageProto"; option ruby_package = "Temporalio::Api::Callback::V1"; option csharp_namespace = "Temporalio.Api.Callback.V1"; +import "google/protobuf/empty.proto"; import "google/protobuf/timestamp.proto"; import "temporal/api/common/v1/message.proto"; @@ -34,4 +35,23 @@ message CallbackInfo { google.protobuf.Timestamp next_attempt_schedule_time = 7; // If the state is BLOCKED, blocked reason provides additional information. string blocked_reason = 8; -} \ No newline at end of file +} + +message CallbackExecutionOutcome { + oneof value { + // The callback completed successfully. (Which may include delivering a "failed" result successfully.) + google.protobuf.Empty success = 1; + // The failure if the callback was not able to complete successfully. e.g. timed out, received an + // unretriable error, etc. + temporal.api.failure.v1.Failure failure = 2; + } +} + +message CallbackExecutionInfo { + // Identifier of the callback's execution. Unique within the containing namespace. + string callback_id = 1; + + CallbackInfo info = 2; + CallbackExecutionOutcome outcome = 3; +} + diff --git a/temporal/api/common/v1/message.proto b/temporal/api/common/v1/message.proto index 6b8098286..0b6a1a360 100644 --- a/temporal/api/common/v1/message.proto +++ b/temporal/api/common/v1/message.proto @@ -219,9 +219,9 @@ message Callback { // NOTE: This is not a temporal.api.taskqueue.v1.TaskQueue to avoid a circular dependency. string task_queue_name = 1; - // Target Nexus service, e.g. "temporal.api.notificationservice.v1.NotificationService". + // Target Nexus service, e.g. "HTTPAdaptor". string service = 2; - // Target operation, e.g. "OnComplete". + // Target operation, e.g. "DeliverAsWebhook". string operation = 3; // Arbitrary user-supplied data from the source operation's callsite. (As applicable, not all operations diff --git a/temporal/api/notificationservice/v1/request_response.proto b/temporal/api/notificationservice/v1/request_response.proto index 26e9d53dc..edf861c77 100644 --- a/temporal/api/notificationservice/v1/request_response.proto +++ b/temporal/api/notificationservice/v1/request_response.proto @@ -14,28 +14,13 @@ import "temporal/api/failure/v1/message.proto"; // OnCompleteRequest is the request type to the NotificationService's OnComplete operation, // allowing for defining completion handlers for arbitrary asynchronous operations. +// +// Information about the source operation will be available in the form of a commonpb.Link, +// which will be available separately from this OnCompleteRequest. e.g. a link to the source +// standalone Nexus operation would be found in the nexuspb.StartOperationRequest parameter +// sent to the worker callback. (In addition to this OnCompleteRequest.) message OnCompleteRequest { - // The source Nexus operation that the OnComplete invocation is reporting. - message NexusOperation { - // The Nexus endpoint. - string endpoint = 1; - // The Nexus service. - string service = 2; - // The Nexus operation. - string operation = 3; - - // The token the operation produced. (If it was an asynchronous Nexus operation.) - string operation_token = 4; - } - - // The source asynchronous operation. - message SourceOperation { - oneof variant { - NexusOperation nexus_operation = 1; - } - } - // The outcome of the source operation. message Outcome { oneof result { @@ -45,12 +30,10 @@ message OnCompleteRequest { temporal.api.failure.v1.Failure failure = 2; } } - - SourceOperation source_operation = 1; - Outcome outcome = 2; + Outcome outcome = 1; // User-supplied data which was added to the source invocation. (As applicable.) - temporal.api.common.v1.Payload source_context = 3; + temporal.api.common.v1.Payload source_context = 2; } // OnCompleteResponse is the return type of the OnComplete operation. diff --git a/temporal/api/workflowservice/v1/message.proto b/temporal/api/workflowservice/v1/message.proto deleted file mode 100644 index 73d12f90b..000000000 --- a/temporal/api/workflowservice/v1/message.proto +++ /dev/null @@ -1,74 +0,0 @@ -syntax = "proto3"; - -package temporal.api.workflowservice.v1; - -option go_package = "go.temporal.io/api/workflowservice/v1;workflowservice"; -option java_package = "io.temporal.api.workflowservice.v1"; -option java_multiple_files = true; -option java_outer_classname = "MessageProto"; -option ruby_package = "Temporalio::Api::WorkflowService::V1"; -option csharp_namespace = "Temporalio.Api.WorkflowService.V1"; - -import "google/protobuf/duration.proto"; -import "google/protobuf/empty.proto"; -import "google/protobuf/timestamp.proto"; - -import "temporal/api/common/v1/message.proto"; -import "temporal/api/enums/v1/common.proto"; -import "temporal/api/failure/v1/message.proto"; - -// The outcome of a callback's execution, either success or a failure. -message CallbackExecutionOutcome { - oneof value { - // The callback completed successfully. (Which may include delivering a "failed" result successfully.) - google.protobuf.Empty success = 1; - // The failure if the callback was not able to complete successfully. e.g. timed out, received an - // unretriable error, etc. - temporal.api.failure.v1.Failure failure = 2; - } -} - -// Information about a callback's execution. -message CallbackExecutionInfo { - // Identifier of the callback's execution. Unique within the containing namespace. - string callback_id = 1; - // Run ID of the callback execution. - string run_id = 2; - - // The Callback being described. - temporal.api.common.v1.Callback callback = 3; - // The detailed state of the callback. - temporal.api.enums.v1.CallbackState state = 4; - // Human friendly context describing the state, if applicable. - // e.g. if the state is BLOCKED, provides an explanation why. - string state_reason = 5; - - // The outcome of the callback's execution, as applicable. - CallbackExecutionOutcome outcome = 6; - - // The number of attempts made to deliver/execute callback. - // - // This number is approximate. There could be more attempts if the server crashes before recording the attempt's completion, or fewer - // if the callback was terminated or timed out after the counter has been incremented and before an attempt could be made. - int32 attempt = 7; - - // The time when the callback was created. (But not necessarily scheduled.) - google.protobuf.Timestamp create_time = 8; - // Time when the callback transitioned to a terminal state. - google.protobuf.Timestamp close_time = 9; - - // The time when the last attempt completed. - google.protobuf.Timestamp last_attempt_complete_time = 10; - // The last attempt's failure, if any. - temporal.api.failure.v1.Failure last_attempt_failure = 11; - // The time when the next attempt is scheduled (only set when state is BACKING_OFF). - google.protobuf.Timestamp next_attempt_schedule_time = 12; - - // Schedule-to-close timeout for this callback. - // (-- api-linter: core::0140::prepositions=disabled - // aip.dev/not-precedent: "to" is used to indicate interval. --) - google.protobuf.Duration schedule_to_close_timeout = 13; - - // Incremented each time the callback's state is mutated in persistence. - int64 state_transition_count = 14; -} diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index e6864d3c9..683d57bbf 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -22,6 +22,7 @@ import "temporal/api/enums/v1/update.proto"; import "temporal/api/enums/v1/activity.proto"; import "temporal/api/enums/v1/nexus.proto"; import "temporal/api/activity/v1/message.proto"; +import "temporal/api/callback/v1/message.proto"; import "temporal/api/common/v1/message.proto"; import "temporal/api/history/v1/message.proto"; import "temporal/api/workflow/v1/message.proto"; @@ -45,7 +46,6 @@ import "temporal/api/sdk/v1/task_complete_metadata.proto"; import "temporal/api/sdk/v1/user_metadata.proto"; import "temporal/api/nexus/v1/message.proto"; import "temporal/api/worker/v1/message.proto"; -import "temporal/api/workflowservice/v1/message.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/field_mask.proto"; @@ -3448,7 +3448,7 @@ message DescribeNexusOperationExecutionResponse { // Completion callbacks to be invoked once the Nexus operation reaches a terminal state. // They will remain in the CALLBACK_STATE_STANDBY state until the Nexus operation is finished. - repeated CallbackExecutionInfo completion_callbacks = 7; + repeated temporal.api.callback.v1.CallbackExecutionInfo completion_callbacks = 7; } message PollNexusOperationExecutionRequest { From 7278236b1964e6699f6eb067f3f38bf35d0b7ea1 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Fri, 24 Jul 2026 16:17:50 -0700 Subject: [PATCH 5/8] Apply suggestions from code review Co-authored-by: Roey Berman --- temporal/api/common/v1/message.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temporal/api/common/v1/message.proto b/temporal/api/common/v1/message.proto index 0b6a1a360..6bf391d26 100644 --- a/temporal/api/common/v1/message.proto +++ b/temporal/api/common/v1/message.proto @@ -219,7 +219,7 @@ message Callback { // NOTE: This is not a temporal.api.taskqueue.v1.TaskQueue to avoid a circular dependency. string task_queue_name = 1; - // Target Nexus service, e.g. "HTTPAdaptor". + // Target Nexus service, e.g. "HTTPAdapter". string service = 2; // Target operation, e.g. "DeliverAsWebhook". string operation = 3; From a344fad374f0651b3275b30912f0eccb79d63575 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Mon, 27 Jul 2026 10:32:12 -0700 Subject: [PATCH 6/8] Address PR feedback --- openapi/openapiv2.json | 146 +++++++++--------- openapi/openapiv3.yaml | 52 +++---- temporal/api/callback/v1/message.proto | 12 +- temporal/api/common/v1/message.proto | 22 +-- temporal/api/nexusoperation/v1/message.proto | 30 ++++ .../workflowservice/v1/request_response.proto | 4 +- 6 files changed, 138 insertions(+), 128 deletions(-) create mode 100644 temporal/api/nexusoperation/v1/message.proto diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index b596d4312..db8754cda 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -10717,6 +10717,10 @@ "type": "object", "description": "Trigger for when the activity is closed." }, + "CallbackInfoOperationCompleted": { + "type": "object", + "description": "Trigger for when the Nexus operation is completed, covering both success cases as\nwell as any type of failure." + }, "CallbackInfoUpdateWorkflowExecutionCompleted": { "type": "object", "properties": { @@ -10757,20 +10761,6 @@ } } }, - "CallbackNexusOperationCompletion": { - "type": "object", - "properties": { - "operationId": { - "type": "string" - }, - "runId": { - "type": "string" - }, - "requestId": { - "type": "string" - } - } - }, "ComputeStatusProviderValidationStatus": { "type": "object", "properties": { @@ -10906,6 +10896,21 @@ }, "description": "A link to a standalone Nexus operation." }, + "LinkNexusOperationCallback": { + "type": "object", + "properties": { + "operationId": { + "type": "string" + }, + "runId": { + "type": "string" + }, + "requestId": { + "type": "string" + } + }, + "description": "A link to a worker callback attached to a Nexus operation within the same namespace. e.g. the completion handler attached\nto a standalone Nexus operation, not the source Nexus operation itself. A standalone Nexus operation can have multiple\ncallbacks attached to them, and will be differentiated by the server-generated request_id used when the callback was invoked." + }, "LinkWorkflow": { "type": "object", "properties": { @@ -11290,7 +11295,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/commonV1Callback" + "$ref": "#/definitions/v1Callback" }, "description": "Completion callbacks attached to the running workflow update." } @@ -12316,7 +12321,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/commonV1Callback" + "$ref": "#/definitions/v1Callback" }, "description": "Callbacks to be called by the server when this activity reaches a terminal state.\nCallback addresses must be whitelisted in the server's dynamic configuration." }, @@ -12474,7 +12479,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/commonV1Callback" + "$ref": "#/definitions/v1Callback" }, "description": "Completion callbacks to be invoked once the Nexus operation reaches a terminal state." } @@ -12557,7 +12562,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/commonV1Callback" + "$ref": "#/definitions/v1Callback" }, "description": "Callbacks to be called by the server when this workflow reaches a terminal state.\nIf the workflow continues-as-new, these callbacks will be carried over to the new execution.\nCallback addresses must be whitelisted in the server's dynamic configuration." }, @@ -13101,7 +13106,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/commonV1Callback" + "$ref": "#/definitions/v1Callback" }, "description": "Callbacks to be called by the server when this update reaches a terminal state." }, @@ -13201,7 +13206,7 @@ "type": "object", "properties": { "callback": { - "$ref": "#/definitions/commonV1Callback", + "$ref": "#/definitions/v1Callback", "description": "Information on how this callback should be invoked (e.g. its URL and type)." }, "registrationTime": { @@ -13235,6 +13240,10 @@ "blockedReason": { "type": "string", "description": "If the state is BLOCKED, blocked reason provides additional information." + }, + "outcome": { + "$ref": "#/definitions/v1CallbackExecutionOutcome", + "description": "Result of the callback's execution, only set when the callback reaches a terminal state." } }, "description": "Common callback information. Specific CallbackInfo messages should embed this and may include additional fields." @@ -13257,11 +13266,33 @@ }, "description": "When starting an execution with a conflict policy that uses an existing execution and there is already an existing\nrunning execution, OnConflictOptions defines actions to be taken on the existing running execution." }, + "apiNexusoperationV1CallbackInfo": { + "type": "object", + "properties": { + "trigger": { + "$ref": "#/definitions/apiNexusoperationV1CallbackInfoTrigger", + "description": "Trigger for this callback." + }, + "info": { + "$ref": "#/definitions/apiCallbackV1CallbackInfo", + "description": "Common callback info." + } + }, + "description": "CallbackInfo contains the state of a callback attached to a standalone Nexus operation." + }, + "apiNexusoperationV1CallbackInfoTrigger": { + "type": "object", + "properties": { + "operationCompleted": { + "$ref": "#/definitions/CallbackInfoOperationCompleted" + } + } + }, "apiWorkflowV1CallbackInfo": { "type": "object", "properties": { "callback": { - "$ref": "#/definitions/commonV1Callback", + "$ref": "#/definitions/v1Callback", "description": "Information on how this callback should be invoked (e.g. its URL and type)." }, "trigger": { @@ -13331,29 +13362,6 @@ }, "description": "When StartWorkflowExecution uses the conflict policy WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING and\nthere is already an existing running workflow, OnConflictOptions defines actions to be taken on\nthe existing running workflow. In this case, it will create a WorkflowExecutionOptionsUpdatedEvent\nhistory event in the running workflow with the changes requested in this object." }, - "commonV1Callback": { - "type": "object", - "properties": { - "nexus": { - "$ref": "#/definitions/CallbackNexus" - }, - "internal": { - "$ref": "#/definitions/CallbackInternal" - }, - "worker": { - "$ref": "#/definitions/v1CallbackWorker" - }, - "links": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Link" - }, - "description": "Links associated with the callback. It can be used to link to underlying resources of the\ncallback." - } - }, - "description": "Callback to attach to various events in the system, e.g. workflow run completion." - }, "protobufAny": { "type": "object", "properties": { @@ -14428,20 +14436,28 @@ }, "description": "CalendarSpec describes an event specification relative to the calendar,\nsimilar to a traditional cron specification, but with labeled fields. Each\nfield can be one of:\n *: matches always\n x: matches when the field equals x\n x/y : matches when the field equals x+n*y where n is an integer\n x-z: matches when the field is between x and z inclusive\n w,x,y,...: matches when the field is one of the listed values\nEach x, y, z, ... is either a decimal integer, or a month or day of week name\nor abbreviation (in the appropriate fields).\nA timestamp matches if all fields match.\nNote that fields have different default values, for convenience.\nNote that the special case that some cron implementations have for treating\nday_of_month and day_of_week as \"or\" instead of \"and\" when both are set is\nnot implemented.\nday_of_week can accept 0 or 7 as Sunday\nCalendarSpec gets compiled into StructuredCalendarSpec, which is what will be\nreturned if you describe the schedule." }, - "v1CallbackExecutionInfo": { + "v1Callback": { "type": "object", "properties": { - "callbackId": { - "type": "string", - "description": "Identifier of the callback's execution. Unique within the containing namespace." + "nexus": { + "$ref": "#/definitions/CallbackNexus" }, - "info": { - "$ref": "#/definitions/apiCallbackV1CallbackInfo" + "internal": { + "$ref": "#/definitions/CallbackInternal" }, - "outcome": { - "$ref": "#/definitions/v1CallbackExecutionOutcome" + "worker": { + "$ref": "#/definitions/v1CallbackWorker" + }, + "links": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Link" + }, + "description": "Links associated with the callback. It can be used to link to underlying resources of the\ncallback." } - } + }, + "description": "Callback to attach to various events in the system, e.g. workflow run completion." }, "v1CallbackExecutionOutcome": { "type": "object", @@ -15423,7 +15439,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1CallbackExecutionInfo" + "$ref": "#/definitions/apiNexusoperationV1CallbackInfo" }, "description": "Completion callbacks to be invoked once the Nexus operation reaches a terminal state.\nThey will remain in the CALLBACK_STATE_STANDBY state until the Nexus operation is finished." } @@ -16514,24 +16530,12 @@ "workflow": { "$ref": "#/definitions/LinkWorkflow" }, - "callback": { - "$ref": "#/definitions/v1LinkCallback" + "nexusOperationCallback": { + "$ref": "#/definitions/LinkNexusOperationCallback" } }, "description": "Link can be associated with history events. It might contain information about an external entity\nrelated to the history event. For example, workflow A makes a Nexus call that starts workflow B:\nin this case, a history event in workflow A could contain a Link to the workflow started event in\nworkflow B, and vice-versa." }, - "v1LinkCallback": { - "type": "object", - "properties": { - "callbackId": { - "type": "string" - }, - "nexusOperationCompletion": { - "$ref": "#/definitions/CallbackNexusOperationCompletion" - } - }, - "description": "A link to a callback or completion handler for an operation. e.g. not a link to a standalone Nexus operation,\nbut the callback that was executed once that operation finished." - }, "v1ListActivityExecutionsResponse": { "type": "object", "properties": { @@ -18511,7 +18515,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/commonV1Callback" + "$ref": "#/definitions/v1Callback" }, "description": "Callbacks to be called by the server when this update reaches a terminal state." }, @@ -21351,7 +21355,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/commonV1Callback" + "$ref": "#/definitions/v1Callback" }, "description": "Completion callbacks attached to the running workflow execution." }, @@ -21567,7 +21571,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/commonV1Callback" + "$ref": "#/definitions/v1Callback" }, "description": "Completion callbacks attached when this workflow was started." }, diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index ad214c8d8..2da664c0b 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -10758,16 +10758,6 @@ components: Links associated with the callback. It can be used to link to underlying resources of the callback. description: Callback to attach to various events in the system, e.g. workflow run completion. - CallbackExecutionInfo: - type: object - properties: - callbackId: - type: string - description: Identifier of the callback's execution. Unique within the containing namespace. - info: - $ref: '#/components/schemas/CallbackInfo' - outcome: - $ref: '#/components/schemas/CallbackExecutionOutcome' CallbackExecutionOutcome: type: object properties: @@ -10821,6 +10811,10 @@ components: blockedReason: type: string description: If the state is BLOCKED, blocked reason provides additional information. + outcome: + allOf: + - $ref: '#/components/schemas/CallbackExecutionOutcome' + description: Result of the callback's execution, only set when the callback reaches a terminal state. description: Common callback information. Specific CallbackInfo messages should embed this and may include additional fields. Callback_Internal: type: object @@ -10845,15 +10839,6 @@ components: additionalProperties: type: string description: Header to attach to callback request. - Callback_NexusOperationCompletion: - type: object - properties: - operationId: - type: string - runId: - type: string - requestId: - type: string Callback_Worker: type: object properties: @@ -11877,7 +11862,7 @@ components: completionCallbacks: type: array items: - $ref: '#/components/schemas/CallbackExecutionInfo' + $ref: '#/components/schemas/CallbackInfo' description: |- Completion callbacks to be invoked once the Nexus operation reaches a terminal state. They will remain in the CALLBACK_STATE_STANDBY state until the Nexus operation is finished. @@ -12914,8 +12899,8 @@ components: $ref: '#/components/schemas/Link_NexusOperation' workflow: $ref: '#/components/schemas/Link_Workflow' - callback: - $ref: '#/components/schemas/Link_Callback' + nexusOperationCallback: + $ref: '#/components/schemas/Link_NexusOperationCallback' description: |- Link can be associated with history events. It might contain information about an external entity related to the history event. For example, workflow A makes a Nexus call that starts workflow B: @@ -12940,16 +12925,6 @@ components: A link to a built-in batch job. Batch jobs can be used to perform operations on a set of workflows (e.g. terminate, signal, cancel, etc). This link can be put on workflow history events generated by actions taken by a batch job. - Link_Callback: - type: object - properties: - callbackId: - type: string - nexusOperationCompletion: - $ref: '#/components/schemas/Callback_NexusOperationCompletion' - description: |- - A link to a callback or completion handler for an operation. e.g. not a link to a standalone Nexus operation, - but the callback that was executed once that operation finished. Link_NexusOperation: type: object properties: @@ -12960,6 +12935,19 @@ components: runId: type: string description: A link to a standalone Nexus operation. + Link_NexusOperationCallback: + type: object + properties: + operationId: + type: string + runId: + type: string + requestId: + type: string + description: |- + A link to a worker callback attached to a Nexus operation within the same namespace. e.g. the completion handler attached + to a standalone Nexus operation, not the source Nexus operation itself. A standalone Nexus operation can have multiple + callbacks attached to them, and will be differentiated by the server-generated request_id used when the callback was invoked. Link_Workflow: type: object properties: diff --git a/temporal/api/callback/v1/message.proto b/temporal/api/callback/v1/message.proto index 47cc020c8..bede6e318 100644 --- a/temporal/api/callback/v1/message.proto +++ b/temporal/api/callback/v1/message.proto @@ -35,6 +35,9 @@ message CallbackInfo { google.protobuf.Timestamp next_attempt_schedule_time = 7; // If the state is BLOCKED, blocked reason provides additional information. string blocked_reason = 8; + + // Result of the callback's execution, only set when the callback reaches a terminal state. + CallbackExecutionOutcome outcome = 9; } message CallbackExecutionOutcome { @@ -46,12 +49,3 @@ message CallbackExecutionOutcome { temporal.api.failure.v1.Failure failure = 2; } } - -message CallbackExecutionInfo { - // Identifier of the callback's execution. Unique within the containing namespace. - string callback_id = 1; - - CallbackInfo info = 2; - CallbackExecutionOutcome outcome = 3; -} - diff --git a/temporal/api/common/v1/message.proto b/temporal/api/common/v1/message.proto index 6bf391d26..e7f2c291c 100644 --- a/temporal/api/common/v1/message.proto +++ b/temporal/api/common/v1/message.proto @@ -304,19 +304,13 @@ message Link { string reason = 4; } - // A link to a callback or completion handler for an operation. e.g. not a link to a standalone Nexus operation, - // but the callback that was executed once that operation finished. - message Callback { - message NexusOperationCompletion { - string operation_id = 1; - string run_id = 2; - string request_id = 3; - } - - string callback_id = 1; - oneof variant { - NexusOperationCompletion nexus_operation_completion = 2; - } + // A link to a worker callback attached to a Nexus operation within the same namespace. e.g. the completion handler attached + // to a standalone Nexus operation, not the source Nexus operation itself. A standalone Nexus operation can have multiple + // callbacks attached to them, and will be differentiated by the server-generated request_id used when the callback was invoked. + message NexusOperationCallback { + string operation_id = 1; + string run_id = 2; + string request_id = 3; } oneof variant { @@ -325,7 +319,7 @@ message Link { Activity activity = 3; NexusOperation nexus_operation = 4; Workflow workflow = 5; - Callback callback = 6; + NexusOperationCallback nexus_operation_callback = 6; } } diff --git a/temporal/api/nexusoperation/v1/message.proto b/temporal/api/nexusoperation/v1/message.proto new file mode 100644 index 000000000..52d6c53a6 --- /dev/null +++ b/temporal/api/nexusoperation/v1/message.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +package temporal.api.nexusoperation.v1; + +option go_package = "go.temporal.io/api/nexusoperation/v1;nexusoperation"; +option java_package = "io.temporal.api.nexusoperation.v1"; +option java_multiple_files = true; +option java_outer_classname = "MessageProto"; +option ruby_package = "Temporalio::Api::NexusOperation::V1"; +option csharp_namespace = "Temporalio.Api.NexusOperation.V1"; + +import "temporal/api/callback/v1/message.proto"; + +// CallbackInfo contains the state of a callback attached to a standalone Nexus operation. +message CallbackInfo { + // Trigger for when the Nexus operation is completed, covering both success cases as + // well as any type of failure. + message OperationCompleted {} + + message Trigger { + oneof variant { + OperationCompleted operation_completed = 1; + } + } + + // Trigger for this callback. + Trigger trigger = 1; + // Common callback info. + temporal.api.callback.v1.CallbackInfo info = 2; +} diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index 683d57bbf..05eaf784a 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -22,7 +22,6 @@ import "temporal/api/enums/v1/update.proto"; import "temporal/api/enums/v1/activity.proto"; import "temporal/api/enums/v1/nexus.proto"; import "temporal/api/activity/v1/message.proto"; -import "temporal/api/callback/v1/message.proto"; import "temporal/api/common/v1/message.proto"; import "temporal/api/history/v1/message.proto"; import "temporal/api/workflow/v1/message.proto"; @@ -45,6 +44,7 @@ import "temporal/api/batch/v1/message.proto"; import "temporal/api/sdk/v1/task_complete_metadata.proto"; import "temporal/api/sdk/v1/user_metadata.proto"; import "temporal/api/nexus/v1/message.proto"; +import "temporal/api/nexusoperation/v1/message.proto"; import "temporal/api/worker/v1/message.proto"; import "google/protobuf/duration.proto"; @@ -3448,7 +3448,7 @@ message DescribeNexusOperationExecutionResponse { // Completion callbacks to be invoked once the Nexus operation reaches a terminal state. // They will remain in the CALLBACK_STATE_STANDBY state until the Nexus operation is finished. - repeated temporal.api.callback.v1.CallbackExecutionInfo completion_callbacks = 7; + repeated temporal.api.nexusoperation.v1.CallbackInfo completion_callbacks = 7; } message PollNexusOperationExecutionRequest { From bfe8090281b293f543cd1a223f12765d4d693e33 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Mon, 27 Jul 2026 11:55:13 -0700 Subject: [PATCH 7/8] Add temporal.api.nexusoperation.v1.OnConflictOptions to start SANO request --- openapi/openapiv2.json | 20 ++++++++++++++++++- openapi/openapiv3.yaml | 9 ++++++++- temporal/api/nexusoperation/v1/message.proto | 12 +++++++++++ .../workflowservice/v1/request_response.proto | 6 +++++- 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index db8754cda..2f020a07d 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -12460,6 +12460,10 @@ "$ref": "#/definitions/v1NexusOperationIdConflictPolicy", "description": "Defines how to resolve an operation id conflict with a *running* operation.\nThe default policy is NEXUS_OPERATION_ID_CONFLICT_POLICY_FAIL." }, + "onConflictOptions": { + "$ref": "#/definitions/apiNexusoperationV1OnConflictOptions", + "description": "Defines actions to be done to the existing running standalone Nexus when the conflict policy\nNEXUS_OPERATION_ID_CONFLICT_POLICY_USE_EXISTING is used. If not set or set to a empty object\n(all options with default value), it won't do modify running operation." + }, "searchAttributes": { "$ref": "#/definitions/v1SearchAttributes", "description": "Search attributes for indexing." @@ -13288,6 +13292,20 @@ } } }, + "apiNexusoperationV1OnConflictOptions": { + "type": "object", + "properties": { + "attachCompletionCallbacks": { + "type": "boolean", + "description": "Attaches the completion callbacks to the running operation." + }, + "attachLinks": { + "type": "boolean", + "description": "Attaches the links to the WorkflowExecutionOptionsUpdatedEvent history event." + } + }, + "description": "When StartNexusOperationExecutionRequest uses the conflict policy NEXUS_OPERATION_ID_CONFLICT_POLICY_USE_EXISTING\nand there is already an existing, running standalone Nexus operation, OnConflictOptions defines actions to be\ntaken." + }, "apiWorkflowV1CallbackInfo": { "type": "object", "properties": { @@ -14496,7 +14514,7 @@ }, "service": { "type": "string", - "description": "Target Nexus service, e.g. \"HTTPAdaptor\"." + "description": "Target Nexus service, e.g. \"HTTPAdapter\"." }, "operation": { "type": "string", diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 2da664c0b..dd967d148 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -10850,7 +10850,7 @@ components: NOTE: This is not a temporal.api.taskqueue.v1.TaskQueue to avoid a circular dependency. service: type: string - description: Target Nexus service, e.g. "HTTPAdaptor". + description: Target Nexus service, e.g. "HTTPAdapter". operation: type: string description: Target operation, e.g. "DeliverAsWebhook". @@ -17114,6 +17114,13 @@ components: Defines how to resolve an operation id conflict with a *running* operation. The default policy is NEXUS_OPERATION_ID_CONFLICT_POLICY_FAIL. format: enum + onConflictOptions: + allOf: + - $ref: '#/components/schemas/OnConflictOptions' + description: |- + Defines actions to be done to the existing running standalone Nexus when the conflict policy + NEXUS_OPERATION_ID_CONFLICT_POLICY_USE_EXISTING is used. If not set or set to a empty object + (all options with default value), it won't do modify running operation. searchAttributes: allOf: - $ref: '#/components/schemas/SearchAttributes' diff --git a/temporal/api/nexusoperation/v1/message.proto b/temporal/api/nexusoperation/v1/message.proto index 52d6c53a6..f247013b0 100644 --- a/temporal/api/nexusoperation/v1/message.proto +++ b/temporal/api/nexusoperation/v1/message.proto @@ -28,3 +28,15 @@ message CallbackInfo { // Common callback info. temporal.api.callback.v1.CallbackInfo info = 2; } + +// When StartNexusOperationExecutionRequest uses the conflict policy NEXUS_OPERATION_ID_CONFLICT_POLICY_USE_EXISTING +// and there is already an existing, running standalone Nexus operation, OnConflictOptions defines actions to be +// taken. +message OnConflictOptions { + // Attaches the request ID to the running operation. + bool attach_request_id = 1; + // Attaches the completion callbacks to the running operation. + bool attach_completion_callbacks = 2; + // Attaches any new links to the running operation. + bool attach_links = 3; +} diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index 05eaf784a..15526ba74 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -3382,6 +3382,10 @@ message StartNexusOperationExecutionRequest { // Defines how to resolve an operation id conflict with a *running* operation. // The default policy is NEXUS_OPERATION_ID_CONFLICT_POLICY_FAIL. temporal.api.enums.v1.NexusOperationIdConflictPolicy id_conflict_policy = 13; + // Defines actions to be done to the existing running standalone Nexus when the conflict policy + // NEXUS_OPERATION_ID_CONFLICT_POLICY_USE_EXISTING is used. If not set or set to a empty object + // (all options with default value), it won't do modify running operation. + temporal.api.nexusoperation.v1.OnConflictOptions on_conflict_options = 17; // Search attributes for indexing. temporal.api.common.v1.SearchAttributes search_attributes = 14; @@ -3396,7 +3400,7 @@ message StartNexusOperationExecutionRequest { temporal.api.sdk.v1.UserMetadata user_metadata = 16; // Completion callbacks to be invoked once the Nexus operation reaches a terminal state. - repeated temporal.api.common.v1.Callback completion_callbacks = 17; + repeated temporal.api.common.v1.Callback completion_callbacks = 18; } message StartNexusOperationExecutionResponse { From 46a18be769d1b4d24bb6d01230f552e06de552b0 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Tue, 28 Jul 2026 09:56:17 -0700 Subject: [PATCH 8/8] Update temporal/api/callback/v1/message.proto Co-authored-by: Roey Berman --- temporal/api/callback/v1/message.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temporal/api/callback/v1/message.proto b/temporal/api/callback/v1/message.proto index bede6e318..7803d5a20 100644 --- a/temporal/api/callback/v1/message.proto +++ b/temporal/api/callback/v1/message.proto @@ -40,7 +40,7 @@ message CallbackInfo { CallbackExecutionOutcome outcome = 9; } -message CallbackExecutionOutcome { +message CallbackOutcome { oneof value { // The callback completed successfully. (Which may include delivering a "failed" result successfully.) google.protobuf.Empty success = 1;