From e2ed77ed213c94796ad70e7bec2acb39271b18c5 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Mon, 27 Apr 2026 11:19:12 -0700 Subject: [PATCH 1/6] Add Stand Alone Callbacks (rebase) --- openapi/openapiv2.json | 932 +++++++++++++++++- openapi/openapiv3.yaml | 855 +++++++++++++++- temporal/api/callback/v1/message.proto | 105 +- temporal/api/common/v1/message.proto | 2 + temporal/api/enums/v1/common.proto | 20 + temporal/api/errordetails/v1/message.proto | 7 + temporal/api/nexus/v1/message.proto | 2 + .../workflowservice/v1/request_response.proto | 140 +++ temporal/api/workflowservice/v1/service.proto | 83 ++ 9 files changed, 2090 insertions(+), 56 deletions(-) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 12d163654..eda75cec0 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -1435,6 +1435,303 @@ ] } }, + "/api/v1/namespaces/{namespace}/callback-count": { + "get": { + "summary": "CountCallbackExecutions is a visibility API to count callback executions in a specific namespace.", + "operationId": "CountCallbackExecutions2", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1CountCallbackExecutionsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "query", + "description": "Visibility query, see https://docs.temporal.io/list-filter for the syntax.", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "WorkflowService" + ] + } + }, + "/api/v1/namespaces/{namespace}/callbacks": { + "get": { + "summary": "ListCallbackExecutions is a visibility API to list callback executions in a specific namespace.", + "operationId": "ListCallbackExecutions2", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListCallbackExecutionsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "pageSize", + "description": "Max number of executions to return per page.", + "in": "query", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "nextPageToken", + "description": "Token returned in ListCallbackExecutionsResponse.", + "in": "query", + "required": false, + "type": "string", + "format": "byte" + }, + { + "name": "query", + "description": "Visibility query, see https://docs.temporal.io/list-filter for the syntax.", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "WorkflowService" + ] + } + }, + "/api/v1/namespaces/{namespace}/callbacks/{callbackId}": { + "get": { + "summary": "DescribeCallbackExecution returns information about a callback execution.", + "description": "It can be used to:\n- Get current callback info without waiting\n- Long-poll for next state change and return new callback info\n\nResponse can optionally include the outcome if the callback has completed.", + "operationId": "DescribeCallbackExecution2", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1DescribeCallbackExecutionResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "callbackId", + "description": "Identifier for the callback", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "runId", + "description": "Run ID of the callback execution to describe. If empty, the latest run will be described.", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "includeInput", + "description": "Include the input field in the response.", + "in": "query", + "required": false, + "type": "boolean" + }, + { + "name": "includeOutcome", + "description": "Include the outcome (result/failure) in the response if the callback has completed.", + "in": "query", + "required": false, + "type": "boolean" + }, + { + "name": "longPollToken", + "description": "Token from a previous DescribeCallbackExecutionResponse. If present, long-poll until callback\nstate changes from the state encoded in this token. If absent, return current state immediately.\nNote that callback state may change multiple times between requests, therefore it is not\nguaranteed that a client making a sequence of long-poll requests will see a complete\nsequence of state changes.", + "in": "query", + "required": false, + "type": "string", + "format": "byte" + } + ], + "tags": [ + "WorkflowService" + ] + }, + "post": { + "summary": "StartCallbackExecution starts a new standalone callback execution.", + "description": "Returns a `CallbackExecutionAlreadyStarted` error if a callback already exists with the same\ncallback ID in this namespace, either in running or terminal states.", + "operationId": "StartCallbackExecution2", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1StartCallbackExecutionResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "callbackId", + "description": "Identifier for this callback. Required. Must be unique among callbacks in the same namespace.\nIf a callback with this ID already exists, the request will fail with CallbackExecutionAlreadyStarted.", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/WorkflowServiceStartCallbackExecutionBody" + } + } + ], + "tags": [ + "WorkflowService" + ] + } + }, + "/api/v1/namespaces/{namespace}/callbacks/{callbackId}/outcome": { + "get": { + "summary": "PollCallbackExecution long-polls for a callback execution to complete and returns the outcome.", + "operationId": "PollCallbackExecution2", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1PollCallbackExecutionResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "callbackId", + "description": "Identifier for the callback", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "runId", + "description": "Run ID of the callback execution to poll. If empty, the latest run will be polled.", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "WorkflowService" + ] + } + }, + "/api/v1/namespaces/{namespace}/callbacks/{callbackId}/terminate": { + "post": { + "summary": "TerminateCallbackExecution terminates an existing callback execution immediately.", + "description": "Termination happens immediately. A terminated callback will have its state set to\nCALLBACK_STATE_TERMINATED.", + "operationId": "TerminateCallbackExecution2", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1TerminateCallbackExecutionResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "callbackId", + "description": "Identifier for the callback", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/WorkflowServiceTerminateCallbackExecutionBody" + } + } + ], + "tags": [ + "WorkflowService" + ] + } + }, "/api/v1/namespaces/{namespace}/current-deployment/{deployment.seriesName}": { "post": { "summary": "Sets a deployment as the current deployment for its deployment series. Can optionally update\nthe metadata of the deployment as well.\nExperimental. This API might significantly change or be removed in a future release.\nDeprecated. Replaced by `SetWorkerDeploymentCurrentVersion`.", @@ -6894,7 +7191,306 @@ "200": { "description": "A successful response.", "schema": { - "$ref": "#/definitions/v1StartBatchOperationResponse" + "$ref": "#/definitions/v1StartBatchOperationResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "namespace", + "description": "Namespace that contains the batch operation", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "jobId", + "description": "Job ID defines the unique ID for the batch job", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/WorkflowServiceStartBatchOperationBody" + } + } + ], + "tags": [ + "WorkflowService" + ] + } + }, + "/namespaces/{namespace}/batch-operations/{jobId}/stop": { + "post": { + "summary": "StopBatchOperation stops a batch operation", + "operationId": "StopBatchOperation", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1StopBatchOperationResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "namespace", + "description": "Namespace that contains the batch operation", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "jobId", + "description": "Batch job id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/WorkflowServiceStopBatchOperationBody" + } + } + ], + "tags": [ + "WorkflowService" + ] + } + }, + "/namespaces/{namespace}/callback-count": { + "get": { + "summary": "CountCallbackExecutions is a visibility API to count callback executions in a specific namespace.", + "operationId": "CountCallbackExecutions", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1CountCallbackExecutionsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "query", + "description": "Visibility query, see https://docs.temporal.io/list-filter for the syntax.", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "WorkflowService" + ] + } + }, + "/namespaces/{namespace}/callbacks": { + "get": { + "summary": "ListCallbackExecutions is a visibility API to list callback executions in a specific namespace.", + "operationId": "ListCallbackExecutions", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListCallbackExecutionsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "pageSize", + "description": "Max number of executions to return per page.", + "in": "query", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "nextPageToken", + "description": "Token returned in ListCallbackExecutionsResponse.", + "in": "query", + "required": false, + "type": "string", + "format": "byte" + }, + { + "name": "query", + "description": "Visibility query, see https://docs.temporal.io/list-filter for the syntax.", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "WorkflowService" + ] + } + }, + "/namespaces/{namespace}/callbacks/{callbackId}": { + "get": { + "summary": "DescribeCallbackExecution returns information about a callback execution.", + "description": "It can be used to:\n- Get current callback info without waiting\n- Long-poll for next state change and return new callback info\n\nResponse can optionally include the outcome if the callback has completed.", + "operationId": "DescribeCallbackExecution", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1DescribeCallbackExecutionResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "callbackId", + "description": "Identifier for the callback", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "runId", + "description": "Run ID of the callback execution to describe. If empty, the latest run will be described.", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "includeInput", + "description": "Include the input field in the response.", + "in": "query", + "required": false, + "type": "boolean" + }, + { + "name": "includeOutcome", + "description": "Include the outcome (result/failure) in the response if the callback has completed.", + "in": "query", + "required": false, + "type": "boolean" + }, + { + "name": "longPollToken", + "description": "Token from a previous DescribeCallbackExecutionResponse. If present, long-poll until callback\nstate changes from the state encoded in this token. If absent, return current state immediately.\nNote that callback state may change multiple times between requests, therefore it is not\nguaranteed that a client making a sequence of long-poll requests will see a complete\nsequence of state changes.", + "in": "query", + "required": false, + "type": "string", + "format": "byte" + } + ], + "tags": [ + "WorkflowService" + ] + }, + "post": { + "summary": "StartCallbackExecution starts a new standalone callback execution.", + "description": "Returns a `CallbackExecutionAlreadyStarted` error if a callback already exists with the same\ncallback ID in this namespace, either in running or terminal states.", + "operationId": "StartCallbackExecution", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1StartCallbackExecutionResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "callbackId", + "description": "Identifier for this callback. Required. Must be unique among callbacks in the same namespace.\nIf a callback with this ID already exists, the request will fail with CallbackExecutionAlreadyStarted.", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/WorkflowServiceStartCallbackExecutionBody" + } + } + ], + "tags": [ + "WorkflowService" + ] + } + }, + "/namespaces/{namespace}/callbacks/{callbackId}/outcome": { + "get": { + "summary": "PollCallbackExecution long-polls for a callback execution to complete and returns the outcome.", + "operationId": "PollCallbackExecution", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1PollCallbackExecutionResponse" } }, "default": { @@ -6907,25 +7503,23 @@ "parameters": [ { "name": "namespace", - "description": "Namespace that contains the batch operation", "in": "path", "required": true, "type": "string" }, { - "name": "jobId", - "description": "Job ID defines the unique ID for the batch job", + "name": "callbackId", + "description": "Identifier for the callback", "in": "path", "required": true, "type": "string" }, { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/WorkflowServiceStartBatchOperationBody" - } + "name": "runId", + "description": "Run ID of the callback execution to poll. If empty, the latest run will be polled.", + "in": "query", + "required": false, + "type": "string" } ], "tags": [ @@ -6933,15 +7527,16 @@ ] } }, - "/namespaces/{namespace}/batch-operations/{jobId}/stop": { + "/namespaces/{namespace}/callbacks/{callbackId}/terminate": { "post": { - "summary": "StopBatchOperation stops a batch operation", - "operationId": "StopBatchOperation", + "summary": "TerminateCallbackExecution terminates an existing callback execution immediately.", + "description": "Termination happens immediately. A terminated callback will have its state set to\nCALLBACK_STATE_TERMINATED.", + "operationId": "TerminateCallbackExecution", "responses": { "200": { "description": "A successful response.", "schema": { - "$ref": "#/definitions/v1StopBatchOperationResponse" + "$ref": "#/definitions/v1TerminateCallbackExecutionResponse" } }, "default": { @@ -6954,14 +7549,13 @@ "parameters": [ { "name": "namespace", - "description": "Namespace that contains the batch operation", "in": "path", "required": true, "type": "string" }, { - "name": "jobId", - "description": "Batch job id", + "name": "callbackId", + "description": "Identifier for the callback", "in": "path", "required": true, "type": "string" @@ -6971,7 +7565,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/WorkflowServiceStopBatchOperationBody" + "$ref": "#/definitions/WorkflowServiceTerminateCallbackExecutionBody" } } ], @@ -10627,6 +11221,10 @@ "type": "string" }, "description": "Header to attach to callback request." + }, + "token": { + "type": "string", + "description": "Standard token to use for identifying the callback, used for completion." } } }, @@ -12181,6 +12779,35 @@ } } }, + "WorkflowServiceStartCallbackExecutionBody": { + "type": "object", + "properties": { + "identity": { + "type": "string", + "description": "The identity of the client who initiated this request." + }, + "requestId": { + "type": "string", + "description": "A unique identifier for this start request. Typically UUIDv4." + }, + "callback": { + "$ref": "#/definitions/v1Callback", + "description": "Information on how this callback should be invoked (e.g. its URL and type)." + }, + "scheduleToCloseTimeout": { + "type": "string", + "description": "Schedule-to-close timeout for this callback." + }, + "searchAttributes": { + "$ref": "#/definitions/v1SearchAttributes", + "description": "Search attributes for indexing." + }, + "completion": { + "$ref": "#/definitions/v1CallbackExecutionCompletion", + "description": "The Nexus completion data to deliver to the callback URL.\nContains either a successful result payload or a failure." + } + } + }, "WorkflowServiceStartNexusOperationExecutionBody": { "type": "object", "properties": { @@ -12394,6 +13021,27 @@ } } }, + "WorkflowServiceTerminateCallbackExecutionBody": { + "type": "object", + "properties": { + "runId": { + "type": "string", + "description": "Run ID of the callback execution to terminate. If empty, the latest run will be terminated." + }, + "identity": { + "type": "string", + "description": "The identity of the worker/client." + }, + "requestId": { + "type": "string", + "description": "Used to de-dupe termination requests." + }, + "reason": { + "type": "string", + "description": "Reason for requesting the termination." + } + } + }, "WorkflowServiceTerminateNexusOperationExecutionBody": { "type": "object", "properties": { @@ -14094,6 +14742,156 @@ }, "description": "Callback to attach to various events in the system, e.g. workflow run completion." }, + "v1CallbackExecutionCompletion": { + "type": "object", + "properties": { + "success": { + "$ref": "#/definitions/v1Payload", + "description": "Deliver a successful Nexus operation completion with this result payload.\nIf set, the callback delivers a successful completion to the target URL." + }, + "failure": { + "$ref": "#/definitions/v1Failure", + "description": "Deliver a failed Nexus operation completion with this failure.\nIf set, the callback delivers a failed completion to the target URL.\nIf CanceledFailureInfo is set, the target operation is resolved is canceled instead of failed." + } + }, + "description": "The Nexus completion data that a standalone callback execution will deliver to its target URL.\nExactly one of success or failure should be set." + }, + "v1CallbackExecutionInfo": { + "type": "object", + "properties": { + "callbackId": { + "type": "string", + "description": "Unique identifier of this callback within its namespace." + }, + "runId": { + "type": "string", + "description": "Run ID of the callback execution." + }, + "callback": { + "$ref": "#/definitions/v1Callback", + "description": "Information on how this callback should be invoked (e.g. its URL and type)." + }, + "status": { + "$ref": "#/definitions/v1CallbackExecutionStatus", + "description": "A general status for this callback, indicates whether it is currently running or in one of the terminal statuses." + }, + "state": { + "$ref": "#/definitions/v1CallbackState", + "description": "The detailed state of this callback, provides more granular information than the general status." + }, + "attempt": { + "type": "integer", + "format": "int32", + "description": "The number of attempts made to deliver the callback.\nThis number represents a minimum bound since the attempt is incremented after the callback request completes." + }, + "createTime": { + "type": "string", + "format": "date-time", + "description": "The time when the callback was created/scheduled." + }, + "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." + }, + "blockedReason": { + "type": "string", + "description": "If the state is BLOCKED, provides additional information." + }, + "closeTime": { + "type": "string", + "format": "date-time", + "description": "Time when the callback transitioned to a terminal state." + }, + "searchAttributes": { + "$ref": "#/definitions/v1SearchAttributes", + "description": "Search attributes for indexing." + }, + "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 standalone callback execution." + }, + "v1CallbackExecutionListInfo": { + "type": "object", + "properties": { + "callbackId": { + "type": "string", + "description": "Unique identifier of this callback within its namespace." + }, + "runId": { + "type": "string", + "description": "Run ID of the callback execution." + }, + "status": { + "$ref": "#/definitions/v1CallbackExecutionStatus", + "description": "Only running and terminal statuses appear here. More detailed information in CallbackExecutionInfo but not\navailable in the list response." + }, + "createTime": { + "type": "string", + "format": "date-time", + "description": "The time when the callback was created/scheduled." + }, + "closeTime": { + "type": "string", + "format": "date-time", + "description": "Time when the callback transitioned to a terminal state." + }, + "searchAttributes": { + "$ref": "#/definitions/v1SearchAttributes", + "description": "Search attributes from the start request." + }, + "stateTransitionCount": { + "type": "string", + "format": "int64", + "description": "Incremented each time the callback's state is mutated." + } + }, + "description": "Limited callback information returned in the list response." + }, + "v1CallbackExecutionOutcome": { + "type": "object", + "properties": { + "success": { + "type": "object", + "properties": {}, + "description": "The callback completed successfully." + }, + "failure": { + "$ref": "#/definitions/v1Failure", + "description": "The failure if the callback completed unsuccessfully." + } + }, + "description": "The outcome of a completed callback execution: either success or a failure." + }, + "v1CallbackExecutionStatus": { + "type": "string", + "enum": [ + "CALLBACK_EXECUTION_STATUS_UNSPECIFIED", + "CALLBACK_EXECUTION_STATUS_RUNNING", + "CALLBACK_EXECUTION_STATUS_SUCCEEDED", + "CALLBACK_EXECUTION_STATUS_FAILED", + "CALLBACK_EXECUTION_STATUS_TERMINATED" + ], + "default": "CALLBACK_EXECUTION_STATUS_UNSPECIFIED", + "description": "Status of a callback execution.\nThe status is only updated twice. First, when the callback is scheduled. And second, when the\ncallback reaches a terminal status.\n\n - CALLBACK_EXECUTION_STATUS_UNSPECIFIED: Default value, unspecified status.\n - CALLBACK_EXECUTION_STATUS_RUNNING: Callback execution is running.\n - CALLBACK_EXECUTION_STATUS_SUCCEEDED: Callback has succeeded.\n - CALLBACK_EXECUTION_STATUS_FAILED: Callback has failed.\n - CALLBACK_EXECUTION_STATUS_TERMINATED: Callback was terminated via TerminateCallbackExecution." + }, "v1CallbackState": { "type": "string", "enum": [ @@ -14103,10 +14901,11 @@ "CALLBACK_STATE_BACKING_OFF", "CALLBACK_STATE_FAILED", "CALLBACK_STATE_SUCCEEDED", - "CALLBACK_STATE_BLOCKED" + "CALLBACK_STATE_BLOCKED", + "CALLBACK_STATE_TERMINATED" ], "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 (eg: by circuit breaker).\n - CALLBACK_STATE_TERMINATED: Callback was terminated via TerminateCallbackExecution. Only possible for standalone callbacks." }, "v1CancelExternalWorkflowExecutionFailedCause": { "type": "string", @@ -14545,6 +15344,40 @@ } } }, + "v1CountCallbackExecutionsResponse": { + "type": "object", + "properties": { + "count": { + "type": "string", + "format": "int64", + "description": "If `query` is not grouping by any field, the count is an approximate number\nof callbacks that match the query.\nIf `query` is grouping by a field, the count is simply the sum of the counts\nof the groups returned in the response. This number can be smaller than the\ntotal number of callbacks matching the query." + }, + "groups": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1CountCallbackExecutionsResponseAggregationGroup" + }, + "description": "Contains the groups if the request is grouping by a field.\nThe list might not be complete, and the counts of each group is approximate." + } + } + }, + "v1CountCallbackExecutionsResponseAggregationGroup": { + "type": "object", + "properties": { + "groupValues": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Payload" + } + }, + "count": { + "type": "string", + "format": "int64" + } + } + }, "v1CountNexusOperationExecutionsResponse": { "type": "object", "properties": { @@ -14922,6 +15755,24 @@ } } }, + "v1DescribeCallbackExecutionResponse": { + "type": "object", + "properties": { + "info": { + "$ref": "#/definitions/v1CallbackExecutionInfo", + "description": "Information about the callback execution." + }, + "outcome": { + "$ref": "#/definitions/v1CallbackExecutionOutcome", + "description": "Only set if the callback is completed and include_outcome was true in the request." + }, + "longPollToken": { + "type": "string", + "format": "byte", + "description": "Token for follow-on long-poll requests. Absent only if the callback is complete." + } + } + }, "v1DescribeDeploymentResponse": { "type": "object", "properties": { @@ -16046,6 +16897,23 @@ } } }, + "v1ListCallbackExecutionsResponse": { + "type": "object", + "properties": { + "executions": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1CallbackExecutionListInfo" + } + }, + "nextPageToken": { + "type": "string", + "format": "byte", + "description": "Token to use to fetch the next page. If empty, there is no next page." + } + } + }, "v1ListDeploymentsResponse": { "type": "object", "properties": { @@ -17477,6 +18345,18 @@ } } }, + "v1PollCallbackExecutionResponse": { + "type": "object", + "properties": { + "runId": { + "type": "string", + "description": "The run ID of the callback, useful when run_id was not specified in the request." + }, + "outcome": { + "$ref": "#/definitions/v1CallbackExecutionOutcome" + } + } + }, "v1PollNexusOperationExecutionResponse": { "type": "object", "properties": { @@ -18837,6 +19717,15 @@ "v1StartBatchOperationResponse": { "type": "object" }, + "v1StartCallbackExecutionResponse": { + "type": "object", + "properties": { + "runId": { + "type": "string", + "description": "The run ID of the callback that was started." + } + } + }, "v1StartChildWorkflowExecutionFailedCause": { "type": "string", "enum": [ @@ -19331,6 +20220,9 @@ "v1TerminateActivityExecutionResponse": { "type": "object" }, + "v1TerminateCallbackExecutionResponse": { + "type": "object" + }, "v1TerminateNexusOperationExecutionResponse": { "type": "object" }, diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 14a6a130c..f17f2df9a 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -1307,6 +1307,261 @@ paths: application/json: schema: $ref: '#/components/schemas/Status' + /api/v1/namespaces/{namespace}/callback-count: + get: + tags: + - WorkflowService + description: CountCallbackExecutions is a visibility API to count callback executions in a specific namespace. + operationId: CountCallbackExecutions + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: query + in: query + description: Visibility query, see https://docs.temporal.io/list-filter for the syntax. + schema: + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/CountCallbackExecutionsResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + /api/v1/namespaces/{namespace}/callbacks: + get: + tags: + - WorkflowService + description: ListCallbackExecutions is a visibility API to list callback executions in a specific namespace. + operationId: ListCallbackExecutions + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: pageSize + in: query + description: Max number of executions to return per page. + schema: + type: integer + format: int32 + - name: nextPageToken + in: query + description: Token returned in ListCallbackExecutionsResponse. + schema: + type: string + format: bytes + - name: query + in: query + description: Visibility query, see https://docs.temporal.io/list-filter for the syntax. + schema: + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/ListCallbackExecutionsResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + /api/v1/namespaces/{namespace}/callbacks/{callbackId}: + get: + tags: + - WorkflowService + description: |- + DescribeCallbackExecution returns information about a callback execution. + + It can be used to: + - Get current callback info without waiting + - Long-poll for next state change and return new callback info + + Response can optionally include the outcome if the callback has completed. + operationId: DescribeCallbackExecution + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: callbackId + in: path + description: Identifier for the callback + required: true + schema: + type: string + - name: runId + in: query + description: Run ID of the callback execution to describe. If empty, the latest run will be described. + schema: + type: string + - name: includeInput + in: query + description: Include the input field in the response. + schema: + type: boolean + - name: includeOutcome + in: query + description: Include the outcome (result/failure) in the response if the callback has completed. + schema: + type: boolean + - name: longPollToken + in: query + description: |- + Token from a previous DescribeCallbackExecutionResponse. If present, long-poll until callback + state changes from the state encoded in this token. If absent, return current state immediately. + Note that callback state may change multiple times between requests, therefore it is not + guaranteed that a client making a sequence of long-poll requests will see a complete + sequence of state changes. + schema: + type: string + format: bytes + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/DescribeCallbackExecutionResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + post: + tags: + - WorkflowService + description: |- + StartCallbackExecution starts a new standalone callback execution. + + Returns a `CallbackExecutionAlreadyStarted` error if a callback already exists with the same + callback ID in this namespace, either in running or terminal states. + operationId: StartCallbackExecution + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: callbackId + in: path + description: |- + Identifier for this callback. Required. Must be unique among callbacks in the same namespace. + If a callback with this ID already exists, the request will fail with CallbackExecutionAlreadyStarted. + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/StartCallbackExecutionRequest' + required: true + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/StartCallbackExecutionResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + /api/v1/namespaces/{namespace}/callbacks/{callbackId}/outcome: + get: + tags: + - WorkflowService + description: PollCallbackExecution long-polls for a callback execution to complete and returns the outcome. + operationId: PollCallbackExecution + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: callbackId + in: path + description: Identifier for the callback + required: true + schema: + type: string + - name: runId + in: query + description: Run ID of the callback execution to poll. If empty, the latest run will be polled. + schema: + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/PollCallbackExecutionResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + /api/v1/namespaces/{namespace}/callbacks/{callbackId}/terminate: + post: + tags: + - WorkflowService + description: |- + TerminateCallbackExecution terminates an existing callback execution immediately. + + Termination happens immediately. A terminated callback will have its state set to + CALLBACK_STATE_TERMINATED. + operationId: TerminateCallbackExecution + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: callbackId + in: path + description: Identifier for the callback + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TerminateCallbackExecutionRequest' + required: true + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/TerminateCallbackExecutionResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' /api/v1/namespaces/{namespace}/current-deployment/{deployment.series_name}: post: tags: @@ -6180,13 +6435,256 @@ paths: type: string - name: pageSize in: query - description: List page size + description: List page size + schema: + type: integer + format: int32 + - name: nextPageToken + in: query + description: Next page token + schema: + type: string + format: bytes + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/ListBatchOperationsResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + /namespaces/{namespace}/batch-operations/{jobId}: + get: + tags: + - WorkflowService + description: DescribeBatchOperation returns the information about a batch operation + operationId: DescribeBatchOperation + parameters: + - name: namespace + in: path + description: Namespace that contains the batch operation + required: true + schema: + type: string + - name: jobId + in: path + description: Batch job id + required: true + schema: + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/DescribeBatchOperationResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + post: + tags: + - WorkflowService + description: StartBatchOperation starts a new batch operation + operationId: StartBatchOperation + parameters: + - name: namespace + in: path + description: Namespace that contains the batch operation + required: true + schema: + type: string + - name: jobId + in: path + description: Job ID defines the unique ID for the batch job + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/StartBatchOperationRequest' + required: true + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/StartBatchOperationResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + /namespaces/{namespace}/batch-operations/{jobId}/stop: + post: + tags: + - WorkflowService + description: StopBatchOperation stops a batch operation + operationId: StopBatchOperation + parameters: + - name: namespace + in: path + description: Namespace that contains the batch operation + required: true + schema: + type: string + - name: jobId + in: path + description: Batch job id + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/StopBatchOperationRequest' + required: true + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/StopBatchOperationResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + /namespaces/{namespace}/callback-count: + get: + tags: + - WorkflowService + description: CountCallbackExecutions is a visibility API to count callback executions in a specific namespace. + operationId: CountCallbackExecutions + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: query + in: query + description: Visibility query, see https://docs.temporal.io/list-filter for the syntax. + schema: + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/CountCallbackExecutionsResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + /namespaces/{namespace}/callbacks: + get: + tags: + - WorkflowService + description: ListCallbackExecutions is a visibility API to list callback executions in a specific namespace. + operationId: ListCallbackExecutions + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: pageSize + in: query + description: Max number of executions to return per page. + schema: + type: integer + format: int32 + - name: nextPageToken + in: query + description: Token returned in ListCallbackExecutionsResponse. + schema: + type: string + format: bytes + - name: query + in: query + description: Visibility query, see https://docs.temporal.io/list-filter for the syntax. + schema: + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/ListCallbackExecutionsResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + /namespaces/{namespace}/callbacks/{callbackId}: + get: + tags: + - WorkflowService + description: |- + DescribeCallbackExecution returns information about a callback execution. + + It can be used to: + - Get current callback info without waiting + - Long-poll for next state change and return new callback info + + Response can optionally include the outcome if the callback has completed. + operationId: DescribeCallbackExecution + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: callbackId + in: path + description: Identifier for the callback + required: true + schema: + type: string + - name: runId + in: query + description: Run ID of the callback execution to describe. If empty, the latest run will be described. + schema: + type: string + - name: includeInput + in: query + description: Include the input field in the response. + schema: + type: boolean + - name: includeOutcome + in: query + description: Include the outcome (result/failure) in the response if the callback has completed. schema: - type: integer - format: int32 - - name: nextPageToken + type: boolean + - name: longPollToken in: query - description: Next page token + description: |- + Token from a previous DescribeCallbackExecutionResponse. If present, long-poll until callback + state changes from the state encoded in this token. If absent, return current state immediately. + Note that callback state may change multiple times between requests, therefore it is not + guaranteed that a client making a sequence of long-poll requests will see a complete + sequence of state changes. schema: type: string format: bytes @@ -6196,98 +6694,110 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ListBatchOperationsResponse' + $ref: '#/components/schemas/DescribeCallbackExecutionResponse' default: description: Default error response content: application/json: schema: $ref: '#/components/schemas/Status' - /namespaces/{namespace}/batch-operations/{jobId}: - get: + post: tags: - WorkflowService - description: DescribeBatchOperation returns the information about a batch operation - operationId: DescribeBatchOperation + description: |- + StartCallbackExecution starts a new standalone callback execution. + + Returns a `CallbackExecutionAlreadyStarted` error if a callback already exists with the same + callback ID in this namespace, either in running or terminal states. + operationId: StartCallbackExecution parameters: - name: namespace in: path - description: Namespace that contains the batch operation required: true schema: type: string - - name: jobId + - name: callbackId in: path - description: Batch job id + description: |- + Identifier for this callback. Required. Must be unique among callbacks in the same namespace. + If a callback with this ID already exists, the request will fail with CallbackExecutionAlreadyStarted. required: true schema: type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/StartCallbackExecutionRequest' + required: true responses: "200": description: OK content: application/json: schema: - $ref: '#/components/schemas/DescribeBatchOperationResponse' + $ref: '#/components/schemas/StartCallbackExecutionResponse' default: description: Default error response content: application/json: schema: $ref: '#/components/schemas/Status' - post: + /namespaces/{namespace}/callbacks/{callbackId}/outcome: + get: tags: - WorkflowService - description: StartBatchOperation starts a new batch operation - operationId: StartBatchOperation + description: PollCallbackExecution long-polls for a callback execution to complete and returns the outcome. + operationId: PollCallbackExecution parameters: - name: namespace in: path - description: Namespace that contains the batch operation required: true schema: type: string - - name: jobId + - name: callbackId in: path - description: Job ID defines the unique ID for the batch job + description: Identifier for the callback required: true schema: type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/StartBatchOperationRequest' - required: true + - name: runId + in: query + description: Run ID of the callback execution to poll. If empty, the latest run will be polled. + schema: + type: string responses: "200": description: OK content: application/json: schema: - $ref: '#/components/schemas/StartBatchOperationResponse' + $ref: '#/components/schemas/PollCallbackExecutionResponse' default: description: Default error response content: application/json: schema: $ref: '#/components/schemas/Status' - /namespaces/{namespace}/batch-operations/{jobId}/stop: + /namespaces/{namespace}/callbacks/{callbackId}/terminate: post: tags: - WorkflowService - description: StopBatchOperation stops a batch operation - operationId: StopBatchOperation + description: |- + TerminateCallbackExecution terminates an existing callback execution immediately. + + Termination happens immediately. A terminated callback will have its state set to + CALLBACK_STATE_TERMINATED. + operationId: TerminateCallbackExecution parameters: - name: namespace in: path - description: Namespace that contains the batch operation required: true schema: type: string - - name: jobId + - name: callbackId in: path - description: Batch job id + description: Identifier for the callback required: true schema: type: string @@ -6295,7 +6805,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/StopBatchOperationRequest' + $ref: '#/components/schemas/TerminateCallbackExecutionRequest' required: true responses: "200": @@ -6303,7 +6813,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/StopBatchOperationResponse' + $ref: '#/components/schemas/TerminateCallbackExecutionResponse' default: description: Default error response content: @@ -10555,6 +11065,150 @@ 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. + CallbackExecutionCompletion: + type: object + properties: + success: + allOf: + - $ref: '#/components/schemas/Payload' + description: |- + Deliver a successful Nexus operation completion with this result payload. + If set, the callback delivers a successful completion to the target URL. + failure: + allOf: + - $ref: '#/components/schemas/Failure' + description: |- + Deliver a failed Nexus operation completion with this failure. + If set, the callback delivers a failed completion to the target URL. + If CanceledFailureInfo is set, the target operation is resolved is canceled instead of failed. + description: |- + The Nexus completion data that a standalone callback execution will deliver to its target URL. + Exactly one of success or failure should be set. + CallbackExecutionInfo: + type: object + properties: + callbackId: + type: string + description: Unique identifier of this callback within its namespace. + runId: + type: string + description: Run ID of the callback execution. + callback: + allOf: + - $ref: '#/components/schemas/Callback' + description: Information on how this callback should be invoked (e.g. its URL and type). + status: + enum: + - CALLBACK_EXECUTION_STATUS_UNSPECIFIED + - CALLBACK_EXECUTION_STATUS_RUNNING + - CALLBACK_EXECUTION_STATUS_SUCCEEDED + - CALLBACK_EXECUTION_STATUS_FAILED + - CALLBACK_EXECUTION_STATUS_TERMINATED + type: string + description: A general status for this callback, indicates whether it is currently running or in one of the terminal statuses. + format: enum + state: + enum: + - CALLBACK_STATE_UNSPECIFIED + - CALLBACK_STATE_STANDBY + - CALLBACK_STATE_SCHEDULED + - CALLBACK_STATE_BACKING_OFF + - CALLBACK_STATE_FAILED + - CALLBACK_STATE_SUCCEEDED + - CALLBACK_STATE_BLOCKED + - CALLBACK_STATE_TERMINATED + type: string + description: The detailed state of this callback, provides more granular information than the general status. + format: enum + attempt: + type: integer + description: |- + 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. + format: int32 + createTime: + type: string + description: The time when the callback was created/scheduled. + 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. + format: date-time + blockedReason: + type: string + description: If the state is BLOCKED, provides additional information. + closeTime: + type: string + description: Time when the callback transitioned to a terminal state. + format: date-time + searchAttributes: + allOf: + - $ref: '#/components/schemas/SearchAttributes' + description: Search attributes for indexing. + 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 standalone callback execution. + CallbackExecutionListInfo: + type: object + properties: + callbackId: + type: string + description: Unique identifier of this callback within its namespace. + runId: + type: string + description: Run ID of the callback execution. + status: + enum: + - CALLBACK_EXECUTION_STATUS_UNSPECIFIED + - CALLBACK_EXECUTION_STATUS_RUNNING + - CALLBACK_EXECUTION_STATUS_SUCCEEDED + - CALLBACK_EXECUTION_STATUS_FAILED + - CALLBACK_EXECUTION_STATUS_TERMINATED + type: string + description: |- + Only running and terminal statuses appear here. More detailed information in CallbackExecutionInfo but not + available in the list response. + format: enum + createTime: + type: string + description: The time when the callback was created/scheduled. + format: date-time + closeTime: + type: string + description: Time when the callback transitioned to a terminal state. + format: date-time + searchAttributes: + allOf: + - $ref: '#/components/schemas/SearchAttributes' + description: Search attributes from the start request. + stateTransitionCount: + type: string + description: Incremented each time the callback's state is mutated. + description: Limited callback information returned in the list response. + CallbackExecutionOutcome: + type: object + properties: + failure: + allOf: + - $ref: '#/components/schemas/Failure' + description: The failure if the callback completed unsuccessfully. + description: 'The outcome of a completed callback execution: either success or a failure.' CallbackInfo: type: object properties: @@ -10575,6 +11229,7 @@ components: - CALLBACK_STATE_FAILED - CALLBACK_STATE_SUCCEEDED - CALLBACK_STATE_BLOCKED + - CALLBACK_STATE_TERMINATED type: string description: The current state of the callback. format: enum @@ -10623,6 +11278,9 @@ components: additionalProperties: type: string description: Header to attach to callback request. + token: + type: string + description: Standard token to use for identifying the callback, used for completion. CanceledFailureInfo: type: object properties: @@ -11033,6 +11691,33 @@ components: $ref: '#/components/schemas/Payload' count: type: string + CountCallbackExecutionsResponse: + type: object + properties: + count: + type: string + description: |- + If `query` is not grouping by any field, the count is an approximate number + of callbacks that match the query. + If `query` is grouping by a field, the count is simply the sum of the counts + of the groups returned in the response. This number can be smaller than the + total number of callbacks matching the query. + groups: + type: array + items: + $ref: '#/components/schemas/CountCallbackExecutionsResponse_AggregationGroup' + description: |- + Contains the groups if the request is grouping by a field. + The list might not be complete, and the counts of each group is approximate. + CountCallbackExecutionsResponse_AggregationGroup: + type: object + properties: + groupValues: + type: array + items: + $ref: '#/components/schemas/Payload' + count: + type: string CountNexusOperationExecutionsResponse: type: object properties: @@ -11488,6 +12173,21 @@ components: reason: type: string description: Reason indicates the reason to stop a operation + DescribeCallbackExecutionResponse: + type: object + properties: + info: + allOf: + - $ref: '#/components/schemas/CallbackExecutionInfo' + description: Information about the callback execution. + outcome: + allOf: + - $ref: '#/components/schemas/CallbackExecutionOutcome' + description: Only set if the callback is completed and include_outcome was true in the request. + longPollToken: + type: string + description: Token for follow-on long-poll requests. Absent only if the callback is complete. + format: bytes DescribeDeploymentResponse: type: object properties: @@ -12568,6 +13268,17 @@ components: nextPageToken: type: string format: bytes + ListCallbackExecutionsResponse: + type: object + properties: + executions: + type: array + items: + $ref: '#/components/schemas/CallbackExecutionListInfo' + nextPageToken: + type: string + description: Token to use to fetch the next page. If empty, there is no next page. + format: bytes ListDeploymentsResponse: type: object properties: @@ -13983,6 +14694,14 @@ components: description: The run ID of the activity, useful when run_id was not specified in the request. outcome: $ref: '#/components/schemas/ActivityExecutionOutcome' + PollCallbackExecutionResponse: + type: object + properties: + runId: + type: string + description: The run ID of the callback, useful when run_id was not specified in the request. + outcome: + $ref: '#/components/schemas/CallbackExecutionOutcome' PollNexusOperationExecutionResponse: type: object properties: @@ -16387,6 +17106,49 @@ components: StartBatchOperationResponse: type: object properties: {} + StartCallbackExecutionRequest: + type: object + properties: + namespace: + type: string + identity: + type: string + description: The identity of the client who initiated this request. + requestId: + type: string + description: A unique identifier for this start request. Typically UUIDv4. + callbackId: + type: string + description: |- + Identifier for this callback. Required. Must be unique among callbacks in the same namespace. + If a callback with this ID already exists, the request will fail with CallbackExecutionAlreadyStarted. + callback: + allOf: + - $ref: '#/components/schemas/Callback' + description: Information on how this callback should be invoked (e.g. its URL and type). + 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. --) + searchAttributes: + allOf: + - $ref: '#/components/schemas/SearchAttributes' + description: Search attributes for indexing. + completion: + allOf: + - $ref: '#/components/schemas/CallbackExecutionCompletion' + description: |- + The Nexus completion data to deliver to the callback URL. + Contains either a successful result payload or a failure. + StartCallbackExecutionResponse: + type: object + properties: + runId: + type: string + description: The run ID of the callback that was started. StartChildWorkflowExecutionFailedEventAttributes: type: object properties: @@ -17124,6 +17886,29 @@ components: TerminateActivityExecutionResponse: type: object properties: {} + TerminateCallbackExecutionRequest: + type: object + properties: + namespace: + type: string + callbackId: + type: string + description: Identifier for the callback + runId: + type: string + description: Run ID of the callback execution to terminate. If empty, the latest run will be terminated. + identity: + type: string + description: The identity of the worker/client. + requestId: + type: string + description: Used to de-dupe termination requests. + reason: + type: string + description: Reason for requesting the termination. + TerminateCallbackExecutionResponse: + type: object + properties: {} TerminateNexusOperationExecutionRequest: type: object properties: diff --git a/temporal/api/callback/v1/message.proto b/temporal/api/callback/v1/message.proto index f881a4eef..e14cc70e7 100644 --- a/temporal/api/callback/v1/message.proto +++ b/temporal/api/callback/v1/message.proto @@ -9,12 +9,115 @@ option java_outer_classname = "MessageProto"; option ruby_package = "Temporalio::Api::Callback::V1"; option csharp_namespace = "Temporalio.Api.Callback.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 completed callback execution: either success or a failure. +message CallbackExecutionOutcome { + oneof value { + // The callback completed successfully. + google.protobuf.Empty success = 1; + // The failure if the callback completed unsuccessfully. + temporal.api.failure.v1.Failure failure = 2; + } +} + +// The Nexus completion data that a standalone callback execution will deliver to its target URL. +// Exactly one of success or failure should be set. +message CallbackExecutionCompletion { + oneof result { + // Deliver a successful Nexus operation completion with this result payload. + // If set, the callback delivers a successful completion to the target URL. + temporal.api.common.v1.Payload success = 1; + // Deliver a failed Nexus operation completion with this failure. + // If set, the callback delivers a failed completion to the target URL. + // If CanceledFailureInfo is set, the target operation is resolved is canceled instead of failed. + temporal.api.failure.v1.Failure failure = 2; + } +} + +// Information about a standalone callback execution. +message CallbackExecutionInfo { + // Unique identifier of this callback within its namespace. + string callback_id = 1; + + // Run ID of the callback execution. + string run_id = 2; + + // Information on how this callback should be invoked (e.g. its URL and type). + temporal.api.common.v1.Callback callback = 3; + + // A general status for this callback, indicates whether it is currently running or in one of the terminal statuses. + temporal.api.enums.v1.CallbackExecutionStatus status = 4; + + // The detailed state of this callback, provides more granular information than the general status. + 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. + int32 attempt = 6; + + // The time when the callback was created/scheduled. + google.protobuf.Timestamp create_time = 7; + + // The time when the last attempt completed. + google.protobuf.Timestamp last_attempt_complete_time = 8; + + // The last attempt's failure, if any. + temporal.api.failure.v1.Failure last_attempt_failure = 9; + + // The time when the next attempt is scheduled. + google.protobuf.Timestamp next_attempt_schedule_time = 10; + + // If the state is BLOCKED, provides additional information. + string blocked_reason = 11; + + // Time when the callback transitioned to a terminal state. + google.protobuf.Timestamp close_time = 12; + + // Search attributes for indexing. + temporal.api.common.v1.SearchAttributes search_attributes = 13; + + // 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 = 14; + + // Incremented each time the callback's state is mutated in persistence. + int64 state_transition_count = 15; +} + +// Limited callback information returned in the list response. +message CallbackExecutionListInfo { + // Unique identifier of this callback within its namespace. + string callback_id = 1; + + // Run ID of the callback execution. + string run_id = 2; + + // Only running and terminal statuses appear here. More detailed information in CallbackExecutionInfo but not + // available in the list response. + temporal.api.enums.v1.CallbackExecutionStatus status = 3; + + // The time when the callback was created/scheduled. + google.protobuf.Timestamp create_time = 4; + + // Time when the callback transitioned to a terminal state. + google.protobuf.Timestamp close_time = 5; + + // Search attributes from the start request. + temporal.api.common.v1.SearchAttributes search_attributes = 6; + + // Incremented each time the callback's state is mutated. + int64 state_transition_count = 7; +} + + // Common callback information. Specific CallbackInfo messages should embed this and may include additional fields. message CallbackInfo { // Information on how this callback should be invoked (e.g. its URL and type). @@ -34,4 +137,4 @@ 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 +} diff --git a/temporal/api/common/v1/message.proto b/temporal/api/common/v1/message.proto index 13d9d1dc8..0c292d84e 100644 --- a/temporal/api/common/v1/message.proto +++ b/temporal/api/common/v1/message.proto @@ -181,6 +181,8 @@ message Callback { string url = 1; // Header to attach to callback request. map header = 2; + // Standard token to use for identifying the callback, used for completion. + string token = 3; } // Callbacks to be delivered internally within the system. diff --git a/temporal/api/enums/v1/common.proto b/temporal/api/enums/v1/common.proto index 192c1d75b..30f1a0bed 100644 --- a/temporal/api/enums/v1/common.proto +++ b/temporal/api/enums/v1/common.proto @@ -49,6 +49,26 @@ enum CallbackState { CALLBACK_STATE_SUCCEEDED = 5; // 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; +} + +// Status of a callback execution. +// The status is only updated twice. First, when the callback is scheduled. And second, when the +// callback reaches a terminal status. +// (-- api-linter: core::0216::synonyms=disabled +// aip.dev/not-precedent: To be consistent with other enums like ActivityExecutionStatus. --) +enum CallbackExecutionStatus { + // Default value, unspecified status. + CALLBACK_EXECUTION_STATUS_UNSPECIFIED = 0; + // Callback execution is running. + CALLBACK_EXECUTION_STATUS_RUNNING = 1; + // Callback has succeeded. + CALLBACK_EXECUTION_STATUS_SUCCEEDED = 2; + // Callback has failed. + CALLBACK_EXECUTION_STATUS_FAILED = 3; + // Callback was terminated via TerminateCallbackExecution. + CALLBACK_EXECUTION_STATUS_TERMINATED = 4; } // State of a pending Nexus operation. diff --git a/temporal/api/errordetails/v1/message.proto b/temporal/api/errordetails/v1/message.proto index 2abb60db6..68063d3b1 100644 --- a/temporal/api/errordetails/v1/message.proto +++ b/temporal/api/errordetails/v1/message.proto @@ -130,6 +130,13 @@ message ActivityExecutionAlreadyStartedFailure { string run_id = 2; } +// An error indicating that a callback execution failed to start because a callback with the given +// callback ID already exists in this namespace. +message CallbackExecutionAlreadyStartedFailure { + string start_request_id = 1; + string run_id = 2; +} + // An error indicating that a Nexus operation failed to start. Returned when there is an existing operation with the // given operation ID, and the given ID reuse and conflict policies do not permit starting a new one or attaching to an // existing one. diff --git a/temporal/api/nexus/v1/message.proto b/temporal/api/nexus/v1/message.proto index ec03a2ac7..aff9c7bc1 100644 --- a/temporal/api/nexus/v1/message.proto +++ b/temporal/api/nexus/v1/message.proto @@ -64,6 +64,8 @@ message StartOperationRequest { map 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. + string callback_token = 8; } // A request to cancel an operation. diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index f4012c73d..b99b07e9d 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"; @@ -3544,3 +3545,142 @@ message DeleteNexusOperationExecutionRequest { message DeleteNexusOperationExecutionResponse { } + +message StartCallbackExecutionRequest { + string namespace = 1; + // The identity of the client who initiated this request. + string identity = 2; + // A unique identifier for this start request. Typically UUIDv4. + string request_id = 3; + // Identifier for this callback. Required. Must be unique among callbacks in the same namespace. + // If a callback with this ID already exists, the request will fail with CallbackExecutionAlreadyStarted. + string callback_id = 4; + // Information on how this callback should be invoked (e.g. its URL and type). + temporal.api.common.v1.Callback callback = 5; + // 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 = 6; + // Search attributes for indexing. + temporal.api.common.v1.SearchAttributes search_attributes = 7; + // The input data to deliver to the callback URL. + oneof input { + // The Nexus completion data to deliver to the callback URL. + // Contains either a successful result payload or a failure. + temporal.api.callback.v1.CallbackExecutionCompletion completion = 8; + } +} + +message StartCallbackExecutionResponse { + // The run ID of the callback that was started. + string run_id = 1; +} + +message DescribeCallbackExecutionRequest { + string namespace = 1; + // 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; + // Include the input field in the response. + bool include_input = 4; + // Include the outcome (result/failure) in the response if the callback has completed. + bool include_outcome = 5; + // Token from a previous DescribeCallbackExecutionResponse. If present, long-poll until callback + // state changes from the state encoded in this token. If absent, return current state immediately. + // Note that callback state may change multiple times between requests, therefore it is not + // guaranteed that a client making a sequence of long-poll requests will see a complete + // sequence of state changes. + bytes long_poll_token = 6; +} + +message DescribeCallbackExecutionResponse { + // Information about the callback execution. + temporal.api.callback.v1.CallbackExecutionInfo info = 1; + // Only set if the callback is completed and include_outcome was true in the request. + temporal.api.callback.v1.CallbackExecutionOutcome outcome = 2; + // Token for follow-on long-poll requests. Absent only if the callback is complete. + bytes long_poll_token = 3; +} + +message PollCallbackExecutionRequest { + string namespace = 1; + // Identifier for the callback + string callback_id = 2; + // Run ID of the callback execution to poll. If empty, the latest run will be polled. + string run_id = 3; +} + +message PollCallbackExecutionResponse { + // The run ID of the callback, useful when run_id was not specified in the request. + string run_id = 1; + temporal.api.callback.v1.CallbackExecutionOutcome outcome = 2; +} + +message ListCallbackExecutionsRequest { + string namespace = 1; + // Max number of executions to return per page. + 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. + string query = 4; +} + +message ListCallbackExecutionsResponse { + repeated temporal.api.callback.v1.CallbackExecutionListInfo executions = 1; + // Token to use to fetch the next page. If empty, there is no next page. + bytes next_page_token = 2; +} + +message CountCallbackExecutionsRequest { + string namespace = 1; + // Visibility query, see https://docs.temporal.io/list-filter for the syntax. + string query = 2; +} + +message CountCallbackExecutionsResponse { + // If `query` is not grouping by any field, the count is an approximate number + // of callbacks that match the query. + // If `query` is grouping by a field, the count is simply the sum of the counts + // of the groups returned in the response. This number can be smaller than the + // total number of callbacks matching the query. + int64 count = 1; + + // Contains the groups if the request is grouping by a field. + // The list might not be complete, and the counts of each group is approximate. + repeated AggregationGroup groups = 2; + + message AggregationGroup { + repeated temporal.api.common.v1.Payload group_values = 1; + int64 count = 2; + } +} + +message TerminateCallbackExecutionRequest { + string namespace = 1; + // Identifier for the callback + string callback_id = 2; + // Run ID of the callback execution to terminate. If empty, the latest run will be terminated. + string run_id = 3; + // The identity of the worker/client. + string identity = 4; + // Used to de-dupe termination requests. + string request_id = 5; + // Reason for requesting the termination. + string reason = 6; +} + +message TerminateCallbackExecutionResponse { +} + +message DeleteCallbackExecutionRequest { + string namespace = 1; + // Identifier for the callback + string callback_id = 2; + // Run ID of the callback execution to delete. If empty, the latest run will be deleted. + string run_id = 3; +} + +message DeleteCallbackExecutionResponse { +} diff --git a/temporal/api/workflowservice/v1/service.proto b/temporal/api/workflowservice/v1/service.proto index 49be10dfb..54b170e38 100644 --- a/temporal/api/workflowservice/v1/service.proto +++ b/temporal/api/workflowservice/v1/service.proto @@ -2026,4 +2026,87 @@ service WorkflowService { // (-- api-linter: core::0127::http-annotation=disabled // aip.dev/not-precedent: Nexus operation deletion not exposed to HTTP, users should use cancel or terminate. --) rpc DeleteNexusOperationExecution (DeleteNexusOperationExecutionRequest) returns (DeleteNexusOperationExecutionResponse) {} + + // StartCallbackExecution starts a new standalone callback execution. + // + // Returns a `CallbackExecutionAlreadyStarted` error if a callback already exists with the same + // callback ID in this namespace, either in running or terminal states. + rpc StartCallbackExecution (StartCallbackExecutionRequest) returns (StartCallbackExecutionResponse) { + option (google.api.http) = { + post: "/namespaces/{namespace}/callbacks/{callback_id}" + body: "*" + additional_bindings { + post: "/api/v1/namespaces/{namespace}/callbacks/{callback_id}" + body: "*" + } + }; + } + + // DescribeCallbackExecution returns information about a callback execution. + // + // It can be used to: + // - Get current callback info without waiting + // - Long-poll for next state change and return new callback info + // + // Response can optionally include the outcome if the callback has completed. + rpc DescribeCallbackExecution (DescribeCallbackExecutionRequest) returns (DescribeCallbackExecutionResponse) { + option (google.api.http) = { + get: "/namespaces/{namespace}/callbacks/{callback_id}" + additional_bindings { + get: "/api/v1/namespaces/{namespace}/callbacks/{callback_id}" + } + }; + } + + // PollCallbackExecution long-polls for a callback execution to complete and returns the outcome. + rpc PollCallbackExecution (PollCallbackExecutionRequest) returns (PollCallbackExecutionResponse) { + option (google.api.http) = { + get: "/namespaces/{namespace}/callbacks/{callback_id}/outcome" + additional_bindings { + get: "/api/v1/namespaces/{namespace}/callbacks/{callback_id}/outcome" + } + }; + } + + // ListCallbackExecutions is a visibility API to list callback executions in a specific namespace. + rpc ListCallbackExecutions (ListCallbackExecutionsRequest) returns (ListCallbackExecutionsResponse) { + option (google.api.http) = { + get: "/namespaces/{namespace}/callbacks" + additional_bindings { + get: "/api/v1/namespaces/{namespace}/callbacks" + } + }; + } + + // CountCallbackExecutions is a visibility API to count callback executions in a specific namespace. + rpc CountCallbackExecutions (CountCallbackExecutionsRequest) returns (CountCallbackExecutionsResponse) { + option (google.api.http) = { + get: "/namespaces/{namespace}/callback-count" + additional_bindings { + get: "/api/v1/namespaces/{namespace}/callback-count" + } + }; + } + + // TerminateCallbackExecution terminates an existing callback execution immediately. + // + // Termination happens immediately. A terminated callback will have its state set to + // CALLBACK_STATE_TERMINATED. + rpc TerminateCallbackExecution (TerminateCallbackExecutionRequest) returns (TerminateCallbackExecutionResponse) { + option (google.api.http) = { + post: "/namespaces/{namespace}/callbacks/{callback_id}/terminate" + body: "*" + additional_bindings { + post: "/api/v1/namespaces/{namespace}/callbacks/{callback_id}/terminate" + body: "*" + } + }; + } + + // DeleteCallbackExecution asynchronously deletes a callback execution. If the callback is + // running, it will be terminated before deletion. + // + // (-- api-linter: core::0127::http-annotation=disabled + // aip.dev/not-precedent: Callback deletion not exposed to HTTP, users should use cancel or terminate. --) + rpc DeleteCallbackExecution (DeleteCallbackExecutionRequest) returns (DeleteCallbackExecutionResponse) {} } From 5757dfe1b2cd7ac06c9b88f2d5038c312f6ed879 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Wed, 6 May 2026 13:28:06 -0700 Subject: [PATCH 2/6] Add missing DescribeCallbackExecutionResponse.input field --- temporal/api/errordetails/v1/message.proto | 1 + temporal/api/workflowservice/v1/request_response.proto | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/temporal/api/errordetails/v1/message.proto b/temporal/api/errordetails/v1/message.proto index 68063d3b1..7491b84d6 100644 --- a/temporal/api/errordetails/v1/message.proto +++ b/temporal/api/errordetails/v1/message.proto @@ -135,6 +135,7 @@ message ActivityExecutionAlreadyStartedFailure { message CallbackExecutionAlreadyStartedFailure { string start_request_id = 1; string run_id = 2; + string callback_id = 3; } // An error indicating that a Nexus operation failed to start. Returned when there is an existing operation with the diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index b99b07e9d..ea6fbc850 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -3597,10 +3597,12 @@ message DescribeCallbackExecutionRequest { message DescribeCallbackExecutionResponse { // Information about the callback execution. temporal.api.callback.v1.CallbackExecutionInfo info = 1; + // Only set if include_input was true in the request. + temporal.api.callback.v1.CallbackExecutionCompletion input = 2; // Only set if the callback is completed and include_outcome was true in the request. - temporal.api.callback.v1.CallbackExecutionOutcome outcome = 2; + temporal.api.callback.v1.CallbackExecutionOutcome outcome = 3; // Token for follow-on long-poll requests. Absent only if the callback is complete. - bytes long_poll_token = 3; + bytes long_poll_token = 4; } message PollCallbackExecutionRequest { From ad8f707fb46db9250d892951c6f17ca952c56438 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Thu, 7 May 2026 14:48:19 -0700 Subject: [PATCH 3/6] Update comment --- openapi/openapiv2.json | 6 +++++- openapi/openapiv3.yaml | 4 ++++ temporal/api/callback/v1/message.proto | 3 ++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index eda75cec0..66028b0a0 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -14871,7 +14871,7 @@ "success": { "type": "object", "properties": {}, - "description": "The callback completed successfully." + "title": "The callback completed successfully. (Which includes delivering\na Nexus operation that completed with a failure.)" }, "failure": { "$ref": "#/definitions/v1Failure", @@ -15762,6 +15762,10 @@ "$ref": "#/definitions/v1CallbackExecutionInfo", "description": "Information about the callback execution." }, + "input": { + "$ref": "#/definitions/v1CallbackExecutionCompletion", + "description": "Only set if include_input was true in the request." + }, "outcome": { "$ref": "#/definitions/v1CallbackExecutionOutcome", "description": "Only set if the callback is completed and include_outcome was true in the request." diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index f17f2df9a..7746bbf63 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -12180,6 +12180,10 @@ components: allOf: - $ref: '#/components/schemas/CallbackExecutionInfo' description: Information about the callback execution. + input: + allOf: + - $ref: '#/components/schemas/CallbackExecutionCompletion' + description: Only set if include_input was true in the request. outcome: allOf: - $ref: '#/components/schemas/CallbackExecutionOutcome' diff --git a/temporal/api/callback/v1/message.proto b/temporal/api/callback/v1/message.proto index e14cc70e7..cdb0d0e6c 100644 --- a/temporal/api/callback/v1/message.proto +++ b/temporal/api/callback/v1/message.proto @@ -20,7 +20,8 @@ import "temporal/api/failure/v1/message.proto"; // The outcome of a completed callback execution: either success or a failure. message CallbackExecutionOutcome { oneof value { - // The callback completed successfully. + // The callback completed successfully. (Which includes delivering + // a Nexus operation that completed with a failure.) google.protobuf.Empty success = 1; // The failure if the callback completed unsuccessfully. temporal.api.failure.v1.Failure failure = 2; From 7c4b67edf545110b09a64632eef0aabcaf02823e Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Wed, 13 May 2026 12:54:44 -0700 Subject: [PATCH 4/6] Address PR feedback --- openapi/openapiv2.json | 45 +++++++------- openapi/openapiv3.yaml | 61 ++++++++++++------- temporal/api/callback/v1/message.proto | 12 ++-- temporal/api/common/v1/message.proto | 1 + temporal/api/enums/v1/common.proto | 2 + temporal/api/errordetails/v1/message.proto | 3 +- temporal/api/nexus/v1/message.proto | 2 + .../workflowservice/v1/request_response.proto | 15 +++-- 8 files changed, 85 insertions(+), 56 deletions(-) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 66028b0a0..c99f7eee5 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -1462,7 +1462,7 @@ }, { "name": "query", - "description": "Visibility query, see https://docs.temporal.io/list-filter for the syntax.", + "description": "Visibility query, see https://docs.temporal.io/list-filter for the syntax.\nSearch attributes that are available:\n- ExecutionStatus", "in": "query", "required": false, "type": "string" @@ -1516,7 +1516,7 @@ }, { "name": "query", - "description": "Visibility query, see https://docs.temporal.io/list-filter for the syntax.", + "description": "Visibility query, see https://docs.temporal.io/list-filter for the syntax.\nSearch attributes that are available:\n- ExecutionStatus", "in": "query", "required": false, "type": "string" @@ -1555,7 +1555,7 @@ }, { "name": "callbackId", - "description": "Identifier for the callback", + "description": "Identifier for the callback.", "in": "path", "required": true, "type": "string" @@ -1583,7 +1583,7 @@ }, { "name": "longPollToken", - "description": "Token from a previous DescribeCallbackExecutionResponse. If present, long-poll until callback\nstate changes from the state encoded in this token. If absent, return current state immediately.\nNote that callback state may change multiple times between requests, therefore it is not\nguaranteed that a client making a sequence of long-poll requests will see a complete\nsequence of state changes.", + "description": "Token from a previous DescribeCallbackExecutionResponse. If present, long-poll until the callback\nstate changes from the state encoded in this token. If absent, return current state immediately.\nIf present, run_id must also be present.\nNote that callback state may change multiple times between requests, therefore it is not\nguaranteed that a client making a sequence of long-poll requests will see a complete\nsequence of state changes.", "in": "query", "required": false, "type": "string", @@ -1667,7 +1667,7 @@ }, { "name": "callbackId", - "description": "Identifier for the callback", + "description": "Identifier for the callback.", "in": "path", "required": true, "type": "string" @@ -1713,7 +1713,7 @@ }, { "name": "callbackId", - "description": "Identifier for the callback", + "description": "Identifier for the callback.", "in": "path", "required": true, "type": "string" @@ -7304,7 +7304,7 @@ }, { "name": "query", - "description": "Visibility query, see https://docs.temporal.io/list-filter for the syntax.", + "description": "Visibility query, see https://docs.temporal.io/list-filter for the syntax.\nSearch attributes that are available:\n- ExecutionStatus", "in": "query", "required": false, "type": "string" @@ -7358,7 +7358,7 @@ }, { "name": "query", - "description": "Visibility query, see https://docs.temporal.io/list-filter for the syntax.", + "description": "Visibility query, see https://docs.temporal.io/list-filter for the syntax.\nSearch attributes that are available:\n- ExecutionStatus", "in": "query", "required": false, "type": "string" @@ -7397,7 +7397,7 @@ }, { "name": "callbackId", - "description": "Identifier for the callback", + "description": "Identifier for the callback.", "in": "path", "required": true, "type": "string" @@ -7425,7 +7425,7 @@ }, { "name": "longPollToken", - "description": "Token from a previous DescribeCallbackExecutionResponse. If present, long-poll until callback\nstate changes from the state encoded in this token. If absent, return current state immediately.\nNote that callback state may change multiple times between requests, therefore it is not\nguaranteed that a client making a sequence of long-poll requests will see a complete\nsequence of state changes.", + "description": "Token from a previous DescribeCallbackExecutionResponse. If present, long-poll until the callback\nstate changes from the state encoded in this token. If absent, return current state immediately.\nIf present, run_id must also be present.\nNote that callback state may change multiple times between requests, therefore it is not\nguaranteed that a client making a sequence of long-poll requests will see a complete\nsequence of state changes.", "in": "query", "required": false, "type": "string", @@ -7509,7 +7509,7 @@ }, { "name": "callbackId", - "description": "Identifier for the callback", + "description": "Identifier for the callback.", "in": "path", "required": true, "type": "string" @@ -7555,7 +7555,7 @@ }, { "name": "callbackId", - "description": "Identifier for the callback", + "description": "Identifier for the callback.", "in": "path", "required": true, "type": "string" @@ -11224,7 +11224,7 @@ }, "token": { "type": "string", - "description": "Standard token to use for identifying the callback, used for completion." + "description": "Standard token to use for identifying the callback, used for completion.\nClients should also populate the token header field for compatibility with older servers." } } }, @@ -14782,13 +14782,18 @@ "attempt": { "type": "integer", "format": "int32", - "description": "The number of attempts made to deliver the callback.\nThis number represents a minimum bound since the attempt is incremented after the callback request completes." + "description": "The number of attempts made to deliver the start callback execution request.\nThis number is approximate. There could be more attempts if callback invocation fails, or fewer\nif it was terminated." }, "createTime": { "type": "string", "format": "date-time", "description": "The time when the callback was created/scheduled." }, + "closeTime": { + "type": "string", + "format": "date-time", + "description": "Time when the callback transitioned to a terminal state." + }, "lastAttemptCompleteTime": { "type": "string", "format": "date-time", @@ -14801,17 +14806,12 @@ "nextAttemptScheduleTime": { "type": "string", "format": "date-time", - "description": "The time when the next attempt is scheduled." + "description": "The time when the next attempt is scheduled (only set when in BACKING_OFF state)." }, "blockedReason": { "type": "string", "description": "If the state is BLOCKED, provides additional information." }, - "closeTime": { - "type": "string", - "format": "date-time", - "description": "Time when the callback transitioned to a terminal state." - }, "searchAttributes": { "$ref": "#/definitions/v1SearchAttributes", "description": "Search attributes for indexing." @@ -14902,10 +14902,11 @@ "CALLBACK_STATE_FAILED", "CALLBACK_STATE_SUCCEEDED", "CALLBACK_STATE_BLOCKED", - "CALLBACK_STATE_TERMINATED" + "CALLBACK_STATE_TERMINATED", + "CALLBACK_STATE_TIMED_OUT" ], "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).\n - CALLBACK_STATE_TERMINATED: Callback was terminated via TerminateCallbackExecution. Only possible for standalone callbacks." + "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).\n - CALLBACK_STATE_TERMINATED: Callback was terminated via TerminateCallbackExecution. Only possible for standalone callbacks.\n - CALLBACK_STATE_TIMED_OUT: Callback exceeded the schedule-to-close timeout." }, "v1CancelExternalWorkflowExecutionFailedCause": { "type": "string", diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 7746bbf63..f65bfedd3 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -1321,7 +1321,10 @@ paths: type: string - name: query in: query - description: Visibility query, see https://docs.temporal.io/list-filter for the syntax. + description: |- + Visibility query, see https://docs.temporal.io/list-filter for the syntax. + Search attributes that are available: + - ExecutionStatus schema: type: string responses: @@ -1363,7 +1366,10 @@ paths: format: bytes - name: query in: query - description: Visibility query, see https://docs.temporal.io/list-filter for the syntax. + description: |- + Visibility query, see https://docs.temporal.io/list-filter for the syntax. + Search attributes that are available: + - ExecutionStatus schema: type: string responses: @@ -1400,7 +1406,7 @@ paths: type: string - name: callbackId in: path - description: Identifier for the callback + description: Identifier for the callback. required: true schema: type: string @@ -1422,8 +1428,9 @@ paths: - name: longPollToken in: query description: |- - Token from a previous DescribeCallbackExecutionResponse. If present, long-poll until callback + Token from a previous DescribeCallbackExecutionResponse. If present, long-poll until the callback state changes from the state encoded in this token. If absent, return current state immediately. + If present, run_id must also be present. Note that callback state may change multiple times between requests, therefore it is not guaranteed that a client making a sequence of long-poll requests will see a complete sequence of state changes. @@ -1499,7 +1506,7 @@ paths: type: string - name: callbackId in: path - description: Identifier for the callback + description: Identifier for the callback. required: true schema: type: string @@ -1539,7 +1546,7 @@ paths: type: string - name: callbackId in: path - description: Identifier for the callback + description: Identifier for the callback. required: true schema: type: string @@ -6579,7 +6586,10 @@ paths: type: string - name: query in: query - description: Visibility query, see https://docs.temporal.io/list-filter for the syntax. + description: |- + Visibility query, see https://docs.temporal.io/list-filter for the syntax. + Search attributes that are available: + - ExecutionStatus schema: type: string responses: @@ -6621,7 +6631,10 @@ paths: format: bytes - name: query in: query - description: Visibility query, see https://docs.temporal.io/list-filter for the syntax. + description: |- + Visibility query, see https://docs.temporal.io/list-filter for the syntax. + Search attributes that are available: + - ExecutionStatus schema: type: string responses: @@ -6658,7 +6671,7 @@ paths: type: string - name: callbackId in: path - description: Identifier for the callback + description: Identifier for the callback. required: true schema: type: string @@ -6680,8 +6693,9 @@ paths: - name: longPollToken in: query description: |- - Token from a previous DescribeCallbackExecutionResponse. If present, long-poll until callback + Token from a previous DescribeCallbackExecutionResponse. If present, long-poll until the callback state changes from the state encoded in this token. If absent, return current state immediately. + If present, run_id must also be present. Note that callback state may change multiple times between requests, therefore it is not guaranteed that a client making a sequence of long-poll requests will see a complete sequence of state changes. @@ -6757,7 +6771,7 @@ paths: type: string - name: callbackId in: path - description: Identifier for the callback + description: Identifier for the callback. required: true schema: type: string @@ -6797,7 +6811,7 @@ paths: type: string - name: callbackId in: path - description: Identifier for the callback + description: Identifier for the callback. required: true schema: type: string @@ -11117,19 +11131,25 @@ components: - CALLBACK_STATE_SUCCEEDED - CALLBACK_STATE_BLOCKED - CALLBACK_STATE_TERMINATED + - CALLBACK_STATE_TIMED_OUT type: string description: The detailed state of this callback, provides more granular information than the general status. format: enum attempt: type: integer description: |- - 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. + The number of attempts made to deliver the start callback execution request. + This number is approximate. There could be more attempts if callback invocation fails, or fewer + if it was terminated. format: int32 createTime: type: string description: The time when the callback was created/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. @@ -11140,15 +11160,11 @@ components: description: The last attempt's failure, if any. nextAttemptScheduleTime: type: string - description: The time when the next attempt is scheduled. + description: The time when the next attempt is scheduled (only set when in BACKING_OFF state). format: date-time blockedReason: type: string description: If the state is BLOCKED, provides additional information. - closeTime: - type: string - description: Time when the callback transitioned to a terminal state. - format: date-time searchAttributes: allOf: - $ref: '#/components/schemas/SearchAttributes' @@ -11230,6 +11246,7 @@ components: - CALLBACK_STATE_SUCCEEDED - CALLBACK_STATE_BLOCKED - CALLBACK_STATE_TERMINATED + - CALLBACK_STATE_TIMED_OUT type: string description: The current state of the callback. format: enum @@ -11280,7 +11297,9 @@ components: description: Header to attach to callback request. token: type: string - description: Standard token to use for identifying the callback, used for completion. + description: |- + Standard token to use for identifying the callback, used for completion. + Clients should also populate the token header field for compatibility with older servers. CanceledFailureInfo: type: object properties: @@ -17897,7 +17916,7 @@ components: type: string callbackId: type: string - description: Identifier for the callback + description: Identifier for the callback. runId: type: string description: Run ID of the callback execution to terminate. If empty, the latest run will be terminated. diff --git a/temporal/api/callback/v1/message.proto b/temporal/api/callback/v1/message.proto index cdb0d0e6c..db538d5bb 100644 --- a/temporal/api/callback/v1/message.proto +++ b/temporal/api/callback/v1/message.proto @@ -59,12 +59,15 @@ message CallbackExecutionInfo { // The detailed state of this callback, provides more granular information than the general status. 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. + // The number of attempts made to deliver the start callback execution request. + // This number is approximate. There could be more attempts if callback invocation fails, or fewer + // if it was terminated. int32 attempt = 6; // The time when the callback was created/scheduled. google.protobuf.Timestamp create_time = 7; + // Time when the callback transitioned to a terminal state. + google.protobuf.Timestamp close_time = 12; // The time when the last attempt completed. google.protobuf.Timestamp last_attempt_complete_time = 8; @@ -72,15 +75,12 @@ message CallbackExecutionInfo { // The last attempt's failure, if any. temporal.api.failure.v1.Failure last_attempt_failure = 9; - // The time when the next attempt is scheduled. + // The time when the next attempt is scheduled (only set when in BACKING_OFF state). google.protobuf.Timestamp next_attempt_schedule_time = 10; // If the state is BLOCKED, provides additional information. string blocked_reason = 11; - // Time when the callback transitioned to a terminal state. - google.protobuf.Timestamp close_time = 12; - // Search attributes for indexing. temporal.api.common.v1.SearchAttributes search_attributes = 13; diff --git a/temporal/api/common/v1/message.proto b/temporal/api/common/v1/message.proto index 0c292d84e..f317afd2a 100644 --- a/temporal/api/common/v1/message.proto +++ b/temporal/api/common/v1/message.proto @@ -182,6 +182,7 @@ message Callback { // Header to attach to callback request. map header = 2; // Standard token to use for identifying the callback, used for completion. + // Clients should also populate the token header field for compatibility with older servers. string token = 3; } diff --git a/temporal/api/enums/v1/common.proto b/temporal/api/enums/v1/common.proto index 30f1a0bed..f19a425d3 100644 --- a/temporal/api/enums/v1/common.proto +++ b/temporal/api/enums/v1/common.proto @@ -51,6 +51,8 @@ enum CallbackState { CALLBACK_STATE_BLOCKED = 6; // Callback was terminated via TerminateCallbackExecution. Only possible for standalone callbacks. CALLBACK_STATE_TERMINATED = 7; + // Callback exceeded the schedule-to-close timeout. + CALLBACK_STATE_TIMED_OUT = 8; } // Status of a callback execution. diff --git a/temporal/api/errordetails/v1/message.proto b/temporal/api/errordetails/v1/message.proto index 7491b84d6..6bc52c599 100644 --- a/temporal/api/errordetails/v1/message.proto +++ b/temporal/api/errordetails/v1/message.proto @@ -130,12 +130,11 @@ message ActivityExecutionAlreadyStartedFailure { string run_id = 2; } -// An error indicating that a callback execution failed to start because a callback with the given +// An error indicating that a callback execution failed to start because a callback with the same // callback ID already exists in this namespace. message CallbackExecutionAlreadyStartedFailure { string start_request_id = 1; string run_id = 2; - string callback_id = 3; } // An error indicating that a Nexus operation failed to start. Returned when there is an existing operation with the diff --git a/temporal/api/nexus/v1/message.proto b/temporal/api/nexus/v1/message.proto index aff9c7bc1..0daa6325e 100644 --- a/temporal/api/nexus/v1/message.proto +++ b/temporal/api/nexus/v1/message.proto @@ -65,6 +65,8 @@ message StartOperationRequest { // 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. + // Clients should set both the callback_token and the Temporal-Callback-Token header for + // compatibility with Workers running older versions of the SDK. string callback_token = 8; } diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index ea6fbc850..08ef23683 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -3578,7 +3578,7 @@ message StartCallbackExecutionResponse { message DescribeCallbackExecutionRequest { string namespace = 1; - // Identifier for the callback + // 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; @@ -3586,8 +3586,9 @@ message DescribeCallbackExecutionRequest { bool include_input = 4; // Include the outcome (result/failure) in the response if the callback has completed. bool include_outcome = 5; - // Token from a previous DescribeCallbackExecutionResponse. If present, long-poll until callback + // Token from a previous DescribeCallbackExecutionResponse. If present, long-poll until the callback // state changes from the state encoded in this token. If absent, return current state immediately. + // If present, run_id must also be present. // Note that callback state may change multiple times between requests, therefore it is not // guaranteed that a client making a sequence of long-poll requests will see a complete // sequence of state changes. @@ -3607,7 +3608,7 @@ message DescribeCallbackExecutionResponse { message PollCallbackExecutionRequest { string namespace = 1; - // Identifier for the callback + // Identifier for the callback. string callback_id = 2; // Run ID of the callback execution to poll. If empty, the latest run will be polled. string run_id = 3; @@ -3626,6 +3627,8 @@ message ListCallbackExecutionsRequest { // Token returned in ListCallbackExecutionsResponse. bytes next_page_token = 3; // Visibility query, see https://docs.temporal.io/list-filter for the syntax. + // Search attributes that are available: + // - ExecutionStatus string query = 4; } @@ -3638,6 +3641,8 @@ message ListCallbackExecutionsResponse { message CountCallbackExecutionsRequest { string namespace = 1; // Visibility query, see https://docs.temporal.io/list-filter for the syntax. + // Search attributes that are available: + // - ExecutionStatus string query = 2; } @@ -3661,7 +3666,7 @@ message CountCallbackExecutionsResponse { message TerminateCallbackExecutionRequest { string namespace = 1; - // Identifier for the callback + // Identifier for the callback. string callback_id = 2; // Run ID of the callback execution to terminate. If empty, the latest run will be terminated. string run_id = 3; @@ -3678,7 +3683,7 @@ message TerminateCallbackExecutionResponse { message DeleteCallbackExecutionRequest { string namespace = 1; - // Identifier for the callback + // Identifier for the callback. string callback_id = 2; // Run ID of the callback execution to delete. If empty, the latest run will be deleted. string run_id = 3; From 8dc0454dbaf036205127b5ffc6af775a151ac56c Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Thu, 14 May 2026 15:34:29 -0700 Subject: [PATCH 5/6] Update temporal/api/callback/v1/message.proto Co-authored-by: Roey Berman --- temporal/api/callback/v1/message.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/temporal/api/callback/v1/message.proto b/temporal/api/callback/v1/message.proto index db538d5bb..a45a73690 100644 --- a/temporal/api/callback/v1/message.proto +++ b/temporal/api/callback/v1/message.proto @@ -60,8 +60,8 @@ message CallbackExecutionInfo { temporal.api.enums.v1.CallbackState state = 5; // The number of attempts made to deliver the start callback execution request. - // This number is approximate. There could be more attempts if callback invocation fails, or fewer - // if it was terminated. + // 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 = 6; // The time when the callback was created/scheduled. From 2fecc48951e4f0f2bd308554ebc678d5773ab563 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Mon, 18 May 2026 09:37:35 -0700 Subject: [PATCH 6/6] Add errordetails.NexusOperationNotStartedFailure --- openapi/openapiv2.json | 2 +- openapi/openapiv3.yaml | 4 ++-- temporal/api/errordetails/v1/message.proto | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index c99f7eee5..7e68a5b7b 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -14782,7 +14782,7 @@ "attempt": { "type": "integer", "format": "int32", - "description": "The number of attempts made to deliver the start callback execution request.\nThis number is approximate. There could be more attempts if callback invocation fails, or fewer\nif it was terminated." + "description": "The number of attempts made to deliver the start callback execution request.\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", diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index f65bfedd3..058f24c9d 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -11139,8 +11139,8 @@ components: type: integer description: |- The number of attempts made to deliver the start callback execution request. - This number is approximate. There could be more attempts if callback invocation fails, or fewer - if it was terminated. + 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 diff --git a/temporal/api/errordetails/v1/message.proto b/temporal/api/errordetails/v1/message.proto index 6bc52c599..944ebe217 100644 --- a/temporal/api/errordetails/v1/message.proto +++ b/temporal/api/errordetails/v1/message.proto @@ -144,3 +144,8 @@ message NexusOperationExecutionAlreadyStartedFailure { string start_request_id = 1; string run_id = 2; } + +// An error indicating that the request's targeted Nexus operation has not yet started. +message NexusOperationNotStartedFailure { + string start_request_id = 1; +}