diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 9a475d2d2..4542352dd 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -10815,6 +10815,10 @@ "type": "object", "description": "Trigger for when the activity is closed." }, + "CallbackInfoOperationCompleted": { + "type": "object", + "description": "Trigger for when the Nexus operation is completed, covering both success cases as\nwell as any type of failure." + }, "CallbackInfoUpdateWorkflowExecutionCompleted": { "type": "object", "properties": { @@ -10853,7 +10857,32 @@ }, "description": "Header to attach to callback request." } - } + }, + "title": "Nexus callbacks are used to delivery Nexus operation completions, as defined in the Nexus RPC spec: \nhttps://github.com/nexus-rpc/api/blob/main/SPEC.md#callback-urls" + }, + "CallbackNexusHandler": { + "type": "object", + "properties": { + "taskQueueName": { + "type": "string", + "description": "Nexus task queue the Temporal worker is listening on.\n\nNOTE: This is not a temporal.api.taskqueue.v1.TaskQueue to avoid a circular dependency." + }, + "service": { + "type": "string", + "description": "Target Nexus service, e.g. \"HTTPAdapter\"." + }, + "operation": { + "type": "string", + "description": "Target operation, e.g. \"DeliverAsWebhook\"." + }, + "sourceContext": { + "$ref": "#/definitions/v1Payload", + "description": "There are restrictions on the maxium payload size a single callback can carry, as well as the\ntotal sum of all source context payloads attached to an execution. See dynamic configuration\nsettings: \"callback.worker.sourceContext.maxSize\", \"callback.worker.sourceContext.aggregateMaxSize\".", + "title": "Arbitrary user-supplied data from the source operation's callsite. (As applicable, not all operations\nsupport attaching context data.)" + } + }, + "description": "The targeted Nexus service must be registered within the same namespace as the source operation\nthe callback is attached to. (While Nexus allows for cross-namespace operations, NexusHandler callbacks\nare strictly caller-side.)\n\nNexusHandler callbacks are only supported for certain types of operations, e.g. standalone Nexus operations.\nAttempting to attach a Worker callback for an unsupported operation will result in an INVALID_ARGUMENT\nerror from the server.", + "title": "NexusHandler callbacks are requests to invoke a specific shape of Nexus operation on a Temporal worker.\nThe specified Nexus operation must have the following:\n- Input: temporal.api.notificationservice.v1.OnCompleteRequest\n- Output: temporal.api.notificationservice.v1.OnCompleteResponse" }, "ComputeStatusProviderValidationStatus": { "type": "object", @@ -11544,7 +11573,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Callback" + "$ref": "#/definitions/commonV1Callback" }, "description": "Completion callbacks attached to the running workflow update." } @@ -12586,7 +12615,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Callback" + "$ref": "#/definitions/commonV1Callback" }, "description": "Callbacks to be called by the server when this activity reaches a terminal state.\nCallback addresses must be whitelisted in the server's dynamic configuration." }, @@ -12725,6 +12754,10 @@ "$ref": "#/definitions/v1NexusOperationIdConflictPolicy", "description": "Defines how to resolve an operation id conflict with a *running* operation.\nThe default policy is NEXUS_OPERATION_ID_CONFLICT_POLICY_FAIL." }, + "onConflictOptions": { + "$ref": "#/definitions/apiNexusoperationV1OnConflictOptions", + "description": "Defines actions to be done to the existing running standalone Nexus when the conflict policy\nNEXUS_OPERATION_ID_CONFLICT_POLICY_USE_EXISTING is used. If not set or set to a empty object\n(all options with default value), it will not modify the running operation." + }, "searchAttributes": { "$ref": "#/definitions/v1SearchAttributes", "description": "Search attributes for indexing." @@ -12739,6 +12772,22 @@ "userMetadata": { "$ref": "#/definitions/v1UserMetadata", "description": "Metadata for use by user interfaces to display the fixed as-of-start summary and details of the operation." + }, + "completionCallbacks": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/commonV1Callback" + }, + "description": "Completion callbacks to be invoked once the Nexus operation reaches a terminal state." + }, + "links": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/apiCommonV1Link" + }, + "description": "Links to be associated with the Nexus operation. Callbacks may also have associated links;\nlinks already included with a callback should not be duplicated here." } } }, @@ -12819,7 +12868,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Callback" + "$ref": "#/definitions/commonV1Callback" }, "description": "Callbacks to be called by the server when this workflow reaches a terminal state.\nIf the workflow continues-as-new, these callbacks will be carried over to the new execution.\nCallback addresses must be whitelisted in the server's dynamic configuration." }, @@ -13363,7 +13412,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Callback" + "$ref": "#/definitions/commonV1Callback" }, "description": "Callbacks to be called by the server when this update reaches a terminal state." }, @@ -13463,7 +13512,7 @@ "type": "object", "properties": { "callback": { - "$ref": "#/definitions/v1Callback", + "$ref": "#/definitions/commonV1Callback", "description": "Information on how this callback should be invoked (e.g. its URL and type)." }, "registrationTime": { @@ -13497,6 +13546,19 @@ "blockedReason": { "type": "string", "description": "If the state is BLOCKED, blocked reason provides additional information." + }, + "requestId": { + "type": "string", + "description": "Server-generated request ID used as an idempotency token when invoking callbacks.\nIt has no relation to caller-side request_id sent in operations like StartNexusOperationExecutionRequest." + }, + "success": { + "type": "object", + "properties": {}, + "title": "The callback completed successfully. (Which may include delivering a \"failed\" result successfully.)" + }, + "failure": { + "$ref": "#/definitions/v1Failure", + "description": "The failure if the callback was not able to complete successfully. e.g. timed out, received an\nunretriable error, etc." } }, "description": "Common callback information. Specific CallbackInfo messages should embed this and may include additional fields." @@ -13519,11 +13581,51 @@ }, "description": "When starting an execution with a conflict policy that uses an existing execution and there is already an existing\nrunning execution, OnConflictOptions defines actions to be taken on the existing running execution." }, + "apiNexusoperationV1CallbackInfo": { + "type": "object", + "properties": { + "trigger": { + "$ref": "#/definitions/apiNexusoperationV1CallbackInfoTrigger", + "description": "Trigger for this callback." + }, + "info": { + "$ref": "#/definitions/apiCallbackV1CallbackInfo", + "description": "Common callback info." + } + }, + "description": "CallbackInfo contains the state of a callback attached to a standalone Nexus operation." + }, + "apiNexusoperationV1CallbackInfoTrigger": { + "type": "object", + "properties": { + "operationCompleted": { + "$ref": "#/definitions/CallbackInfoOperationCompleted" + } + } + }, + "apiNexusoperationV1OnConflictOptions": { + "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 any new links to the running operation." + } + }, + "description": "When StartNexusOperationExecutionRequest uses the conflict policy NEXUS_OPERATION_ID_CONFLICT_POLICY_USE_EXISTING\nand there is already an existing, running standalone Nexus operation, OnConflictOptions defines actions to be\ntaken." + }, "apiWorkflowV1CallbackInfo": { "type": "object", "properties": { "callback": { - "$ref": "#/definitions/v1Callback", + "$ref": "#/definitions/commonV1Callback", "description": "Information on how this callback should be invoked (e.g. its URL and type)." }, "trigger": { @@ -13593,6 +13695,29 @@ }, "description": "When StartWorkflowExecution uses the conflict policy WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING and\nthere is already an existing running workflow, OnConflictOptions defines actions to be taken on\nthe existing running workflow. In this case, it will create a WorkflowExecutionOptionsUpdatedEvent\nhistory event in the running workflow with the changes requested in this object." }, + "commonV1Callback": { + "type": "object", + "properties": { + "nexus": { + "$ref": "#/definitions/CallbackNexus" + }, + "internal": { + "$ref": "#/definitions/CallbackInternal" + }, + "nexusHandler": { + "$ref": "#/definitions/CallbackNexusHandler" + }, + "links": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Link" + }, + "description": "Links associated with the callback. It can be used to link to underlying resources of the\ncallback." + } + }, + "description": "Callback to attach to various events in the system, e.g. workflow run completion." + }, "protobufAny": { "type": "object", "properties": { @@ -14686,26 +14811,6 @@ }, "description": "CalendarSpec describes an event specification relative to the calendar,\nsimilar to a traditional cron specification, but with labeled fields. Each\nfield can be one of:\n *: matches always\n x: matches when the field equals x\n x/y : matches when the field equals x+n*y where n is an integer\n x-z: matches when the field is between x and z inclusive\n w,x,y,...: matches when the field is one of the listed values\nEach x, y, z, ... is either a decimal integer, or a month or day of week name\nor abbreviation (in the appropriate fields).\nA timestamp matches if all fields match.\nNote that fields have different default values, for convenience.\nNote that the special case that some cron implementations have for treating\nday_of_month and day_of_week as \"or\" instead of \"and\" when both are set is\nnot implemented.\nday_of_week can accept 0 or 7 as Sunday\nCalendarSpec gets compiled into StructuredCalendarSpec, which is what will be\nreturned if you describe the schedule." }, - "v1Callback": { - "type": "object", - "properties": { - "nexus": { - "$ref": "#/definitions/CallbackNexus" - }, - "internal": { - "$ref": "#/definitions/CallbackInternal" - }, - "links": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Link" - }, - "description": "Links associated with the callback. It can be used to link to underlying resources of the\ncallback." - } - }, - "description": "Callback to attach to various events in the system, e.g. workflow run completion." - }, "v1CallbackState": { "type": "string", "enum": [ @@ -14718,7 +14823,7 @@ "CALLBACK_STATE_BLOCKED" ], "default": "CALLBACK_STATE_UNSPECIFIED", - "description": "State of a callback.\n\n - CALLBACK_STATE_UNSPECIFIED: Default value, unspecified state.\n - CALLBACK_STATE_STANDBY: Callback is standing by, waiting to be triggered.\n - CALLBACK_STATE_SCHEDULED: Callback is in the queue waiting to be executed or is currently executing.\n - CALLBACK_STATE_BACKING_OFF: Callback has failed with a retryable error and is backing off before the next attempt.\n - CALLBACK_STATE_FAILED: Callback has failed.\n - CALLBACK_STATE_SUCCEEDED: Callback has succeeded.\n - CALLBACK_STATE_BLOCKED: Callback is blocked (eg: by circuit breaker)." + "description": "State of a callback.\n\n - CALLBACK_STATE_UNSPECIFIED: Default value, unspecified state.\n - CALLBACK_STATE_STANDBY: Callback is standing by, waiting to be triggered.\n - CALLBACK_STATE_SCHEDULED: Callback is in the queue waiting to be executed or is currently executing.\n - CALLBACK_STATE_BACKING_OFF: Callback has failed with a retryable error and is backing off before the next attempt.\n - CALLBACK_STATE_FAILED: Callback has failed.\n - CALLBACK_STATE_SUCCEEDED: Callback has succeeded.\n - CALLBACK_STATE_BLOCKED: Callback is blocked, e.g. by circuit breaker." }, "v1CancelExternalWorkflowExecutionFailedCause": { "type": "string", @@ -15643,6 +15748,14 @@ "type": "string", "format": "byte", "description": "Token for follow-on long-poll requests. Absent only if the operation is complete." + }, + "completionCallbacks": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/apiNexusoperationV1CallbackInfo" + }, + "description": "Completion callbacks to be invoked once the Nexus operation reaches a terminal state.\nThey will remain in the CALLBACK_STATE_STANDBY state until the Nexus operation is finished." } } }, @@ -16023,17 +16136,18 @@ "type": "string" } }, - "description": "Identifies a specific execution within a namespace. This is used for standalone activities\nexecutions in batch jobs currently." + "description": "Identifies a specific execution within a namespace." }, "v1ExecutionType": { "type": "string", "enum": [ "EXECUTION_TYPE_UNSPECIFIED", "EXECUTION_TYPE_WORKFLOW", - "EXECUTION_TYPE_ACTIVITY" + "EXECUTION_TYPE_ACTIVITY", + "EXECUTION_TYPE_NEXUS_OPERATION" ], "default": "EXECUTION_TYPE_UNSPECIFIED", - "description": " - EXECUTION_TYPE_WORKFLOW: A workflow execution archetype.\n - EXECUTION_TYPE_ACTIVITY: An activity execution archetype. This is reserved for standalone activities." + "description": " - EXECUTION_TYPE_WORKFLOW: A workflow execution archetype.\n - EXECUTION_TYPE_ACTIVITY: An activity execution archetype. This is reserved for standalone activities.\n - EXECUTION_TYPE_NEXUS_OPERATION: A Nexus operation execution archetype. This is reserved for standalone Nexus operations." }, "v1ExternalWorkflowExecutionCancelRequestedEventAttributes": { "type": "object", @@ -16765,10 +16879,33 @@ }, "workflow": { "$ref": "#/definitions/LinkWorkflow" + }, + "callback": { + "$ref": "#/definitions/v1LinkCallback" } }, "description": "Link can be associated with history events. It might contain information about an external entity\nrelated to the history event. For example, workflow A makes a Nexus call that starts workflow B:\nin this case, a history event in workflow A could contain a Link to the workflow started event in\nworkflow B, and vice-versa." }, + "v1LinkCallback": { + "type": "object", + "properties": { + "namespace": { + "type": "string" + }, + "execution": { + "$ref": "#/definitions/v1Execution" + }, + "componentId": { + "type": "string", + "description": "In most cases, the Execution is sufficient to identify the callback's source. But for some types of execution,\na separate \"component ID\" is required. e.g. for completion callbacks attached to a workflow update. The\nexecution would be the workflow itself, with the component_id being the update ID of the update operation." + }, + "requestId": { + "type": "string", + "description": "Server-generate request ID sent when the callback was dispatched." + } + }, + "description": "A link to a worker callback attached to an execution. An execution (e.g. standalone Nexus operation) can have\nmultiple callbacks attached, and will be differentiated by the request_id used when the callback is invoked." + }, "v1ListActivityExecutionsResponse": { "type": "object", "properties": { @@ -18769,7 +18906,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Callback" + "$ref": "#/definitions/commonV1Callback" }, "description": "Callbacks to be called by the server when this update reaches a terminal state." }, @@ -21674,7 +21811,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Callback" + "$ref": "#/definitions/commonV1Callback" }, "description": "Completion callbacks attached to the running workflow execution." }, @@ -21890,7 +22027,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Callback" + "$ref": "#/definitions/commonV1Callback" }, "description": "Completion callbacks attached when this workflow was started." }, diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 1cba692a1..6c3d7c9fb 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -10826,6 +10826,8 @@ components: $ref: '#/components/schemas/Callback_Nexus' internal: $ref: '#/components/schemas/Callback_Internal' + nexusHandler: + $ref: '#/components/schemas/Callback_NexusHandler' links: type: array items: @@ -10878,6 +10880,17 @@ components: blockedReason: type: string description: If the state is BLOCKED, blocked reason provides additional information. + requestId: + type: string + description: |- + Server-generated request ID used as an idempotency token when invoking callbacks. + It has no relation to caller-side request_id sent in operations like StartNexusOperationExecutionRequest. + failure: + allOf: + - $ref: '#/components/schemas/Failure' + description: |- + The failure if the callback was not able to complete successfully. e.g. timed out, received an + unretriable error, etc. description: Common callback information. Specific CallbackInfo messages should embed this and may include additional fields. Callback_Internal: type: object @@ -10902,6 +10915,45 @@ components: additionalProperties: type: string description: Header to attach to callback request. + description: "Nexus callbacks are used to delivery Nexus operation completions, as defined in the Nexus RPC spec: \n https://github.com/nexus-rpc/api/blob/main/SPEC.md#callback-urls" + Callback_NexusHandler: + type: object + properties: + taskQueueName: + type: string + description: |- + Nexus task queue the Temporal worker is listening on. + + NOTE: This is not a temporal.api.taskqueue.v1.TaskQueue to avoid a circular dependency. + service: + type: string + description: Target Nexus service, e.g. "HTTPAdapter". + operation: + type: string + description: Target operation, e.g. "DeliverAsWebhook". + sourceContext: + allOf: + - $ref: '#/components/schemas/Payload' + description: |- + Arbitrary user-supplied data from the source operation's callsite. (As applicable, not all operations + support attaching context data.) + + There are restrictions on the maxium payload size a single callback can carry, as well as the + total sum of all source context payloads attached to an execution. See dynamic configuration + settings: "callback.worker.sourceContext.maxSize", "callback.worker.sourceContext.aggregateMaxSize". + description: |- + NexusHandler callbacks are requests to invoke a specific shape of Nexus operation on a Temporal worker. + The specified Nexus operation must have the following: + - Input: temporal.api.notificationservice.v1.OnCompleteRequest + - Output: temporal.api.notificationservice.v1.OnCompleteResponse + + The targeted Nexus service must be registered within the same namespace as the source operation + the callback is attached to. (While Nexus allows for cross-namespace operations, NexusHandler callbacks + are strictly caller-side.) + + NexusHandler callbacks are only supported for certain types of operations, e.g. standalone Nexus operations. + Attempting to attach a Worker callback for an unsupported operation will result in an INVALID_ARGUMENT + error from the server. CanceledFailureInfo: type: object properties: @@ -11886,6 +11938,13 @@ components: type: string description: Token for follow-on long-poll requests. Absent only if the operation is complete. format: bytes + completionCallbacks: + type: array + items: + $ref: '#/components/schemas/CallbackInfo' + description: |- + Completion callbacks to be invoked once the Nexus operation reaches a terminal state. + They will remain in the CALLBACK_STATE_STANDBY state until the Nexus operation is finished. DescribeScheduleResponse: type: object properties: @@ -12355,15 +12414,14 @@ components: - EXECUTION_TYPE_UNSPECIFIED - EXECUTION_TYPE_WORKFLOW - EXECUTION_TYPE_ACTIVITY + - EXECUTION_TYPE_NEXUS_OPERATION type: string format: enum businessId: type: string runId: type: string - description: |- - Identifies a specific execution within a namespace. This is used for standalone activities - executions in batch jobs currently. + description: Identifies a specific execution within a namespace. ExternalWorkflowExecutionCancelRequestedEventAttributes: type: object properties: @@ -13070,6 +13128,8 @@ components: $ref: '#/components/schemas/Link_NexusOperation' workflow: $ref: '#/components/schemas/Link_Workflow' + callback: + $ref: '#/components/schemas/Link_Callback' description: |- Link can be associated with history events. It might contain information about an external entity related to the history event. For example, workflow A makes a Nexus call that starts workflow B: @@ -13094,6 +13154,25 @@ components: A link to a built-in batch job. Batch jobs can be used to perform operations on a set of workflows (e.g. terminate, signal, cancel, etc). This link can be put on workflow history events generated by actions taken by a batch job. + Link_Callback: + type: object + properties: + namespace: + type: string + execution: + $ref: '#/components/schemas/Execution' + componentId: + type: string + description: |- + In most cases, the Execution is sufficient to identify the callback's source. But for some types of execution, + a separate "component ID" is required. e.g. for completion callbacks attached to a workflow update. The + execution would be the workflow itself, with the component_id being the update ID of the update operation. + requestId: + type: string + description: Server-generate request ID sent when the callback was dispatched. + description: |- + A link to a worker callback attached to an execution. An execution (e.g. standalone Nexus operation) can have + multiple callbacks attached, and will be differentiated by the request_id used when the callback is invoked. Link_NexusOperation: type: object properties: @@ -17330,6 +17409,13 @@ components: Defines how to resolve an operation id conflict with a *running* operation. The default policy is NEXUS_OPERATION_ID_CONFLICT_POLICY_FAIL. format: enum + onConflictOptions: + allOf: + - $ref: '#/components/schemas/OnConflictOptions' + description: |- + Defines actions to be done to the existing running standalone Nexus when the conflict policy + NEXUS_OPERATION_ID_CONFLICT_POLICY_USE_EXISTING is used. If not set or set to a empty object + (all options with default value), it will not modify the running operation. searchAttributes: allOf: - $ref: '#/components/schemas/SearchAttributes' @@ -17349,6 +17435,18 @@ components: allOf: - $ref: '#/components/schemas/UserMetadata' description: Metadata for use by user interfaces to display the fixed as-of-start summary and details of the operation. + completionCallbacks: + type: array + items: + $ref: '#/components/schemas/Callback' + description: Completion callbacks to be invoked once the Nexus operation reaches a terminal state. + links: + type: array + items: + $ref: '#/components/schemas/Link' + description: |- + Links to be associated with the Nexus operation. Callbacks may also have associated links; + links already included with a callback should not be duplicated here. StartNexusOperationExecutionResponse: type: object properties: diff --git a/temporal/api/callback/v1/message.proto b/temporal/api/callback/v1/message.proto index f881a4eef..ca5b7ea0b 100644 --- a/temporal/api/callback/v1/message.proto +++ b/temporal/api/callback/v1/message.proto @@ -9,6 +9,7 @@ option java_outer_classname = "MessageProto"; option ruby_package = "Temporalio::Api::Callback::V1"; option csharp_namespace = "Temporalio.Api.Callback.V1"; +import "google/protobuf/empty.proto"; import "google/protobuf/timestamp.proto"; import "temporal/api/common/v1/message.proto"; @@ -34,4 +35,17 @@ 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 + + // Server-generated request ID used as an idempotency token when invoking callbacks. + // It has no relation to caller-side request_id sent in operations like StartNexusOperationExecutionRequest. + string request_id = 9; + + // Result of the callback's execution, only set when the callback reaches a terminal state. + oneof result { + // The callback completed successfully. (Which may include delivering a "failed" result successfully.) + google.protobuf.Empty success = 10; + // The failure if the callback was not able to complete successfully. e.g. timed out, received an + // unretriable error, etc. + temporal.api.failure.v1.Failure failure = 11; + } +} diff --git a/temporal/api/common/v1/message.proto b/temporal/api/common/v1/message.proto index 3e2fc0e1c..15cc54660 100644 --- a/temporal/api/common/v1/message.proto +++ b/temporal/api/common/v1/message.proto @@ -68,8 +68,7 @@ message WorkflowExecution { string run_id = 2; } -// Identifies a specific execution within a namespace. This is used for standalone activities -// executions in batch jobs currently. +// Identifies a specific execution within a namespace. message Execution { temporal.api.enums.v1.ExecutionType type = 1; string business_id = 2; @@ -185,6 +184,8 @@ message ResetOptions { // Callback to attach to various events in the system, e.g. workflow run completion. message Callback { + // Nexus callbacks are used to delivery Nexus operation completions, as defined in the Nexus RPC spec: + // https://github.com/nexus-rpc/api/blob/main/SPEC.md#callback-urls message Nexus { // Callback URL. string url = 1; @@ -201,10 +202,43 @@ message Callback { bytes data = 1; } + // NexusHandler callbacks are requests to invoke a specific shape of Nexus operation on a Temporal worker. + // The specified Nexus operation must have the following: + // - Input: temporal.api.notificationservice.v1.OnCompleteRequest + // - Output: temporal.api.notificationservice.v1.OnCompleteResponse + // + // The targeted Nexus service must be registered within the same namespace as the source operation + // the callback is attached to. (While Nexus allows for cross-namespace operations, NexusHandler callbacks + // are strictly caller-side.) + // + // NexusHandler callbacks are only supported for certain types of operations, e.g. standalone Nexus operations. + // Attempting to attach a Worker callback for an unsupported operation will result in an INVALID_ARGUMENT + // error from the server. + message NexusHandler { + // Nexus task queue the Temporal worker is listening on. + // + // NOTE: This is not a temporal.api.taskqueue.v1.TaskQueue to avoid a circular dependency. + string task_queue_name = 1; + + // Target Nexus service, e.g. "HTTPAdapter". + string service = 2; + // Target operation, e.g. "DeliverAsWebhook". + string operation = 3; + + // Arbitrary user-supplied data from the source operation's callsite. (As applicable, not all operations + // support attaching context data.) + // + // There are restrictions on the maxium payload size a single callback can carry, as well as the + // total sum of all source context payloads attached to an execution. See dynamic configuration: + // "callback.nexusHandler.sourceContext.maxSize", "callback.nexusHandler.sourceContext.aggregateMaxSize". + temporal.api.common.v1.Payload source_context = 4; + } + reserved 1; // For a generic callback mechanism to be added later. oneof variant { Nexus nexus = 2; Internal internal = 3; + NexusHandler nexus_handler = 4; } // Links associated with the callback. It can be used to link to underlying resources of the @@ -273,12 +307,27 @@ message Link { string reason = 4; } + // A link to a worker callback attached to an execution. An execution (e.g. standalone Nexus operation) can have + // multiple callbacks attached, and will be differentiated by the request_id used when the callback is invoked. + message Callback { + string namespace = 1; + Execution execution = 2; + // In most cases, the Execution is sufficient to identify the callback's source. But for some types of execution, + // a separate "component ID" is required. e.g. for completion callbacks attached to a workflow update. The + // execution would be the workflow itself, with the component_id being the update ID of the update operation. + string component_id = 3; + + // Server-generate request ID sent when the callback was dispatched. + string request_id = 4; + } + oneof variant { WorkflowEvent workflow_event = 1; BatchJob batch_job = 2; Activity activity = 3; NexusOperation nexus_operation = 4; Workflow workflow = 5; + Callback callback = 6; } } diff --git a/temporal/api/enums/v1/common.proto b/temporal/api/enums/v1/common.proto index cdc387173..ef8381cda 100644 --- a/temporal/api/enums/v1/common.proto +++ b/temporal/api/enums/v1/common.proto @@ -47,7 +47,7 @@ enum CallbackState { CALLBACK_STATE_FAILED = 4; // Callback has succeeded. CALLBACK_STATE_SUCCEEDED = 5; - // Callback is blocked (eg: by circuit breaker). + // Callback is blocked, e.g. by circuit breaker. CALLBACK_STATE_BLOCKED = 6; } @@ -113,4 +113,6 @@ enum ExecutionType { EXECUTION_TYPE_WORKFLOW = 1; // An activity execution archetype. This is reserved for standalone activities. EXECUTION_TYPE_ACTIVITY = 2; -} \ No newline at end of file + // A Nexus operation execution archetype. This is reserved for standalone Nexus operations. + EXECUTION_TYPE_NEXUS_OPERATION = 3; +} diff --git a/temporal/api/nexusoperation/v1/message.proto b/temporal/api/nexusoperation/v1/message.proto new file mode 100644 index 000000000..f247013b0 --- /dev/null +++ b/temporal/api/nexusoperation/v1/message.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; + +package temporal.api.nexusoperation.v1; + +option go_package = "go.temporal.io/api/nexusoperation/v1;nexusoperation"; +option java_package = "io.temporal.api.nexusoperation.v1"; +option java_multiple_files = true; +option java_outer_classname = "MessageProto"; +option ruby_package = "Temporalio::Api::NexusOperation::V1"; +option csharp_namespace = "Temporalio.Api.NexusOperation.V1"; + +import "temporal/api/callback/v1/message.proto"; + +// CallbackInfo contains the state of a callback attached to a standalone Nexus operation. +message CallbackInfo { + // Trigger for when the Nexus operation is completed, covering both success cases as + // well as any type of failure. + message OperationCompleted {} + + message Trigger { + oneof variant { + OperationCompleted operation_completed = 1; + } + } + + // Trigger for this callback. + Trigger trigger = 1; + // Common callback info. + temporal.api.callback.v1.CallbackInfo info = 2; +} + +// When StartNexusOperationExecutionRequest uses the conflict policy NEXUS_OPERATION_ID_CONFLICT_POLICY_USE_EXISTING +// and there is already an existing, running standalone Nexus operation, OnConflictOptions defines actions to be +// taken. +message OnConflictOptions { + // Attaches the request ID to the running operation. + bool attach_request_id = 1; + // Attaches the completion callbacks to the running operation. + bool attach_completion_callbacks = 2; + // Attaches any new links to the running operation. + bool attach_links = 3; +} diff --git a/temporal/api/notificationservice/v1/request_response.proto b/temporal/api/notificationservice/v1/request_response.proto new file mode 100644 index 000000000..9a7ac529f --- /dev/null +++ b/temporal/api/notificationservice/v1/request_response.proto @@ -0,0 +1,37 @@ +syntax = "proto3"; + +package temporal.api.notificationservice.v1; + +option go_package = "go.temporal.io/api/notificationservice/v1;notificationservice"; +option java_package = "io.temporal.api.notificationservice.v1"; +option java_multiple_files = true; +option java_outer_classname = "RequestResponseProto"; +option ruby_package = "Temporalio::Api::NotificationService::V1"; +option csharp_namespace = "Temporalio.Api.NotificationService.V1"; + +import "temporal/api/common/v1/message.proto"; +import "temporal/api/failure/v1/message.proto"; + +// OnCompleteRequest is the request type to the NotificationService's OnComplete operation, +// allowing for defining completion handlers for arbitrary operations. +// +// Information about the source operation will be available in the form of a commonpb.Link, +// which will be available separately from this OnCompleteRequest. e.g. a link to the source +// standalone Nexus operation would be found in the nexuspb.StartOperationRequest parameter +// sent to the worker callback. (In addition to this OnCompleteRequest.) +message OnCompleteRequest { + + // The result of the source operation. + oneof result { + // The operation was successful, and resulted in the given payload. + temporal.api.common.v1.Payload success = 1; + // The operation failed. Includes timeout, cancellation, and application errors. + temporal.api.failure.v1.Failure failure = 2; + } + + // User-supplied data which was added to the source invocation. (As applicable.) + temporal.api.common.v1.Payload source_context = 3; +} + +// OnCompleteResponse is the return type of the OnComplete operation. +message OnCompleteResponse {} diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index de1c271cd..1aae988d8 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -45,6 +45,7 @@ import "temporal/api/batch/v1/message.proto"; import "temporal/api/sdk/v1/task_complete_metadata.proto"; import "temporal/api/sdk/v1/user_metadata.proto"; import "temporal/api/nexus/v1/message.proto"; +import "temporal/api/nexusoperation/v1/message.proto"; import "temporal/api/worker/v1/message.proto"; import "google/protobuf/duration.proto"; @@ -3404,6 +3405,10 @@ message StartNexusOperationExecutionRequest { // Defines how to resolve an operation id conflict with a *running* operation. // The default policy is NEXUS_OPERATION_ID_CONFLICT_POLICY_FAIL. temporal.api.enums.v1.NexusOperationIdConflictPolicy id_conflict_policy = 13; + // Defines actions to be done to the existing running standalone Nexus when the conflict policy + // NEXUS_OPERATION_ID_CONFLICT_POLICY_USE_EXISTING is used. If not set or set to a empty object + // (all options with default value), it will not modify the running operation. + temporal.api.nexusoperation.v1.OnConflictOptions on_conflict_options = 17; // Search attributes for indexing. temporal.api.common.v1.SearchAttributes search_attributes = 14; @@ -3416,6 +3421,12 @@ message StartNexusOperationExecutionRequest { map nexus_header = 15; // Metadata for use by user interfaces to display the fixed as-of-start summary and details of the operation. temporal.api.sdk.v1.UserMetadata user_metadata = 16; + + // Completion callbacks to be invoked once the Nexus operation reaches a terminal state. + repeated temporal.api.common.v1.Callback completion_callbacks = 18; + // Links to be associated with the Nexus operation. Callbacks may also have associated links; + // links already included with a callback should not be duplicated here. + repeated temporal.api.common.v1.Link links = 19; } message StartNexusOperationExecutionResponse { @@ -3464,6 +3475,10 @@ message DescribeNexusOperationExecutionResponse { // Token for follow-on long-poll requests. Absent only if the operation is complete. bytes long_poll_token = 6; + + // Completion callbacks to be invoked once the Nexus operation reaches a terminal state. + // They will remain in the CALLBACK_STATE_STANDBY state until the Nexus operation is finished. + repeated temporal.api.nexusoperation.v1.CallbackInfo completion_callbacks = 7; } message PollNexusOperationExecutionRequest {