diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index a512c103f..37cc33ab4 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -1095,6 +1095,217 @@ ] } }, + "/api/v1/namespaces/{namespace}/nexus/operation-count": { + "get": { + "summary": "CountNexusOperations is a visibility API to count of Nexus operations in a specific namespace.", + "operationId": "CountNexusOperations2", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1CountNexusOperationsResponse" + } + }, + "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}/nexus/operations": { + "get": { + "summary": "ListNexusOperations is a visibility API to list Nexus operations in a specific namespace.", + "operationId": "ListNexusOperations2", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListNexusOperationsResponse" + } + }, + "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 operations to return per page.", + "in": "query", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "nextPageToken", + "description": "Token returned in ListNexusOperationsResponse.", + "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}/nexus/operations/{operationId}": { + "get": { + "summary": "PollNexusOperation returns the status and/or outcome of a Nexus operation.\nSupported use cases include\n- Get current operation info without waiting\n- Wait for next state change and return operation info\n- Wait for completion and return outcome", + "operationId": "PollNexusOperation2", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1PollNexusOperationResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "operationId", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "runId", + "description": "Operation run ID. If empty the request targets the latest run.", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "includeInfo", + "description": "Include the info field from the response.", + "in": "query", + "required": false, + "type": "boolean" + }, + { + "name": "includeInput", + "description": "Include the input field in the response.", + "in": "query", + "required": false, + "type": "boolean" + }, + { + "name": "includeOutcome", + "description": "Include the outcome field in the response.", + "in": "query", + "required": false, + "type": "boolean" + }, + { + "name": "waitAnyStateChange.longPollToken", + "description": "Token from a previous PollNexusOperationResponse used to inform the server of the\nlast state seen by the caller. If present, run_id must also be present.", + "in": "query", + "required": false, + "type": "string", + "format": "byte" + } + ], + "tags": [ + "WorkflowService" + ] + } + }, + "/api/v1/namespaces/{namespace}/nexus/operations/{operationId}/terminate": { + "post": { + "summary": "TerminateNexusOperation terminates an existing Nexus operation immediately.", + "description": "Termination does not reach the operation handler and the handler cannot react to it. A terminated operation may\nhave a running attempt and will be requested to be canceled by the server.", + "operationId": "TerminateNexusOperation2", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1TerminateNexusOperationResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "operationId", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/WorkflowServiceTerminateNexusOperationBody" + } + } + ], + "tags": [ + "WorkflowService" + ] + } + }, "/api/v1/namespaces/{namespace}/schedules": { "get": { "summary": "List all schedules in a namespace.", @@ -4990,6 +5201,217 @@ ] } }, + "/namespaces/{namespace}/nexus/operation-count": { + "get": { + "summary": "CountNexusOperations is a visibility API to count of Nexus operations in a specific namespace.", + "operationId": "CountNexusOperations", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1CountNexusOperationsResponse" + } + }, + "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}/nexus/operations": { + "get": { + "summary": "ListNexusOperations is a visibility API to list Nexus operations in a specific namespace.", + "operationId": "ListNexusOperations", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListNexusOperationsResponse" + } + }, + "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 operations to return per page.", + "in": "query", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "nextPageToken", + "description": "Token returned in ListNexusOperationsResponse.", + "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}/nexus/operations/{operationId}": { + "get": { + "summary": "PollNexusOperation returns the status and/or outcome of a Nexus operation.\nSupported use cases include\n- Get current operation info without waiting\n- Wait for next state change and return operation info\n- Wait for completion and return outcome", + "operationId": "PollNexusOperation", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1PollNexusOperationResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "operationId", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "runId", + "description": "Operation run ID. If empty the request targets the latest run.", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "includeInfo", + "description": "Include the info field from the response.", + "in": "query", + "required": false, + "type": "boolean" + }, + { + "name": "includeInput", + "description": "Include the input field in the response.", + "in": "query", + "required": false, + "type": "boolean" + }, + { + "name": "includeOutcome", + "description": "Include the outcome field in the response.", + "in": "query", + "required": false, + "type": "boolean" + }, + { + "name": "waitAnyStateChange.longPollToken", + "description": "Token from a previous PollNexusOperationResponse used to inform the server of the\nlast state seen by the caller. If present, run_id must also be present.", + "in": "query", + "required": false, + "type": "string", + "format": "byte" + } + ], + "tags": [ + "WorkflowService" + ] + } + }, + "/namespaces/{namespace}/nexus/operations/{operationId}/terminate": { + "post": { + "summary": "TerminateNexusOperation terminates an existing Nexus operation immediately.", + "description": "Termination does not reach the operation handler and the handler cannot react to it. A terminated operation may\nhave a running attempt and will be requested to be canceled by the server.", + "operationId": "TerminateNexusOperation", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1TerminateNexusOperationResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "operationId", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/WorkflowServiceTerminateNexusOperationBody" + } + } + ], + "tags": [ + "WorkflowService" + ] + } + }, "/namespaces/{namespace}/schedules": { "get": { "summary": "List all schedules in a namespace.", @@ -7334,22 +7756,6 @@ } } }, - "CountWorkflowExecutionsResponseAggregationGroup": { - "type": "object", - "properties": { - "groupValues": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Payload" - } - }, - "count": { - "type": "string", - "format": "int64" - } - } - }, "DeploymentInfoTaskQueueInfo": { "type": "object", "properties": { @@ -7448,6 +7854,21 @@ }, "description": "A link to a built-in batch job.\nBatch jobs can be used to perform operations on a set of workflows (e.g. terminate, signal, cancel, etc).\nThis link can be put on workflow history events generated by actions taken by a batch job." }, + "LinkNexusOperation": { + "type": "object", + "properties": { + "namespace": { + "type": "string" + }, + "operationId": { + "type": "string" + }, + "runId": { + "type": "string" + } + }, + "title": "A link to a Nexus operation" + }, "LinkWorkflowEvent": { "type": "object", "properties": { @@ -7557,6 +7978,19 @@ } } }, + "PollNexusOperationRequestCompletionWaitOptions": { + "type": "object" + }, + "PollNexusOperationRequestStateChangeWaitOptions": { + "type": "object", + "properties": { + "longPollToken": { + "type": "string", + "format": "byte", + "description": "Token from a previous PollNexusOperationResponse used to inform the server of the\nlast state seen by the caller. If present, run_id must also be present." + } + } + }, "PostResetOperationSignalWorkflow": { "type": "object", "properties": { @@ -8836,7 +9270,7 @@ "description": "If set, takes precedence over the Versioning Behavior sent by the SDK on Workflow Task completion.\nTo unset the override after the workflow is running, use UpdateWorkflowExecutionOptions." }, "onConflictOptions": { - "$ref": "#/definitions/v1OnConflictOptions", + "$ref": "#/definitions/apiworkflowv1OnConflictOptions", "description": "Defines actions to be done to the existing running workflow when the conflict policy\nWORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING is used. If not set (ie., nil value) or set to a\nempty object (ie., all options with default value), it won't do anything to the existing\nrunning workflow. If set, it will add a history event to the running workflow." }, "priority": { @@ -8862,6 +9296,23 @@ } } }, + "WorkflowServiceTerminateNexusOperationBody": { + "type": "object", + "properties": { + "runId": { + "type": "string", + "description": "Operation run ID, targets the latest run if run_id is empty." + }, + "reason": { + "type": "string", + "description": "Reason for requesting the termination, recorded in in the operation's result failure outcome." + }, + "identity": { + "type": "string", + "description": "The identity of the worker/client." + } + } + }, "WorkflowServiceTerminateWorkflowExecutionBody": { "type": "object", "properties": { @@ -9222,6 +9673,9 @@ }, "batchJob": { "$ref": "#/definitions/LinkBatchJob" + }, + "nexusOperation": { + "$ref": "#/definitions/LinkNexusOperation" } }, "description": "Link can be associated with history events. It might contain information about an external entity\nrelated to the history event. For example, workflow A makes a Nexus call that starts workflow B:\nin this case, a history event in workflow A could contain a Link to the workflow started event in\nworkflow B, and vice-versa." @@ -9310,6 +9764,24 @@ } } }, + "apinexusv1OnConflictOptions": { + "type": "object", + "properties": { + "attachRequestId": { + "type": "boolean", + "description": "Attaches the request ID to the running operation." + }, + "attachCompletionCallbacks": { + "type": "boolean", + "description": "Attaches the completion callbacks to the running operation." + }, + "attachLinks": { + "type": "boolean", + "description": "Attaches the links to the running operation." + } + }, + "description": "When StartNexusOperation uses the OPERATION_ID_CONFLICT_POLICY_USE_EXISTING and there is already an existing running\noperation, OnConflictOptions defines actions to be taken on the existing running operation, updating its state." + }, "apinexusv1Request": { "type": "object", "properties": { @@ -9360,7 +9832,25 @@ "$ref": "#/definitions/v1Input" } }, - "description": "The client request that triggers a Workflow Update." + "description": "The client request that triggers a Workflow Update." + }, + "apiworkflowv1OnConflictOptions": { + "type": "object", + "properties": { + "attachRequestId": { + "type": "boolean", + "description": "Attaches the request ID to the running workflow." + }, + "attachCompletionCallbacks": { + "type": "boolean", + "description": "Attaches the completion callbacks to the running workflow." + }, + "attachLinks": { + "type": "boolean", + "description": "Attaches the links to the WorkflowExecutionOptionsUpdatedEvent history event." + } + }, + "description": "When StartWorkflowExecution uses the conflict policy WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING and\nthere is already an existing running workflow, OnConflictOptions defines actions to be taken on\nthe existing running workflow. In this case, it will create a WorkflowExecutionOptionsUpdatedEvent\nhistory event in the running workflow with the changes requested in this object." }, "protobufAny": { "type": "object", @@ -10707,6 +11197,40 @@ } } }, + "v1CountNexusOperationsResponse": { + "type": "object", + "properties": { + "count": { + "type": "string", + "format": "int64", + "description": "If `query` is not grouping by any field, the count is an approximate number\nof operations 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 operations matching the query." + }, + "groups": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1CountNexusOperationsResponseAggregationGroup" + }, + "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." + } + } + }, + "v1CountNexusOperationsResponseAggregationGroup": { + "type": "object", + "properties": { + "groupValues": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Payload" + } + }, + "count": { + "type": "string", + "format": "int64" + } + } + }, "v1CountWorkflowExecutionsResponse": { "type": "object", "properties": { @@ -10719,12 +11243,28 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/CountWorkflowExecutionsResponseAggregationGroup" + "$ref": "#/definitions/v1CountWorkflowExecutionsResponseAggregationGroup" }, "description": "`groups` 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." } } }, + "v1CountWorkflowExecutionsResponseAggregationGroup": { + "type": "object", + "properties": { + "groupValues": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Payload" + } + }, + "count": { + "type": "string", + "format": "int64" + } + } + }, "v1CreateNexusEndpointRequest": { "type": "object", "properties": { @@ -10789,6 +11329,9 @@ "v1DeleteNexusEndpointResponse": { "type": "object" }, + "v1DeleteNexusOperationResponse": { + "type": "object" + }, "v1DeleteScheduleResponse": { "type": "object" }, @@ -12065,6 +12608,23 @@ } } }, + "v1ListNexusOperationsResponse": { + "type": "object", + "properties": { + "operations": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1NexusOperationListInfo" + } + }, + "nextPageToken": { + "type": "string", + "format": "byte", + "description": "Token to use to fetch the next page. If empty, there is no next page." + } + } + }, "v1ListOpenWorkflowExecutionsResponse": { "type": "object", "properties": { @@ -12733,6 +13293,196 @@ } } }, + "v1NexusOperationIdConflictPolicy": { + "type": "string", + "enum": [ + "NEXUS_OPERATION_ID_CONFLICT_POLICY_UNSPECIFIED", + "NEXUS_OPERATION_ID_CONFLICT_POLICY_FAIL", + "NEXUS_OPERATION_ID_CONFLICT_POLICY_USE_EXISTING", + "NEXUS_OPERATION_ID_CONFLICT_POLICY_TERMINATE_EXISTING" + ], + "default": "NEXUS_OPERATION_ID_CONFLICT_POLICY_UNSPECIFIED", + "description": "Defines what to do when trying to start a Nexus operation with the same ID as a *running* operation.\nNote that it is *never* valid to have two running instances of the same operation ID.\n\nSee `NexusOperationIdReusePolicy` for handling operation ID duplication with a *closed* operation.\n\n - NEXUS_OPERATION_ID_CONFLICT_POLICY_FAIL: Don't start a new operation; instead return `NexusOperationAlreadyStarted` error.\n - NEXUS_OPERATION_ID_CONFLICT_POLICY_USE_EXISTING: Don't start a new operation; instead return a handle for the running operation.\n - NEXUS_OPERATION_ID_CONFLICT_POLICY_TERMINATE_EXISTING: Terminate the running operation before starting a new one." + }, + "v1NexusOperationIdReusePolicy": { + "type": "string", + "enum": [ + "NEXUS_OPERATION_ID_REUSE_POLICY_UNSPECIFIED", + "NEXUS_OPERATION_ID_REUSE_POLICY_ALLOW_DUPLICATE", + "NEXUS_OPERATION_ID_REUSE_POLICY_ALLOW_DUPLICATE_FAILED_ONLY", + "NEXUS_OPERATION_ID_REUSE_POLICY_REJECT_DUPLICATE" + ], + "default": "NEXUS_OPERATION_ID_REUSE_POLICY_UNSPECIFIED", + "description": "Defines whether to allow re-using a Nexus operation ID from a previously *closed* operation.\nIf the request is denied, the server returns a `NexusOperationAlreadyStarted` error.\n\nSee `NexusOperationIdConflictPolicy` for handling ID duplication with a *running* operation.\n\n - NEXUS_OPERATION_ID_REUSE_POLICY_ALLOW_DUPLICATE: Always allow starting an operation using the same operation ID.\n - NEXUS_OPERATION_ID_REUSE_POLICY_ALLOW_DUPLICATE_FAILED_ONLY: Allow starting an operation using the same ID only when the last operation's final state is one\nof {failed, canceled, terminated, timed out}.\n - NEXUS_OPERATION_ID_REUSE_POLICY_REJECT_DUPLICATE: Do not permit re-use of the ID for this operation. Future start requests could potentially change the policy,\nallowing re-use of the ID." + }, + "v1NexusOperationInfo": { + "type": "object", + "properties": { + "operationId": { + "type": "string", + "description": "Unique identifier of this operation within its caller namespace along with run ID (below)." + }, + "runId": { + "type": "string" + }, + "endpoint": { + "type": "string", + "description": "Endpoint name associated with this operation." + }, + "service": { + "type": "string", + "description": "Name of the service to which this operation belongs." + }, + "operation": { + "type": "string", + "description": "Name of the operation as registered with the Temporal worker." + }, + "status": { + "$ref": "#/definitions/v1NexusOperationStatus", + "description": "A general status for this operation, indicates whether it is currently running or in one of the terminal statuses." + }, + "runState": { + "$ref": "#/definitions/v1PendingNexusOperationState", + "description": "More detailed breakdown of NEXUS_OPERATION_EXECUTION_STATUS_RUNNING." + }, + "startedTime": { + "type": "string", + "format": "date-time", + "description": "Time the operation transitioned to started, if the operation is asynchronous." + }, + "attempt": { + "type": "integer", + "format": "int32", + "description": "The attempt this operation is currently on.\nIncremented each time a new attempt is made to send a StartOperation or RequestCancelOperation request to the\noperation handler." + }, + "maximumAttempts": { + "type": "integer", + "format": "int32" + }, + "scheduledTime": { + "type": "string", + "format": "date-time", + "description": "Time the activity was originally scheduled via a StartNexusOperation request." + }, + "expirationTime": { + "type": "string", + "format": "date-time", + "description": "Scheduled time + schedule to close timeout." + }, + "lastFailure": { + "$ref": "#/definitions/apifailurev1Failure", + "description": "Failure details from the last failed attempt." + }, + "currentRetryInterval": { + "type": "string", + "description": "Time from the last attempt failure to the next retry. Calculated from the specified retry policy.\nIf operation is currently backing off between attempts, this represents the current retry interval.\nIf there is no next retry allowed, this field will be null." + }, + "lastAttemptCompleteTime": { + "type": "string", + "format": "date-time", + "description": "The time when the last request attempt completed. If the StartOperation request has not been completed yet, it will be null." + }, + "nextAttemptScheduleTime": { + "type": "string", + "format": "date-time", + "description": "The time when the next request attempt will be scheduled.\nIf operation is currently started, this field will be null." + }, + "stateTransitionCount": { + "type": "string", + "format": "int64", + "description": "Incremented each time the operation's state is mutated in persistence." + }, + "searchAttributes": { + "$ref": "#/definitions/v1SearchAttributes" + }, + "header": { + "$ref": "#/definitions/v1Header" + }, + "completionCallbacks": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Callback" + }, + "description": "Callbacks to be called by the server when this operation reaches a terminal status.\nCallback addresses must be whitelisted in the server's dynamic configuration." + }, + "links": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/apicommonv1Link" + }, + "description": "Links to be associated with the operation." + }, + "canceledReason": { + "type": "string", + "description": "Set if operation cancellation was requested." + } + }, + "description": "Information about a Nexus operation." + }, + "v1NexusOperationListInfo": { + "type": "object", + "properties": { + "operationId": { + "type": "string", + "description": "For standalone operations - a unique identifier of this operation within its namespace along with run ID (below)." + }, + "runId": { + "type": "string", + "description": "The run ID of the workflow or standalone operation." + }, + "workflowId": { + "type": "string", + "description": "Workflow that contains this operation - only present for workflow operations." + }, + "endpoint": { + "type": "string", + "description": "Endpoint name associated with this operation." + }, + "service": { + "type": "string", + "description": "Name of the service to which this operation belongs." + }, + "operation": { + "type": "string", + "description": "Name of the operation as registered with the Temporal worker." + }, + "scheduledTime": { + "type": "string", + "format": "date-time", + "description": "Time the operation was originally scheduled via a StartNexusOperation request." + }, + "closeTime": { + "type": "string", + "format": "date-time", + "description": "If the operation is in a terminal status, this field represents the time the operation transitioned to that status." + }, + "status": { + "$ref": "#/definitions/v1NexusOperationStatus", + "description": "Only scheduled and terminal statuses appear here. More detailed information in PendingNexusOperationInfo but not\navailable in the list response." + }, + "searchAttributes": { + "$ref": "#/definitions/v1SearchAttributes", + "description": "Search attributes from the start request." + }, + "stateTransitionCount": { + "type": "string", + "format": "int64", + "description": "Updated on terminal status." + }, + "stateSizeBytes": { + "type": "string", + "format": "int64", + "description": "Updated once on scheduled and once on terminal status." + }, + "executionDuration": { + "type": "string", + "description": "The difference between close time and scheduled time.\nThis field is only populated if the operation is closed." + } + }, + "description": "Limited Nexus operation information returned in the list response.\nWhen adding fields here, ensure that it is also present in NexusOperationInfo (note that it\nmay already be present in NexusOperationInfo but not at the top-level)." + }, "v1NexusOperationScheduledEventAttributes": { "type": "object", "properties": { @@ -12802,6 +13552,20 @@ }, "description": "Event marking an asynchronous operation was started by the responding Nexus handler.\nIf the operation completes synchronously, this event is not generated.\nIn rare situations, such as request timeouts, the service may fail to record the actual start time and will fabricate\nthis event upon receiving the operation completion via callback." }, + "v1NexusOperationStatus": { + "type": "string", + "enum": [ + "NEXUS_OPERATION_STATUS_UNSPECIFIED", + "NEXUS_OPERATION_STATUS_RUNNING", + "NEXUS_OPERATION_STATUS_COMPLETED", + "NEXUS_OPERATION_STATUS_FAILED", + "NEXUS_OPERATION_STATUS_CANCELED", + "NEXUS_OPERATION_STATUS_TERMINATED", + "NEXUS_OPERATION_STATUS_TIMED_OUT" + ], + "default": "NEXUS_OPERATION_STATUS_UNSPECIFIED", + "description": "Status of a standalone Nexus operation.\nThe status is updated once, when the operation is originally scheduled, and again when the operation reaches a terminal\nstatus.\n\n - NEXUS_OPERATION_STATUS_RUNNING: The operation is not in a terminal status. This does not necessarily mean that there is a currently running\nattempt. The operation may be backing off between attempts or waiting for a response from the operation handler.\n - NEXUS_OPERATION_STATUS_COMPLETED: The operation completed successfully.\n - NEXUS_OPERATION_STATUS_FAILED: The operation completed with failure.\n - NEXUS_OPERATION_STATUS_CANCELED: The operation completed as canceled.\nRequesting to cancel an operation does not automatically transition the activity to canceled status. The\noperation handler may choose to ignore the cancellation request and the operation may end in any terminal state.\nThe operation is only cancelled if the operation handler sends a completion with a cancelled failure.\n - NEXUS_OPERATION_STATUS_TERMINATED: The operation was terminated. Termination does not reach the worker and the operation handler code cannot react to it.\nA terminated operation may have a running attempt and will be requested to be canceled by the server.\n - NEXUS_OPERATION_STATUS_TIMED_OUT: The operation has timed out by reaching the specified schedule-to-start or schedule-to-close timeouts." + }, "v1NexusOperationTimedOutEventAttributes": { "type": "object", "properties": { @@ -12821,24 +13585,6 @@ }, "description": "Nexus operation timed out." }, - "v1OnConflictOptions": { - "type": "object", - "properties": { - "attachRequestId": { - "type": "boolean", - "description": "Attaches the request ID to the running workflow." - }, - "attachCompletionCallbacks": { - "type": "boolean", - "description": "Attaches the completion callbacks to the running workflow." - }, - "attachLinks": { - "type": "boolean", - "description": "Attaches the links to the WorkflowExecutionOptionsUpdatedEvent history event." - } - }, - "description": "When StartWorkflowExecution uses the conflict policy WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING and\nthere is already an existing running workflow, OnConflictOptions defines actions to be taken on\nthe existing running workflow. In this case, it will create a WorkflowExecutionOptionsUpdatedEvent\nhistory event in the running workflow with the changes requested in this object." - }, "v1Outcome": { "type": "object", "properties": { @@ -13234,6 +13980,36 @@ } } }, + "v1PollNexusOperationResponse": { + "type": "object", + "properties": { + "runId": { + "type": "string", + "description": "The run ID of the operation, useful when run_id was not specified in the request." + }, + "info": { + "$ref": "#/definitions/v1NexusOperationInfo", + "description": "Only set if include_info was true in the request." + }, + "input": { + "$ref": "#/definitions/v1Payload", + "description": "Serialized operation input." + }, + "result": { + "$ref": "#/definitions/v1Payload", + "description": "The result if the operation completed successfully." + }, + "failure": { + "$ref": "#/definitions/apifailurev1Failure", + "description": "The failure if the operation completed unsuccessfully." + }, + "stateChangeLongPollToken": { + "type": "string", + "format": "byte", + "description": "Token to use for a follow-on request using wait_any_state_change.\nOnly set if wait_policy was wait_any_state_change and the operation is not complete." + } + } + }, "v1PollNexusTaskQueueResponse": { "type": "object", "properties": { @@ -13784,6 +14560,9 @@ } } }, + "v1RequestCancelNexusOperationResponse": { + "type": "object" + }, "v1RequestCancelWorkflowExecutionResponse": { "type": "object" }, @@ -14977,6 +15756,19 @@ } } }, + "v1StartNexusOperationResponse": { + "type": "object", + "properties": { + "runId": { + "type": "string", + "description": "The run ID of the operation that was started - or used (via NEXUS_OPERATION_ID_CONFLICT_POLICY_USE_EXISTING)." + }, + "started": { + "type": "boolean", + "description": "If true, a new operation was started." + } + } + }, "v1StartOperationRequest": { "type": "object", "properties": { @@ -15164,7 +15956,7 @@ "description": "If set, takes precedence over the Versioning Behavior sent by the SDK on Workflow Task completion.\nTo unset the override after the workflow is running, use UpdateWorkflowExecutionOptions." }, "onConflictOptions": { - "$ref": "#/definitions/v1OnConflictOptions", + "$ref": "#/definitions/apiworkflowv1OnConflictOptions", "description": "Defines actions to be done to the existing running workflow when the conflict policy\nWORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING is used. If not set (ie., nil value) or set to a\nempty object (ie., all options with default value), it won't do anything to the existing\nrunning workflow. If set, it will add a history event to the running workflow." }, "priority": { @@ -15548,6 +16340,9 @@ "default": "TASK_REACHABILITY_UNSPECIFIED", "description": "Specifies which category of tasks may reach a worker on a versioned task queue.\nUsed both in a reachability query and its response.\nDeprecated.\n\n - TASK_REACHABILITY_NEW_WORKFLOWS: There's a possiblity for a worker to receive new workflow tasks. Workers should *not* be retired.\n - TASK_REACHABILITY_EXISTING_WORKFLOWS: There's a possiblity for a worker to receive existing workflow and activity tasks from existing workflows. Workers\nshould *not* be retired.\nThis enum value does not distinguish between open and closed workflows.\n - TASK_REACHABILITY_OPEN_WORKFLOWS: There's a possiblity for a worker to receive existing workflow and activity tasks from open workflows. Workers\nshould *not* be retired.\n - TASK_REACHABILITY_CLOSED_WORKFLOWS: There's a possiblity for a worker to receive existing workflow tasks from closed workflows. Workers may be\nretired dependending on application requirements. For example, if there's no need to query closed workflows." }, + "v1TerminateNexusOperationResponse": { + "type": "object" + }, "v1TerminateWorkflowExecutionResponse": { "type": "object" }, diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 4ee60e0fd..ba7d66b87 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -1008,6 +1008,181 @@ paths: application/json: schema: $ref: '#/components/schemas/Status' + /api/v1/namespaces/{namespace}/nexus/operation-count: + get: + tags: + - WorkflowService + description: CountNexusOperations is a visibility API to count of Nexus operations in a specific namespace. + operationId: CountNexusOperations + 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/CountNexusOperationsResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + /api/v1/namespaces/{namespace}/nexus/operations: + get: + tags: + - WorkflowService + description: ListNexusOperations is a visibility API to list Nexus operations in a specific namespace. + operationId: ListNexusOperations + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: pageSize + in: query + description: Max number of operations to return per page. + schema: + type: integer + format: int32 + - name: nextPageToken + in: query + description: Token returned in ListNexusOperationsResponse. + 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/ListNexusOperationsResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + /api/v1/namespaces/{namespace}/nexus/operations/{operationId}: + get: + tags: + - WorkflowService + description: |- + PollNexusOperation returns the status and/or outcome of a Nexus operation. + Supported use cases include + - Get current operation info without waiting + - Wait for next state change and return operation info + - Wait for completion and return outcome + operationId: PollNexusOperation + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: operationId + in: path + required: true + schema: + type: string + - name: runId + in: query + description: Operation run ID. If empty the request targets the latest run. + schema: + type: string + - name: includeInfo + in: query + description: Include the info field from the response. + schema: + type: boolean + - name: includeInput + in: query + description: Include the input field in the response. + schema: + type: boolean + - name: includeOutcome + in: query + description: Include the outcome field in the response. + schema: + type: boolean + - name: waitAnyStateChange.longPollToken + in: query + description: |- + Token from a previous PollNexusOperationResponse used to inform the server of the + last state seen by the caller. If present, run_id must also be present. + schema: + type: string + format: bytes + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/PollNexusOperationResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + /api/v1/namespaces/{namespace}/nexus/operations/{operationId}/terminate: + post: + tags: + - WorkflowService + description: |- + TerminateNexusOperation terminates an existing Nexus operation immediately. + + Termination does not reach the operation handler and the handler cannot react to it. A terminated operation may + have a running attempt and will be requested to be canceled by the server. + operationId: TerminateNexusOperation + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: operationId + in: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TerminateNexusOperationRequest' + required: true + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/TerminateNexusOperationResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' /api/v1/namespaces/{namespace}/schedules: get: tags: @@ -4490,6 +4665,181 @@ paths: application/json: schema: $ref: '#/components/schemas/Status' + /namespaces/{namespace}/nexus/operation-count: + get: + tags: + - WorkflowService + description: CountNexusOperations is a visibility API to count of Nexus operations in a specific namespace. + operationId: CountNexusOperations + 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/CountNexusOperationsResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + /namespaces/{namespace}/nexus/operations: + get: + tags: + - WorkflowService + description: ListNexusOperations is a visibility API to list Nexus operations in a specific namespace. + operationId: ListNexusOperations + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: pageSize + in: query + description: Max number of operations to return per page. + schema: + type: integer + format: int32 + - name: nextPageToken + in: query + description: Token returned in ListNexusOperationsResponse. + 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/ListNexusOperationsResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + /namespaces/{namespace}/nexus/operations/{operationId}: + get: + tags: + - WorkflowService + description: |- + PollNexusOperation returns the status and/or outcome of a Nexus operation. + Supported use cases include + - Get current operation info without waiting + - Wait for next state change and return operation info + - Wait for completion and return outcome + operationId: PollNexusOperation + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: operationId + in: path + required: true + schema: + type: string + - name: runId + in: query + description: Operation run ID. If empty the request targets the latest run. + schema: + type: string + - name: includeInfo + in: query + description: Include the info field from the response. + schema: + type: boolean + - name: includeInput + in: query + description: Include the input field in the response. + schema: + type: boolean + - name: includeOutcome + in: query + description: Include the outcome field in the response. + schema: + type: boolean + - name: waitAnyStateChange.longPollToken + in: query + description: |- + Token from a previous PollNexusOperationResponse used to inform the server of the + last state seen by the caller. If present, run_id must also be present. + schema: + type: string + format: bytes + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/PollNexusOperationResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + /namespaces/{namespace}/nexus/operations/{operationId}/terminate: + post: + tags: + - WorkflowService + description: |- + TerminateNexusOperation terminates an existing Nexus operation immediately. + + Termination does not reach the operation handler and the handler cannot react to it. A terminated operation may + have a running attempt and will be requested to be canceled by the server. + operationId: TerminateNexusOperation + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: operationId + in: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TerminateNexusOperationRequest' + required: true + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/TerminateNexusOperationResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' /namespaces/{namespace}/schedules: get: tags: @@ -7585,6 +7935,33 @@ components: type: string description: Time of the last update. format: date-time + CountNexusOperationsResponse: + type: object + properties: + count: + type: string + description: |- + If `query` is not grouping by any field, the count is an approximate number + of operations 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 operations matching the query. + groups: + type: array + items: + $ref: '#/components/schemas/CountNexusOperationsResponse_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. + CountNexusOperationsResponse_AggregationGroup: + type: object + properties: + groupValues: + type: array + items: + $ref: '#/components/schemas/Payload' + count: + type: string CountWorkflowExecutionsResponse: type: object properties: @@ -8855,6 +9232,8 @@ components: $ref: '#/components/schemas/Link_WorkflowEvent' batchJob: $ref: '#/components/schemas/Link_BatchJob' + nexusOperation: + $ref: '#/components/schemas/Link_NexusOperation' description: |- Link can be associated with history events. It might contain information about an external entity related to the history event. For example, workflow A makes a Nexus call that starts workflow B: @@ -8869,6 +9248,16 @@ components: A link to a built-in batch job. Batch jobs can be used to perform operations on a set of workflows (e.g. terminate, signal, cancel, etc). This link can be put on workflow history events generated by actions taken by a batch job. + Link_NexusOperation: + type: object + properties: + namespace: + type: string + operationId: + type: string + runId: + type: string + description: A link to a Nexus operation Link_WorkflowEvent: type: object properties: @@ -8935,6 +9324,17 @@ components: type: array items: $ref: '#/components/schemas/Endpoint' + ListNexusOperationsResponse: + type: object + properties: + operations: + type: array + items: + $ref: '#/components/schemas/NexusOperationListInfo' + nextPageToken: + type: string + description: Token to use to fetch the next page. If empty, there is no next page. + format: bytes ListScheduleMatchingTimesResponse: type: object properties: @@ -9468,6 +9868,174 @@ components: operationToken: type: string description: Operation token - may be empty if the operation completed synchronously. + NexusOperationInfo: + type: object + properties: + operationId: + type: string + description: Unique identifier of this operation within its caller namespace along with run ID (below). + runId: + type: string + endpoint: + type: string + description: Endpoint name associated with this operation. + service: + type: string + description: Name of the service to which this operation belongs. + operation: + type: string + description: Name of the operation as registered with the Temporal worker. + status: + enum: + - NEXUS_OPERATION_STATUS_UNSPECIFIED + - NEXUS_OPERATION_STATUS_RUNNING + - NEXUS_OPERATION_STATUS_COMPLETED + - NEXUS_OPERATION_STATUS_FAILED + - NEXUS_OPERATION_STATUS_CANCELED + - NEXUS_OPERATION_STATUS_TERMINATED + - NEXUS_OPERATION_STATUS_TIMED_OUT + type: string + description: A general status for this operation, indicates whether it is currently running or in one of the terminal statuses. + format: enum + runState: + enum: + - PENDING_NEXUS_OPERATION_STATE_UNSPECIFIED + - PENDING_NEXUS_OPERATION_STATE_SCHEDULED + - PENDING_NEXUS_OPERATION_STATE_BACKING_OFF + - PENDING_NEXUS_OPERATION_STATE_STARTED + - PENDING_NEXUS_OPERATION_STATE_BLOCKED + type: string + description: More detailed breakdown of NEXUS_OPERATION_EXECUTION_STATUS_RUNNING. + format: enum + startedTime: + type: string + description: Time the operation transitioned to started, if the operation is asynchronous. + format: date-time + attempt: + type: integer + description: |- + The attempt this operation is currently on. + Incremented each time a new attempt is made to send a StartOperation or RequestCancelOperation request to the + operation handler. + format: int32 + maximumAttempts: + type: integer + format: int32 + scheduledTime: + type: string + description: Time the activity was originally scheduled via a StartNexusOperation request. + format: date-time + expirationTime: + type: string + description: Scheduled time + schedule to close timeout. + format: date-time + lastFailure: + allOf: + - $ref: '#/components/schemas/Failure' + description: Failure details from the last failed attempt. + currentRetryInterval: + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + type: string + description: |- + Time from the last attempt failure to the next retry. Calculated from the specified retry policy. + If operation is currently backing off between attempts, this represents the current retry interval. + If there is no next retry allowed, this field will be null. + lastAttemptCompleteTime: + type: string + description: The time when the last request attempt completed. If the StartOperation request has not been completed yet, it will be null. + format: date-time + nextAttemptScheduleTime: + type: string + description: |- + The time when the next request attempt will be scheduled. + If operation is currently started, this field will be null. + format: date-time + stateTransitionCount: + type: string + description: Incremented each time the operation's state is mutated in persistence. + searchAttributes: + $ref: '#/components/schemas/SearchAttributes' + header: + $ref: '#/components/schemas/Header' + completionCallbacks: + type: array + items: + $ref: '#/components/schemas/Callback' + description: |- + Callbacks to be called by the server when this operation reaches a terminal status. + Callback addresses must be whitelisted in the server's dynamic configuration. + links: + type: array + items: + $ref: '#/components/schemas/Link' + description: Links to be associated with the operation. + canceledReason: + type: string + description: Set if operation cancellation was requested. + description: Information about a Nexus operation. + NexusOperationListInfo: + type: object + properties: + operationId: + type: string + description: For standalone operations - a unique identifier of this operation within its namespace along with run ID (below). + runId: + type: string + description: The run ID of the workflow or standalone operation. + workflowId: + type: string + description: Workflow that contains this operation - only present for workflow operations. + endpoint: + type: string + description: Endpoint name associated with this operation. + service: + type: string + description: Name of the service to which this operation belongs. + operation: + type: string + description: Name of the operation as registered with the Temporal worker. + scheduledTime: + type: string + description: Time the operation was originally scheduled via a StartNexusOperation request. + format: date-time + closeTime: + type: string + description: If the operation is in a terminal status, this field represents the time the operation transitioned to that status. + format: date-time + status: + enum: + - NEXUS_OPERATION_STATUS_UNSPECIFIED + - NEXUS_OPERATION_STATUS_RUNNING + - NEXUS_OPERATION_STATUS_COMPLETED + - NEXUS_OPERATION_STATUS_FAILED + - NEXUS_OPERATION_STATUS_CANCELED + - NEXUS_OPERATION_STATUS_TERMINATED + - NEXUS_OPERATION_STATUS_TIMED_OUT + type: string + description: |- + Only scheduled and terminal statuses appear here. More detailed information in PendingNexusOperationInfo but not + available in the list response. + format: enum + searchAttributes: + allOf: + - $ref: '#/components/schemas/SearchAttributes' + description: Search attributes from the start request. + stateTransitionCount: + type: string + description: Updated on terminal status. + stateSizeBytes: + type: string + description: Updated once on scheduled and once on terminal status. + executionDuration: + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + type: string + description: |- + The difference between close time and scheduled time. + This field is only populated if the operation is closed. + description: |- + Limited Nexus operation information returned in the list response. + When adding fields here, ensure that it is also present in NexusOperationInfo (note that it + may already be present in NexusOperationInfo but not at the top-level). NexusOperationScheduledEventAttributes: type: object properties: @@ -9912,6 +10480,34 @@ components: version: type: string description: The version of the plugin, may be empty. + PollNexusOperationResponse: + type: object + properties: + runId: + type: string + description: The run ID of the operation, useful when run_id was not specified in the request. + info: + allOf: + - $ref: '#/components/schemas/NexusOperationInfo' + description: Only set if include_info was true in the request. + input: + allOf: + - $ref: '#/components/schemas/Payload' + description: Serialized operation input. + result: + allOf: + - $ref: '#/components/schemas/Payload' + description: The result if the operation completed successfully. + failure: + allOf: + - $ref: '#/components/schemas/Failure' + description: The failure if the operation completed unsuccessfully. + stateChangeLongPollToken: + type: string + description: |- + Token to use for a follow-on request using wait_any_state_change. + Only set if wait_policy was wait_any_state_change and the operation is not complete. + format: bytes PollWorkflowTaskQueueResponse: type: object properties: @@ -12523,6 +13119,25 @@ components: description: Last time versioning information of this Task Queue changed. format: date-time description: Experimental. Worker Deployments are experimental and might significantly change in the future. + TerminateNexusOperationRequest: + type: object + properties: + namespace: + type: string + operationId: + type: string + runId: + type: string + description: Operation run ID, targets the latest run if run_id is empty. + reason: + type: string + description: Reason for requesting the termination, recorded in in the operation's result failure outcome. + identity: + type: string + description: The identity of the worker/client. + TerminateNexusOperationResponse: + type: object + properties: {} TerminateWorkflowExecutionRequest: type: object properties: diff --git a/temporal/api/common/v1/message.proto b/temporal/api/common/v1/message.proto index 838f5fefc..40bf30843 100644 --- a/temporal/api/common/v1/message.proto +++ b/temporal/api/common/v1/message.proto @@ -232,9 +232,17 @@ message Link { string job_id = 1; } + // A link to a Nexus operation + message NexusOperation { + string namespace = 1; + string operation_id = 2; + string run_id = 3; + } + oneof variant { WorkflowEvent workflow_event = 1; BatchJob batch_job = 2; + NexusOperation nexus_operation = 3; } } diff --git a/temporal/api/enums/v1/nexus.proto b/temporal/api/enums/v1/nexus.proto index 3a3087716..3284a61ef 100644 --- a/temporal/api/enums/v1/nexus.proto +++ b/temporal/api/enums/v1/nexus.proto @@ -20,3 +20,58 @@ enum NexusHandlerErrorRetryBehavior { NEXUS_HANDLER_ERROR_RETRY_BEHAVIOR_NON_RETRYABLE = 2; } +// Status of a standalone Nexus operation. +// The status is updated once, when the operation is originally scheduled, and again when the operation reaches a terminal +// status. +// (-- api-linter: core::0216::synonyms=disabled +// aip.dev/not-precedent: Named consistently with WorkflowExecutionStatus. --) +enum NexusOperationStatus { + NEXUS_OPERATION_STATUS_UNSPECIFIED = 0; + // The operation is not in a terminal status. This does not necessarily mean that there is a currently running + // attempt. The operation may be backing off between attempts or waiting for a response from the operation handler. + NEXUS_OPERATION_STATUS_RUNNING = 1; + // The operation completed successfully. + NEXUS_OPERATION_STATUS_COMPLETED = 2; + // The operation completed with failure. + NEXUS_OPERATION_STATUS_FAILED = 3; + // The operation completed as canceled. + // Requesting to cancel an operation does not automatically transition the activity to canceled status. The + // operation handler may choose to ignore the cancellation request and the operation may end in any terminal state. + // The operation is only cancelled if the operation handler sends a completion with a cancelled failure. + NEXUS_OPERATION_STATUS_CANCELED = 4; + // The operation was terminated. Termination does not reach the worker and the operation handler code cannot react to it. + // A terminated operation may have a running attempt and will be requested to be canceled by the server. + NEXUS_OPERATION_STATUS_TERMINATED = 5; + // The operation has timed out by reaching the specified schedule-to-start or schedule-to-close timeouts. + NEXUS_OPERATION_STATUS_TIMED_OUT = 6; +} + +// Defines whether to allow re-using a Nexus operation ID from a previously *closed* operation. +// If the request is denied, the server returns a `NexusOperationAlreadyStarted` error. +// +// See `NexusOperationIdConflictPolicy` for handling ID duplication with a *running* operation. +enum NexusOperationIdReusePolicy { + NEXUS_OPERATION_ID_REUSE_POLICY_UNSPECIFIED = 0; + // Always allow starting an operation using the same operation ID. + NEXUS_OPERATION_ID_REUSE_POLICY_ALLOW_DUPLICATE = 1; + // Allow starting an operation using the same ID only when the last operation's final state is one + // of {failed, canceled, terminated, timed out}. + NEXUS_OPERATION_ID_REUSE_POLICY_ALLOW_DUPLICATE_FAILED_ONLY = 2; + // Do not permit re-use of the ID for this operation. Future start requests could potentially change the policy, + // allowing re-use of the ID. + NEXUS_OPERATION_ID_REUSE_POLICY_REJECT_DUPLICATE = 3; +} + +// Defines what to do when trying to start a Nexus operation with the same ID as a *running* operation. +// Note that it is *never* valid to have two running instances of the same operation ID. +// +// See `NexusOperationIdReusePolicy` for handling operation ID duplication with a *closed* operation. +enum NexusOperationIdConflictPolicy { + NEXUS_OPERATION_ID_CONFLICT_POLICY_UNSPECIFIED = 0; + // Don't start a new operation; instead return `NexusOperationAlreadyStarted` error. + NEXUS_OPERATION_ID_CONFLICT_POLICY_FAIL = 1; + // Don't start a new operation; instead return a handle for the running operation. + NEXUS_OPERATION_ID_CONFLICT_POLICY_USE_EXISTING = 2; + // Terminate the running operation before starting a new one. + NEXUS_OPERATION_ID_CONFLICT_POLICY_TERMINATE_EXISTING = 3; +} diff --git a/temporal/api/nexus/v1/message.proto b/temporal/api/nexus/v1/message.proto index bfad6102a..0a3fe9e8c 100644 --- a/temporal/api/nexus/v1/message.proto +++ b/temporal/api/nexus/v1/message.proto @@ -9,9 +9,12 @@ option java_outer_classname = "MessageProto"; option ruby_package = "Temporalio::Api::Nexus::V1"; option csharp_namespace = "Temporalio.Api.Nexus.V1"; +import "google/protobuf/duration.proto"; import "google/protobuf/timestamp.proto"; import "temporal/api/common/v1/message.proto"; +import "temporal/api/enums/v1/common.proto"; import "temporal/api/enums/v1/nexus.proto"; +import "temporal/api/failure/v1/message.proto"; // A general purpose failure message. // See: https://github.com/nexus-rpc/api/blob/main/SPEC.md#failure @@ -42,6 +45,17 @@ message Link { string type = 2; } +// When StartNexusOperation uses the OPERATION_ID_CONFLICT_POLICY_USE_EXISTING and there is already an existing running +// operation, OnConflictOptions defines actions to be taken on the existing running operation, updating its state. +message OnConflictOptions { + // Attaches the request ID to the running operation. + bool attach_request_id = 1; + // Attaches the completion callbacks to the running operation. + bool attach_completion_callbacks = 2; + // Attaches the links to the running operation. + bool attach_links = 3; +} + // A request to start an operation. message StartOperationRequest { // Name of service to start the operation in. @@ -198,3 +212,96 @@ message EndpointTarget { External external = 2; } } + +// Information about a Nexus operation. +message NexusOperationInfo { + // Unique identifier of this operation within its caller namespace along with run ID (below). + string operation_id = 1; + string run_id = 2; + + // Endpoint name associated with this operation. + string endpoint = 3; + // Name of the service to which this operation belongs. + string service = 4; + // Name of the operation as registered with the Temporal worker. + string operation = 5; + // A general status for this operation, indicates whether it is currently running or in one of the terminal statuses. + temporal.api.enums.v1.NexusOperationStatus status = 6; + // More detailed breakdown of NEXUS_OPERATION_EXECUTION_STATUS_RUNNING. + temporal.api.enums.v1.PendingNexusOperationState run_state = 7; + + // Time the operation transitioned to started, if the operation is asynchronous. + google.protobuf.Timestamp started_time = 8; + // The attempt this operation is currently on. + // Incremented each time a new attempt is made to send a StartOperation or RequestCancelOperation request to the + // operation handler. + int32 attempt = 9; + int32 maximum_attempts = 10; + // Time the activity was originally scheduled via a StartNexusOperation request. + google.protobuf.Timestamp scheduled_time = 11; + // Scheduled time + schedule to close timeout. + google.protobuf.Timestamp expiration_time = 12; + // Failure details from the last failed attempt. + temporal.api.failure.v1.Failure last_failure = 13; + // Time from the last attempt failure to the next retry. Calculated from the specified retry policy. + // If operation is currently backing off between attempts, this represents the current retry interval. + // If there is no next retry allowed, this field will be null. + google.protobuf.Duration current_retry_interval = 14; + // The time when the last request attempt completed. If the StartOperation request has not been completed yet, it will be null. + google.protobuf.Timestamp last_attempt_complete_time = 15; + // The time when the next request attempt will be scheduled. + // If operation is currently started, this field will be null. + google.protobuf.Timestamp next_attempt_schedule_time = 16; + + // Incremented each time the operation's state is mutated in persistence. + int64 state_transition_count = 17; + + temporal.api.common.v1.SearchAttributes search_attributes = 18; + temporal.api.common.v1.Header header = 19; + + // Callbacks to be called by the server when this operation reaches a terminal status. + // Callback addresses must be whitelisted in the server's dynamic configuration. + repeated temporal.api.common.v1.Callback completion_callbacks = 20; + // Links to be associated with the operation. + repeated temporal.api.common.v1.Link links = 21; + + // Set if operation cancellation was requested. + string canceled_reason = 22; +} + +// Limited Nexus operation information returned in the list response. +// When adding fields here, ensure that it is also present in NexusOperationInfo (note that it +// may already be present in NexusOperationInfo but not at the top-level). +message NexusOperationListInfo { + // For standalone operations - a unique identifier of this operation within its namespace along with run ID (below). + string operation_id = 1; + // The run ID of the workflow or standalone operation. + string run_id = 2; + // Workflow that contains this operation - only present for workflow operations. + string workflow_id = 3; + + // Endpoint name associated with this operation. + string endpoint = 4; + // Name of the service to which this operation belongs. + string service = 5; + // Name of the operation as registered with the Temporal worker. + string operation = 6; + // Time the operation was originally scheduled via a StartNexusOperation request. + google.protobuf.Timestamp scheduled_time = 7; + // If the operation is in a terminal status, this field represents the time the operation transitioned to that status. + google.protobuf.Timestamp close_time = 8; + // Only scheduled and terminal statuses appear here. More detailed information in PendingNexusOperationInfo but not + // available in the list response. + temporal.api.enums.v1.NexusOperationStatus status = 9; + + // Search attributes from the start request. + temporal.api.common.v1.SearchAttributes search_attributes = 10; + + // Updated on terminal status. + int64 state_transition_count = 11; + // Updated once on scheduled and once on terminal status. + int64 state_size_bytes = 12; + // The difference between close time and scheduled time. + // This field is only populated if the operation is closed. + google.protobuf.Duration execution_duration = 13; +} \ No newline at end of file diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index bd9282998..6acb1a93b 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -13,6 +13,7 @@ import "temporal/api/enums/v1/batch_operation.proto"; import "temporal/api/enums/v1/common.proto"; import "temporal/api/enums/v1/workflow.proto"; import "temporal/api/enums/v1/namespace.proto"; +import "temporal/api/enums/v1/nexus.proto"; import "temporal/api/enums/v1/failed_cause.proto"; import "temporal/api/enums/v1/query.proto"; import "temporal/api/enums/v1/reset.proto"; @@ -2598,3 +2599,192 @@ message DescribeWorkerRequest { message DescribeWorkerResponse { temporal.api.worker.v1.WorkerInfo worker_info = 1; } + +message StartNexusOperationRequest { + // The caller namespace. Note the endpoint below may target a different namespace. + 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; + + // A caller-set ID for referencing this operation in the caller namespace ONLY. This ID will not be propagated to + // the operation handler. + string operation_id = 4; + // A registered Nexus endpoint name. + string endpoint = 5; + // Name of the service to which this operation belongs. + string service = 6; + // Operation name as registered with the Temporal worker. + string operation = 7; + // Serialized input to the operation. + temporal.api.common.v1.Payload input = 8; + // Request headers to forward to the operation handler. + temporal.api.common.v1.Header header = 9; + + // Defines whether to allow re-using the operation id from a previously *closed* operation. + // The default policy is NEXUS_OPERATION_ID_REUSE_POLICY_ALLOW_DUPLICATE. + temporal.api.enums.v1.NexusOperationIdReusePolicy id_reuse_policy = 10; + // Defines how to resolve an operation id conflict with a *running* operation. + // The default policy is NEXUS_OPERATION_ID_CONFLICT_POLICY_FAIL. + temporal.api.enums.v1.NexusOperationIdConflictPolicy id_conflict_policy = 11; + // Defines actions to be done to the existing running operation when NEXUS_OPERATION_ID_CONFLICT_POLICY_USE_EXISTING + // is used. If not set or empty, it won't do anything to the existing running operation. + temporal.api.nexus.v1.OnConflictOptions on_conflict_options = 12; + + // Arbitrary structured data that can be attached to the operation and made available via the list and describe APIs. + temporal.api.common.v1.Memo memo = 13; + // Search attributes for indexing. + temporal.api.common.v1.SearchAttributes search_attributes = 14; + // Callbacks to be called by the server when this operation reaches a terminal status. + // Callback addresses must be whitelisted in the server's dynamic configuration. + repeated temporal.api.common.v1.Callback completion_callbacks = 15; + // Links to be associated with the operation. + repeated temporal.api.common.v1.Link links = 16; +} + +message StartNexusOperationResponse { + // The run ID of the operation that was started - or used (via NEXUS_OPERATION_ID_CONFLICT_POLICY_USE_EXISTING). + string run_id = 1; + // If true, a new operation was started. + bool started = 2; +} + +message PollNexusOperationRequest { + string namespace = 1; + string operation_id = 2; + // Operation run ID. If empty the request targets the latest run. + string run_id = 3; + // Include the info field from the response. + bool include_info = 4; + // Include the input field in the response. + bool include_input = 5; + // Include the outcome field in the response. + bool include_outcome = 6; + + message StateChangeWaitOptions { + // Token from a previous PollNexusOperationResponse used to inform the server of the + // last state seen by the caller. If present, run_id must also be present. + bytes long_poll_token = 1; + } + + message CompletionWaitOptions {} + + // If present, the request will be handled as a long-poll. If absent, a response will be + // returned immediately containing the current operation state. + oneof wait_policy { + // Wait for any change in operation state before responding. If long_poll_token is absent + // then the current state will be returned immediately without any wait. Otherwise the + // server will wait until operation state differs from that encoded in the token before + // returning the new state. Note that operation 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. + StateChangeWaitOptions wait_any_state_change = 7; + // Wait for the operation to complete before responding. + // long_poll_token is currently ignored when waiting for completion + CompletionWaitOptions wait_completion = 8; + } +} + +message PollNexusOperationResponse { + // The run ID of the operation, useful when run_id was not specified in the request. + string run_id = 1; + + // Only set if include_info was true in the request. + temporal.api.nexus.v1.NexusOperationInfo info = 2; + + // Serialized operation input. + temporal.api.common.v1.Payload input = 3; + + // Only set if the operation is completed and include_outcome was true in the request. + oneof outcome { + // The result if the operation completed successfully. + temporal.api.common.v1.Payload result = 4; + // The failure if the operation completed unsuccessfully. + temporal.api.failure.v1.Failure failure = 5; + } + + // Token to use for a follow-on request using wait_any_state_change. + // Only set if wait_policy was wait_any_state_change and the operation is not complete. + bytes state_change_long_poll_token = 6; +} + +message ListNexusOperationsRequest { + string namespace = 1; + // Max number of operations to return per page. + int32 page_size = 2; + // Token returned in ListNexusOperationsResponse. + bytes next_page_token = 3; + // Visibility query, see https://docs.temporal.io/list-filter for the syntax. + string query = 4; +} + +message ListNexusOperationsResponse { + repeated temporal.api.nexus.v1.NexusOperationListInfo operations = 1; + // Token to use to fetch the next page. If empty, there is no next page. + bytes next_page_token = 2; +} + +message CountNexusOperationsRequest { + string namespace = 1; + // Visibility query, see https://docs.temporal.io/list-filter for the syntax. + string query = 2; +} + +message CountNexusOperationsResponse { + // If `query` is not grouping by any field, the count is an approximate number + // of operations 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 operations 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 RequestCancelNexusOperationRequest { + string namespace = 1; + string operation_id = 2; + // Operation run ID, targets the latest run if run_id is empty. + string run_id = 3; + // The identity of the worker/client. + string identity = 4; + // Used to de-dupe cancellation requests. + string request_id = 5; + // Reason for requesting the cancellation, recorded and available via the PollNexusOperation API. + string reason = 6; +} + +message RequestCancelNexusOperationResponse { +} + +message TerminateNexusOperationRequest { + string namespace = 1; + string operation_id = 2; + // Operation run ID, targets the latest run if run_id is empty. + string run_id = 3; + // Reason for requesting the termination, recorded in in the operation's result failure outcome. + string reason = 4; + // The identity of the worker/client. + string identity = 5; +} + +message TerminateNexusOperationResponse { +} + +message DeleteNexusOperationRequest { + string namespace = 1; + string operation_id = 2; + // Operation run ID, targets the latest run if run_id is empty. + string run_id = 3; +} + +message DeleteNexusOperationResponse { +} diff --git a/temporal/api/workflowservice/v1/service.proto b/temporal/api/workflowservice/v1/service.proto index dc33b84ef..3b738ba19 100644 --- a/temporal/api/workflowservice/v1/service.proto +++ b/temporal/api/workflowservice/v1/service.proto @@ -1259,4 +1259,87 @@ service WorkflowService { } }; } + + // StartNexusOperation starts a new Nexus operation. + // + // Returns a `NexusOperationAlreadyStarted` error if an instance already exists with same operation ID in this namespace + // unless permitted by the specified ID conflict policy. + // + // TODO: clarify the different semantics between Durable and Direct calls. TBD exactly how Direct calls will be exposed. + // + // (-- api-linter: core::0127::http-annotation=disabled + // aip.dev/not-precedent: Nexus has a separately defined StartOperation HTTP API. --) + rpc StartNexusOperation (StartNexusOperationRequest) returns (StartNexusOperationResponse) { + } + + // PollNexusOperation returns the status and/or outcome of a Nexus operation. + // Supported use cases include + // - Get current operation info without waiting + // - Wait for next state change and return operation info + // - Wait for completion and return outcome + rpc PollNexusOperation (PollNexusOperationRequest) returns (PollNexusOperationResponse) { + option (google.api.http) = { + get: "/namespaces/{namespace}/nexus/operations/{operation_id}" + additional_bindings { + get: "/api/v1/namespaces/{namespace}/nexus/operations/{operation_id}" + } + }; + } + + // ListNexusOperations is a visibility API to list Nexus operations in a specific namespace. + rpc ListNexusOperations (ListNexusOperationsRequest) returns (ListNexusOperationsResponse) { + option (google.api.http) = { + get: "/namespaces/{namespace}/nexus/operations" + additional_bindings { + get: "/api/v1/namespaces/{namespace}/nexus/operations" + } + }; + } + + // CountNexusOperations is a visibility API to count of Nexus operations in a specific namespace. + rpc CountNexusOperations (CountNexusOperationsRequest) returns (CountNexusOperationsResponse) { + option (google.api.http) = { + get: "/namespaces/{namespace}/nexus/operation-count" + additional_bindings { + get: "/api/v1/namespaces/{namespace}/nexus/operation-count" + } + }; + } + + // RequestCancelNexusOperation requests cancellation of a Nexus operation. + // + // Requesting to cancel an operation does not automatically transition the operation to canceled status. The + // operation handler may choose to ignore the cancellation request and the operation may end in any terminal state. + // The operation handler must invoke the operation completion callback with a failure indicating the operation was + // cancelled for the operation to transition to canceled status. + // + // It returns success if the requested operation is already completed. + // + // (-- api-linter: core::0127::http-annotation=disabled + // aip.dev/not-precedent: Nexus has a separately defined CancelOperation HTTP API. --) + rpc RequestCancelNexusOperation (RequestCancelNexusOperationRequest) returns (RequestCancelNexusOperationResponse) { + } + + // TerminateNexusOperation terminates an existing Nexus operation immediately. + // + // Termination does not reach the operation handler and the handler cannot react to it. A terminated operation may + // have a running attempt and will be requested to be canceled by the server. + rpc TerminateNexusOperation (TerminateNexusOperationRequest) returns (TerminateNexusOperationResponse) { + option (google.api.http) = { + post: "/namespaces/{namespace}/nexus/operations/{operation_id}/terminate" + body: "*" + additional_bindings { + post: "/api/v1/namespaces/{namespace}/nexus/operations/{operation_id}/terminate" + body: "*" + } + }; + } + + // DeleteNexusOperation asynchronously deletes a specific Nexus operation (when run_id is provided) or the latest + // activity execution (when run_id is not provided). If the Nexus operation is running, it will be terminated + // before deletion. + // + // (-- 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 DeleteNexusOperation (DeleteNexusOperationRequest) returns (DeleteNexusOperationResponse) {} }