From 0cea08db603d8d634ca5aa0854e9cce938241dd9 Mon Sep 17 00:00:00 2001 From: long-nt-tran Date: Thu, 30 Apr 2026 17:08:03 -0400 Subject: [PATCH 1/3] Add API for GetWorkflowExecutionResult --- openapi/openapiv2.json | 161 ++++++++++++++++++ openapi/openapiv3.yaml | 159 +++++++++++++++++ .../workflowservice/v1/request_response.proto | 38 +++++ temporal/api/workflowservice/v1/service.proto | 16 ++ 4 files changed, 374 insertions(+) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 917fce76c..ebe6858e2 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -4134,6 +4134,62 @@ ] } }, + "/api/v1/namespaces/{namespace}/workflows/{execution.workflowId}/result": { + "get": { + "summary": "GetWorkflowExecutionResult returns the result of a workflow execution. If the workflow\nis still running, returns a NotCompleted response and optionally registers callbacks\nto be invoked when the workflow completes.", + "operationId": "GetWorkflowExecutionResult2", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetWorkflowExecutionResultResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "execution.workflowId", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "execution.runId", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "requestId", + "description": "Used to de-dup requests (i.e., so we don't register the same callbacks multiple times).", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "identity", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "WorkflowService" + ] + } + }, "/api/v1/namespaces/{namespace}/workflows/{execution.workflowId}/trigger-rule": { "post": { "summary": "TriggerWorkflowRule allows to:\n * trigger existing rule for a specific workflow execution;\n * trigger rule for a specific workflow execution without creating a rule;\nThis is useful for one-off operations.", @@ -9609,6 +9665,62 @@ ] } }, + "/namespaces/{namespace}/workflows/{execution.workflowId}/result": { + "get": { + "summary": "GetWorkflowExecutionResult returns the result of a workflow execution. If the workflow\nis still running, returns a NotCompleted response and optionally registers callbacks\nto be invoked when the workflow completes.", + "operationId": "GetWorkflowExecutionResult", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetWorkflowExecutionResultResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "execution.workflowId", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "execution.runId", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "requestId", + "description": "Used to de-dup requests (i.e., so we don't register the same callbacks multiple times).", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "identity", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "WorkflowService" + ] + } + }, "/namespaces/{namespace}/workflows/{execution.workflowId}/trigger-rule": { "post": { "summary": "TriggerWorkflowRule allows to:\n * trigger existing rule for a specific workflow execution;\n * trigger rule for a specific workflow execution without creating a rule;\nThis is useful for one-off operations.", @@ -10706,6 +10818,36 @@ }, "description": "Target a worker polling on a Nexus task queue in a specific namespace." }, + "GetWorkflowExecutionResultResponseCompleted": { + "type": "object", + "properties": { + "execution": { + "$ref": "#/definitions/v1WorkflowExecution" + }, + "status": { + "$ref": "#/definitions/v1WorkflowExecutionStatus" + }, + "result": { + "$ref": "#/definitions/v1Payloads", + "description": "Set only when status = COMPLETED." + }, + "failure": { + "$ref": "#/definitions/v1Failure", + "description": "Set for FAILED / CANCELED / TERMINATED / TIMED_OUT." + } + } + }, + "GetWorkflowExecutionResultResponseNotCompleted": { + "type": "object", + "properties": { + "execution": { + "$ref": "#/definitions/v1WorkflowExecution" + }, + "status": { + "$ref": "#/definitions/v1WorkflowExecutionStatus" + } + } + }, "LinkActivity": { "type": "object", "properties": { @@ -15655,6 +15797,25 @@ } } }, + "v1GetWorkflowExecutionResultResponse": { + "type": "object", + "properties": { + "links": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Link" + }, + "title": "Link to the relevant history event:\n- completion event, if the workflow has finished\n- options-updated event, if callbacks were registered on a running workflow" + }, + "notCompleted": { + "$ref": "#/definitions/GetWorkflowExecutionResultResponseNotCompleted" + }, + "completed": { + "$ref": "#/definitions/GetWorkflowExecutionResultResponseCompleted" + } + } + }, "v1Header": { "type": "object", "properties": { diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 4ada710f0..5a0aa634e 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -3714,6 +3714,56 @@ paths: application/json: schema: $ref: '#/components/schemas/Status' + /api/v1/namespaces/{namespace}/workflows/{execution.workflow_id}/result: + get: + tags: + - WorkflowService + description: |- + GetWorkflowExecutionResult returns the result of a workflow execution. If the workflow + is still running, returns a NotCompleted response and optionally registers callbacks + to be invoked when the workflow completes. + operationId: GetWorkflowExecutionResult + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: execution.workflow_id + in: path + required: true + schema: + type: string + - name: execution.workflowId + in: query + schema: + type: string + - name: execution.runId + in: query + schema: + type: string + - name: requestId + in: query + description: Used to de-dup requests (i.e., so we don't register the same callbacks multiple times). + schema: + type: string + - name: identity + in: query + schema: + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/GetWorkflowExecutionResultResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' /api/v1/namespaces/{namespace}/workflows/{execution.workflow_id}/trigger-rule: post: tags: @@ -8659,6 +8709,56 @@ paths: application/json: schema: $ref: '#/components/schemas/Status' + /namespaces/{namespace}/workflows/{execution.workflow_id}/result: + get: + tags: + - WorkflowService + description: |- + GetWorkflowExecutionResult returns the result of a workflow execution. If the workflow + is still running, returns a NotCompleted response and optionally registers callbacks + to be invoked when the workflow completes. + operationId: GetWorkflowExecutionResult + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: execution.workflow_id + in: path + required: true + schema: + type: string + - name: execution.workflowId + in: query + schema: + type: string + - name: execution.runId + in: query + schema: + type: string + - name: requestId + in: query + description: Used to de-dup requests (i.e., so we don't register the same callbacks multiple times). + schema: + type: string + - name: identity + in: query + schema: + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/GetWorkflowExecutionResultResponse' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' /namespaces/{namespace}/workflows/{execution.workflow_id}/trigger-rule: post: tags: @@ -12149,6 +12249,65 @@ components: type: string description: Will be set if there are more history events than were included in this response format: bytes + GetWorkflowExecutionResultResponse: + type: object + properties: + links: + type: array + items: + $ref: '#/components/schemas/Link' + description: |- + Link to the relevant history event: + - completion event, if the workflow has finished + - options-updated event, if callbacks were registered on a running workflow + notCompleted: + $ref: '#/components/schemas/GetWorkflowExecutionResultResponse_NotCompleted' + completed: + $ref: '#/components/schemas/GetWorkflowExecutionResultResponse_Completed' + GetWorkflowExecutionResultResponse_Completed: + type: object + properties: + execution: + $ref: '#/components/schemas/WorkflowExecution' + status: + enum: + - WORKFLOW_EXECUTION_STATUS_UNSPECIFIED + - WORKFLOW_EXECUTION_STATUS_RUNNING + - WORKFLOW_EXECUTION_STATUS_COMPLETED + - WORKFLOW_EXECUTION_STATUS_FAILED + - WORKFLOW_EXECUTION_STATUS_CANCELED + - WORKFLOW_EXECUTION_STATUS_TERMINATED + - WORKFLOW_EXECUTION_STATUS_CONTINUED_AS_NEW + - WORKFLOW_EXECUTION_STATUS_TIMED_OUT + - WORKFLOW_EXECUTION_STATUS_PAUSED + type: string + format: enum + result: + allOf: + - $ref: '#/components/schemas/Payloads' + description: Set only when status = COMPLETED. + failure: + allOf: + - $ref: '#/components/schemas/Failure' + description: Set for FAILED / CANCELED / TERMINATED / TIMED_OUT. + GetWorkflowExecutionResultResponse_NotCompleted: + type: object + properties: + execution: + $ref: '#/components/schemas/WorkflowExecution' + status: + enum: + - WORKFLOW_EXECUTION_STATUS_UNSPECIFIED + - WORKFLOW_EXECUTION_STATUS_RUNNING + - WORKFLOW_EXECUTION_STATUS_COMPLETED + - WORKFLOW_EXECUTION_STATUS_FAILED + - WORKFLOW_EXECUTION_STATUS_CANCELED + - WORKFLOW_EXECUTION_STATUS_TERMINATED + - WORKFLOW_EXECUTION_STATUS_CONTINUED_AS_NEW + - WORKFLOW_EXECUTION_STATUS_TIMED_OUT + - WORKFLOW_EXECUTION_STATUS_PAUSED + type: string + format: enum GoogleProtobufAny: type: object properties: diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index f4012c73d..933727894 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -1163,6 +1163,44 @@ message DescribeWorkflowExecutionResponse { temporal.api.workflow.v1.WorkflowExecutionExtendedInfo workflow_extended_info = 8; } +message GetWorkflowExecutionResultRequest { + string namespace = 1; + temporal.api.common.v1.WorkflowExecution execution = 2; + // Used to de-dup requests (i.e., so we don't register the same callbacks multiple times). + string request_id = 3; + string identity = 4; + // Callbacks and links to register if the workflow is not yet completed. + repeated temporal.api.common.v1.Callback callbacks = 5; + repeated temporal.api.common.v1.Link links = 6; +} + +message GetWorkflowExecutionResultResponse { + // Link to the relevant history event: + // - completion event, if the workflow has finished + // - options-updated event, if callbacks were registered on a running workflow + repeated temporal.api.common.v1.Link links = 1; + + // Completion status of the workflow, which carries relevant information for the caller. + oneof completion { + NotCompleted not_completed = 2; + Completed completed = 3; + } + + message NotCompleted { + temporal.api.common.v1.WorkflowExecution execution = 1; + temporal.api.enums.v1.WorkflowExecutionStatus status = 2; + } + + message Completed { + temporal.api.common.v1.WorkflowExecution execution = 1; + temporal.api.enums.v1.WorkflowExecutionStatus status = 2; + // Set only when status = COMPLETED. + temporal.api.common.v1.Payloads result = 3; + // Set for FAILED / CANCELED / TERMINATED / TIMED_OUT. + temporal.api.failure.v1.Failure failure = 4; + } +} + // (-- api-linter: core::0203::optional=disabled // aip.dev/not-precedent: field_behavior annotation not available in our gogo fork --) message DescribeTaskQueueRequest { diff --git a/temporal/api/workflowservice/v1/service.proto b/temporal/api/workflowservice/v1/service.proto index b804f3f03..df5652ddb 100644 --- a/temporal/api/workflowservice/v1/service.proto +++ b/temporal/api/workflowservice/v1/service.proto @@ -2023,4 +2023,20 @@ service WorkflowService { // (-- api-linter: core::0127::http-annotation=disabled // aip.dev/not-precedent: Nexus operation deletion not exposed to HTTP, users should use cancel or terminate. --) rpc DeleteNexusOperationExecution (DeleteNexusOperationExecutionRequest) returns (DeleteNexusOperationExecutionResponse) {} + + // GetWorkflowExecutionResult returns the result of a workflow execution. If the workflow + // is still running, returns a NotCompleted response and optionally registers callbacks + // to be invoked when the workflow completes. + rpc GetWorkflowExecutionResult (GetWorkflowExecutionResultRequest) returns (GetWorkflowExecutionResultResponse) { + option (google.api.http) = { + get: "/namespaces/{namespace}/workflows/{execution.workflow_id}/result" + additional_bindings { + get: "/api/v1/namespaces/{namespace}/workflows/{execution.workflow_id}/result" + } + }; + option (temporal.api.protometa.v1.request_header) = { + header: "temporal-resource-id" + value: "workflow:{execution.workflow_id}" + }; + } } From f56de32e2d0202260980371f19da55ad305cf21e Mon Sep 17 00:00:00 2001 From: long-nt-tran Date: Fri, 8 May 2026 11:14:54 -0400 Subject: [PATCH 2/3] Address PR feedback - Split enums to be more granular (NotCompleted/Success/Failure) - Move some common fields to base message - Comment regarding always getting result of latest run for a workflow_id --- openapi/openapiv2.json | 210 +++++++++--------- openapi/openapiv3.yaml | 60 ++--- .../workflowservice/v1/request_response.proto | 29 +-- 3 files changed, 143 insertions(+), 156 deletions(-) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index ebe6858e2..1b00e04e4 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -10818,33 +10818,14 @@ }, "description": "Target a worker polling on a Nexus task queue in a specific namespace." }, - "GetWorkflowExecutionResultResponseCompleted": { - "type": "object", - "properties": { - "execution": { - "$ref": "#/definitions/v1WorkflowExecution" - }, - "status": { - "$ref": "#/definitions/v1WorkflowExecutionStatus" - }, - "result": { - "$ref": "#/definitions/v1Payloads", - "description": "Set only when status = COMPLETED." - }, - "failure": { - "$ref": "#/definitions/v1Failure", - "description": "Set for FAILED / CANCELED / TERMINATED / TIMED_OUT." - } - } - }, "GetWorkflowExecutionResultResponseNotCompleted": { + "type": "object" + }, + "GetWorkflowExecutionResultResponseSuccess": { "type": "object", "properties": { - "execution": { - "$ref": "#/definitions/v1WorkflowExecution" - }, - "status": { - "$ref": "#/definitions/v1WorkflowExecutionStatus" + "result": { + "$ref": "#/definitions/v1Payloads" } } }, @@ -13111,7 +13092,7 @@ "description": "The time when the last attempt completed." }, "lastAttemptFailure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "The last attempt's failure, if any." }, "nextAttemptScheduleTime": { @@ -13174,7 +13155,7 @@ "description": "The time when the last attempt completed." }, "lastAttemptFailure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "The last attempt's failure, if any." }, "nextAttemptScheduleTime": { @@ -13215,6 +13196,58 @@ }, "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." }, + "failureV1Failure": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "source": { + "type": "string", + "description": "The source this Failure originated in, e.g. TypeScriptSDK / JavaSDK\nIn some SDKs this is used to rehydrate the stack trace into an exception object." + }, + "stackTrace": { + "type": "string" + }, + "encodedAttributes": { + "$ref": "#/definitions/v1Payload", + "description": "Alternative way to supply `message` and `stack_trace` and possibly other attributes, used for encryption of\nerrors originating in user code which might contain sensitive information.\nThe `encoded_attributes` Payload could represent any serializable object, e.g. JSON object or a `Failure` proto\nmessage.\n\nSDK authors:\n- The SDK should provide a default `encodeFailureAttributes` and `decodeFailureAttributes` implementation that:\n - Uses a JSON object to represent `{ message, stack_trace }`.\n - Overwrites the original message with \"Encoded failure\" to indicate that more information could be extracted.\n - Overwrites the original stack_trace with an empty string.\n - The resulting JSON object is converted to Payload using the default PayloadConverter and should be processed\n by the user-provided PayloadCodec\n\n- If there's demand, we could allow overriding the default SDK implementation to encode other opaque Failure attributes." + }, + "cause": { + "$ref": "#/definitions/failureV1Failure" + }, + "applicationFailureInfo": { + "$ref": "#/definitions/v1ApplicationFailureInfo" + }, + "timeoutFailureInfo": { + "$ref": "#/definitions/v1TimeoutFailureInfo" + }, + "canceledFailureInfo": { + "$ref": "#/definitions/v1CanceledFailureInfo" + }, + "terminatedFailureInfo": { + "$ref": "#/definitions/v1TerminatedFailureInfo" + }, + "serverFailureInfo": { + "$ref": "#/definitions/v1ServerFailureInfo" + }, + "resetWorkflowFailureInfo": { + "$ref": "#/definitions/v1ResetWorkflowFailureInfo" + }, + "activityFailureInfo": { + "$ref": "#/definitions/v1ActivityFailureInfo" + }, + "childWorkflowExecutionFailureInfo": { + "$ref": "#/definitions/v1ChildWorkflowExecutionFailureInfo" + }, + "nexusOperationExecutionFailureInfo": { + "$ref": "#/definitions/v1NexusOperationFailureInfo" + }, + "nexusHandlerFailureInfo": { + "$ref": "#/definitions/v1NexusHandlerFailureInfo" + } + } + }, "protobufAny": { "type": "object", "properties": { @@ -13329,7 +13362,7 @@ "description": "Time when the activity transitioned to a closed state." }, "lastFailure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "Failure details from the last failed attempt." }, "lastWorkerIdentity": { @@ -13459,7 +13492,7 @@ "description": "The result if the activity completed successfully." }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "The failure if the activity completed unsuccessfully." } }, @@ -13649,7 +13682,7 @@ "type": "object", "properties": { "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "title": "Failure details" }, "scheduledEventId": { @@ -13751,7 +13784,7 @@ "title": "Starting at 1, the number of times this task has been attempted" }, "lastFailure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "Will be set to the most recent failure details, if this task has previously failed and then\nbeen retried." }, "workerVersion": { @@ -13769,7 +13802,7 @@ "type": "object", "properties": { "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "If this activity had failed, was retried, and then timed out, that failure is stored as the\n`cause` in here." }, "scheduledEventId": { @@ -14337,7 +14370,7 @@ "type": "object", "properties": { "failure": { - "$ref": "#/definitions/v1Failure" + "$ref": "#/definitions/failureV1Failure" }, "namespace": { "type": "string", @@ -15122,7 +15155,7 @@ "description": "The result if the operation completed successfully." }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "The failure if the operation completed unsuccessfully." }, "longPollToken": { @@ -15502,58 +15535,6 @@ }, "title": "Represents a historical replication status of a Namespace" }, - "v1Failure": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "source": { - "type": "string", - "description": "The source this Failure originated in, e.g. TypeScriptSDK / JavaSDK\nIn some SDKs this is used to rehydrate the stack trace into an exception object." - }, - "stackTrace": { - "type": "string" - }, - "encodedAttributes": { - "$ref": "#/definitions/v1Payload", - "description": "Alternative way to supply `message` and `stack_trace` and possibly other attributes, used for encryption of\nerrors originating in user code which might contain sensitive information.\nThe `encoded_attributes` Payload could represent any serializable object, e.g. JSON object or a `Failure` proto\nmessage.\n\nSDK authors:\n- The SDK should provide a default `encodeFailureAttributes` and `decodeFailureAttributes` implementation that:\n - Uses a JSON object to represent `{ message, stack_trace }`.\n - Overwrites the original message with \"Encoded failure\" to indicate that more information could be extracted.\n - Overwrites the original stack_trace with an empty string.\n - The resulting JSON object is converted to Payload using the default PayloadConverter and should be processed\n by the user-provided PayloadCodec\n\n- If there's demand, we could allow overriding the default SDK implementation to encode other opaque Failure attributes." - }, - "cause": { - "$ref": "#/definitions/v1Failure" - }, - "applicationFailureInfo": { - "$ref": "#/definitions/v1ApplicationFailureInfo" - }, - "timeoutFailureInfo": { - "$ref": "#/definitions/v1TimeoutFailureInfo" - }, - "canceledFailureInfo": { - "$ref": "#/definitions/v1CanceledFailureInfo" - }, - "terminatedFailureInfo": { - "$ref": "#/definitions/v1TerminatedFailureInfo" - }, - "serverFailureInfo": { - "$ref": "#/definitions/v1ServerFailureInfo" - }, - "resetWorkflowFailureInfo": { - "$ref": "#/definitions/v1ResetWorkflowFailureInfo" - }, - "activityFailureInfo": { - "$ref": "#/definitions/v1ActivityFailureInfo" - }, - "childWorkflowExecutionFailureInfo": { - "$ref": "#/definitions/v1ChildWorkflowExecutionFailureInfo" - }, - "nexusOperationExecutionFailureInfo": { - "$ref": "#/definitions/v1NexusOperationFailureInfo" - }, - "nexusHandlerFailureInfo": { - "$ref": "#/definitions/v1NexusHandlerFailureInfo" - } - } - }, "v1FetchWorkerConfigResponse": { "type": "object", "properties": { @@ -15800,6 +15781,12 @@ "v1GetWorkflowExecutionResultResponse": { "type": "object", "properties": { + "execution": { + "$ref": "#/definitions/v1WorkflowExecution" + }, + "status": { + "$ref": "#/definitions/v1WorkflowExecutionStatus" + }, "links": { "type": "array", "items": { @@ -15811,8 +15798,19 @@ "notCompleted": { "$ref": "#/definitions/GetWorkflowExecutionResultResponseNotCompleted" }, - "completed": { - "$ref": "#/definitions/GetWorkflowExecutionResultResponseCompleted" + "success": { + "$ref": "#/definitions/GetWorkflowExecutionResultResponseSuccess" + }, + "failure": { + "$ref": "#/definitions/v1GetWorkflowExecutionResultResponseFailure" + } + } + }, + "v1GetWorkflowExecutionResultResponseFailure": { + "type": "object", + "properties": { + "failure": { + "$ref": "#/definitions/failureV1Failure" } } }, @@ -16426,7 +16424,7 @@ "$ref": "#/definitions/v1Header" }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "Some uses of markers, like a local activity, could \"fail\". If they did that is recorded here." } } @@ -16768,7 +16766,7 @@ "description": "The `WORKFLOW_TASK_COMPLETED` event that the corresponding RequestCancelNexusOperation command was reported\nwith." }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "Failure details. A NexusOperationFailureInfo wrapping a CanceledFailureInfo." }, "scheduledEventId": { @@ -16802,7 +16800,7 @@ "description": "The ID of the `NEXUS_OPERATION_SCHEDULED` event. Uniquely identifies this operation." }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "Cancellation details." }, "requestId": { @@ -16834,7 +16832,7 @@ "description": "The time when the last attempt completed." }, "lastAttemptFailure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "The last attempt's failure, if any." }, "nextAttemptScheduleTime": { @@ -16904,7 +16902,7 @@ "description": "The time when the last attempt completed." }, "lastAttemptFailure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "The last attempt's failure, if any." }, "nextAttemptScheduleTime": { @@ -16991,7 +16989,7 @@ "description": "The time when the last attempt completed." }, "lastAttemptFailure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "The last attempt's failure, if any." }, "nextAttemptScheduleTime": { @@ -17128,7 +17126,7 @@ "description": "The ID of the `NEXUS_OPERATION_SCHEDULED` event. Uniquely identifies this operation." }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "Failure details. A NexusOperationFailureInfo wrapping an ApplicationFailureInfo." }, "requestId": { @@ -17276,7 +17274,7 @@ "description": "The ID of the `NEXUS_OPERATION_SCHEDULED` event. Uniquely identifies this operation." }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "Failure details. A NexusOperationFailureInfo wrapping a CanceledFailureInfo." }, "requestId": { @@ -17303,7 +17301,7 @@ "$ref": "#/definitions/v1Payloads" }, "failure": { - "$ref": "#/definitions/v1Failure" + "$ref": "#/definitions/failureV1Failure" } }, "description": "The outcome of a Workflow Update: success or failure." @@ -17390,7 +17388,7 @@ "format": "date-time" }, "lastFailure": { - "$ref": "#/definitions/v1Failure" + "$ref": "#/definitions/failureV1Failure" }, "lastWorkerIdentity": { "type": "string" @@ -17528,7 +17526,7 @@ "description": "The time when the last attempt completed." }, "lastAttemptFailure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "The last attempt's failure, if any." }, "nextAttemptScheduleTime": { @@ -17654,7 +17652,7 @@ "description": "The result if the operation completed successfully." }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "The failure if the operation completed unsuccessfully." } } @@ -18325,7 +18323,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Failure" + "$ref": "#/definitions/failureV1Failure" }, "title": "Server validation failures could include\nlast_heartbeat_details payload is too large, request failure is too large" } @@ -18338,7 +18336,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Failure" + "$ref": "#/definitions/failureV1Failure" }, "title": "Server validation failures could include\nlast_heartbeat_details payload is too large, request failure is too large" } @@ -20609,7 +20607,7 @@ "$ref": "#/definitions/v1ContinueAsNewInitiator" }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "Deprecated. If a workflow's retry policy would cause a new run to start when the current one\nhas failed, this field would be populated with that failure. Now (when supported by server\nand sdk) the final event will be `WORKFLOW_EXECUTION_FAILED` with `new_execution_run_id` set." }, "lastCompletionResult": { @@ -20684,7 +20682,7 @@ "type": "object", "properties": { "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "title": "Serialized result of workflow failure (ex: An exception thrown, or error returned)" }, "retryState": { @@ -20977,7 +20975,7 @@ "$ref": "#/definitions/v1ContinueAsNewInitiator" }, "continuedFailure": { - "$ref": "#/definitions/v1Failure" + "$ref": "#/definitions/failureV1Failure" }, "lastCompletionResult": { "$ref": "#/definitions/v1Payloads" @@ -21251,7 +21249,7 @@ "description": "The message payload of the original request message that initiated this\nupdate." }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "description": "The cause of rejection." } } @@ -21587,7 +21585,7 @@ "$ref": "#/definitions/v1WorkflowTaskFailedCause" }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/failureV1Failure", "title": "The failure details" }, "identity": { diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 5a0aa634e..d58fef8fc 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -12250,21 +12250,6 @@ components: description: Will be set if there are more history events than were included in this response format: bytes GetWorkflowExecutionResultResponse: - type: object - properties: - links: - type: array - items: - $ref: '#/components/schemas/Link' - description: |- - Link to the relevant history event: - - completion event, if the workflow has finished - - options-updated event, if callbacks were registered on a running workflow - notCompleted: - $ref: '#/components/schemas/GetWorkflowExecutionResultResponse_NotCompleted' - completed: - $ref: '#/components/schemas/GetWorkflowExecutionResultResponse_Completed' - GetWorkflowExecutionResultResponse_Completed: type: object properties: execution: @@ -12282,32 +12267,33 @@ components: - WORKFLOW_EXECUTION_STATUS_PAUSED type: string format: enum - result: - allOf: - - $ref: '#/components/schemas/Payloads' - description: Set only when status = COMPLETED. + links: + type: array + items: + $ref: '#/components/schemas/Link' + description: |- + Link to the relevant history event: + - completion event, if the workflow has finished + - options-updated event, if callbacks were registered on a running workflow + notCompleted: + $ref: '#/components/schemas/GetWorkflowExecutionResultResponse_NotCompleted' + success: + $ref: '#/components/schemas/GetWorkflowExecutionResultResponse_Success' failure: - allOf: - - $ref: '#/components/schemas/Failure' - description: Set for FAILED / CANCELED / TERMINATED / TIMED_OUT. + $ref: '#/components/schemas/GetWorkflowExecutionResultResponse_Failure' + GetWorkflowExecutionResultResponse_Failure: + type: object + properties: + failure: + $ref: '#/components/schemas/Failure' GetWorkflowExecutionResultResponse_NotCompleted: + type: object + properties: {} + GetWorkflowExecutionResultResponse_Success: type: object properties: - execution: - $ref: '#/components/schemas/WorkflowExecution' - status: - enum: - - WORKFLOW_EXECUTION_STATUS_UNSPECIFIED - - WORKFLOW_EXECUTION_STATUS_RUNNING - - WORKFLOW_EXECUTION_STATUS_COMPLETED - - WORKFLOW_EXECUTION_STATUS_FAILED - - WORKFLOW_EXECUTION_STATUS_CANCELED - - WORKFLOW_EXECUTION_STATUS_TERMINATED - - WORKFLOW_EXECUTION_STATUS_CONTINUED_AS_NEW - - WORKFLOW_EXECUTION_STATUS_TIMED_OUT - - WORKFLOW_EXECUTION_STATUS_PAUSED - type: string - format: enum + result: + $ref: '#/components/schemas/Payloads' GoogleProtobufAny: type: object properties: diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index 933727894..10ae81d06 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -1165,6 +1165,9 @@ message DescribeWorkflowExecutionResponse { message GetWorkflowExecutionResultRequest { string namespace = 1; + // For now, server will always provide the result of the latest run of the workflow_id + // provided even if the run_id is set here. We use WorkflowExecution message for forward + // compatibility if we want to enable getting the result of a specific run_id in the future. temporal.api.common.v1.WorkflowExecution execution = 2; // Used to de-dup requests (i.e., so we don't register the same callbacks multiple times). string request_id = 3; @@ -1175,29 +1178,29 @@ message GetWorkflowExecutionResultRequest { } message GetWorkflowExecutionResultResponse { + temporal.api.common.v1.WorkflowExecution execution = 1; + temporal.api.enums.v1.WorkflowExecutionStatus status = 2; + // Link to the relevant history event: // - completion event, if the workflow has finished // - options-updated event, if callbacks were registered on a running workflow - repeated temporal.api.common.v1.Link links = 1; + repeated temporal.api.common.v1.Link links = 3; // Completion status of the workflow, which carries relevant information for the caller. oneof completion { - NotCompleted not_completed = 2; - Completed completed = 3; + NotCompleted not_completed = 4; + Success success = 5; + Failure failure = 6; } - message NotCompleted { - temporal.api.common.v1.WorkflowExecution execution = 1; - temporal.api.enums.v1.WorkflowExecutionStatus status = 2; + message NotCompleted {} + + message Success { + temporal.api.common.v1.Payloads result = 1; } - message Completed { - temporal.api.common.v1.WorkflowExecution execution = 1; - temporal.api.enums.v1.WorkflowExecutionStatus status = 2; - // Set only when status = COMPLETED. - temporal.api.common.v1.Payloads result = 3; - // Set for FAILED / CANCELED / TERMINATED / TIMED_OUT. - temporal.api.failure.v1.Failure failure = 4; + message Failure { + temporal.api.failure.v1.Failure failure = 2; } } From 7320d50bf5a933bd40e213972843d9175776b0c1 Mon Sep 17 00:00:00 2001 From: long-nt-tran Date: Fri, 8 May 2026 12:21:39 -0400 Subject: [PATCH 3/3] PR feedback - Comments on each proto field - Remove status field -- this can be inferrable via the oneof completion status - Spacing and enumeration --- openapi/openapiv2.json | 12 +++++----- openapi/openapiv3.yaml | 23 ++++++------------ .../workflowservice/v1/request_response.proto | 24 +++++++++++-------- temporal/api/workflowservice/v1/service.proto | 20 ++++++++-------- 4 files changed, 37 insertions(+), 42 deletions(-) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 1b00e04e4..df110d861 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -4173,13 +4173,14 @@ }, { "name": "requestId", - "description": "Used to de-dup requests (i.e., so we don't register the same callbacks multiple times).", + "description": "A unique identifier for this create request for idempotence. Typically UUIDv4.", "in": "query", "required": false, "type": "string" }, { "name": "identity", + "description": "The identity of the client who initiated this request.", "in": "query", "required": false, "type": "string" @@ -9704,13 +9705,14 @@ }, { "name": "requestId", - "description": "Used to de-dup requests (i.e., so we don't register the same callbacks multiple times).", + "description": "A unique identifier for this create request for idempotence. Typically UUIDv4.", "in": "query", "required": false, "type": "string" }, { "name": "identity", + "description": "The identity of the client who initiated this request.", "in": "query", "required": false, "type": "string" @@ -15782,10 +15784,8 @@ "type": "object", "properties": { "execution": { - "$ref": "#/definitions/v1WorkflowExecution" - }, - "status": { - "$ref": "#/definitions/v1WorkflowExecutionStatus" + "$ref": "#/definitions/v1WorkflowExecution", + "description": "Information about the workflow execution, including the runID that this result is associated to." }, "links": { "type": "array", diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index d58fef8fc..ca96e7853 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -3744,11 +3744,12 @@ paths: type: string - name: requestId in: query - description: Used to de-dup requests (i.e., so we don't register the same callbacks multiple times). + description: A unique identifier for this create request for idempotence. Typically UUIDv4. schema: type: string - name: identity in: query + description: The identity of the client who initiated this request. schema: type: string responses: @@ -8739,11 +8740,12 @@ paths: type: string - name: requestId in: query - description: Used to de-dup requests (i.e., so we don't register the same callbacks multiple times). + description: A unique identifier for this create request for idempotence. Typically UUIDv4. schema: type: string - name: identity in: query + description: The identity of the client who initiated this request. schema: type: string responses: @@ -12253,20 +12255,9 @@ components: type: object properties: execution: - $ref: '#/components/schemas/WorkflowExecution' - status: - enum: - - WORKFLOW_EXECUTION_STATUS_UNSPECIFIED - - WORKFLOW_EXECUTION_STATUS_RUNNING - - WORKFLOW_EXECUTION_STATUS_COMPLETED - - WORKFLOW_EXECUTION_STATUS_FAILED - - WORKFLOW_EXECUTION_STATUS_CANCELED - - WORKFLOW_EXECUTION_STATUS_TERMINATED - - WORKFLOW_EXECUTION_STATUS_CONTINUED_AS_NEW - - WORKFLOW_EXECUTION_STATUS_TIMED_OUT - - WORKFLOW_EXECUTION_STATUS_PAUSED - type: string - format: enum + allOf: + - $ref: '#/components/schemas/WorkflowExecution' + description: Information about the workflow execution, including the runID that this result is associated to. links: type: array items: diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index 10ae81d06..688a1f897 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -1169,28 +1169,32 @@ message GetWorkflowExecutionResultRequest { // provided even if the run_id is set here. We use WorkflowExecution message for forward // compatibility if we want to enable getting the result of a specific run_id in the future. temporal.api.common.v1.WorkflowExecution execution = 2; - // Used to de-dup requests (i.e., so we don't register the same callbacks multiple times). + // A unique identifier for this create request for idempotence. Typically UUIDv4. string request_id = 3; + // The identity of the client who initiated this request. string identity = 4; - // Callbacks and links to register if the workflow is not yet completed. - repeated temporal.api.common.v1.Callback callbacks = 5; + // Callbacks to be called by the server when this activity reaches a terminal state. + // Callback addresses must be allowlisted in the server's dynamic configuration. + repeated temporal.api.common.v1.Callback completion_callbacks = 5; + // Links to be associated with this request. Note that completion_callbacks may also have + // associated links; links already included with a callback should not be duplicated here. repeated temporal.api.common.v1.Link links = 6; } message GetWorkflowExecutionResultResponse { + // Information about the workflow execution, including the runID that this result is associated to. temporal.api.common.v1.WorkflowExecution execution = 1; - temporal.api.enums.v1.WorkflowExecutionStatus status = 2; // Link to the relevant history event: // - completion event, if the workflow has finished // - options-updated event, if callbacks were registered on a running workflow - repeated temporal.api.common.v1.Link links = 3; + repeated temporal.api.common.v1.Link links = 2; // Completion status of the workflow, which carries relevant information for the caller. - oneof completion { - NotCompleted not_completed = 4; - Success success = 5; - Failure failure = 6; + oneof completion_status { + NotCompleted not_completed = 3; + Success success = 4; + Failure failure = 5; } message NotCompleted {} @@ -1200,7 +1204,7 @@ message GetWorkflowExecutionResultResponse { } message Failure { - temporal.api.failure.v1.Failure failure = 2; + temporal.api.failure.v1.Failure failure = 1; } } diff --git a/temporal/api/workflowservice/v1/service.proto b/temporal/api/workflowservice/v1/service.proto index df5652ddb..0153a64de 100644 --- a/temporal/api/workflowservice/v1/service.proto +++ b/temporal/api/workflowservice/v1/service.proto @@ -2028,15 +2028,15 @@ service WorkflowService { // is still running, returns a NotCompleted response and optionally registers callbacks // to be invoked when the workflow completes. rpc GetWorkflowExecutionResult (GetWorkflowExecutionResultRequest) returns (GetWorkflowExecutionResultResponse) { - option (google.api.http) = { - get: "/namespaces/{namespace}/workflows/{execution.workflow_id}/result" - additional_bindings { - get: "/api/v1/namespaces/{namespace}/workflows/{execution.workflow_id}/result" - } - }; - option (temporal.api.protometa.v1.request_header) = { - header: "temporal-resource-id" - value: "workflow:{execution.workflow_id}" - }; + option (google.api.http) = { + get: "/namespaces/{namespace}/workflows/{execution.workflow_id}/result" + additional_bindings { + get: "/api/v1/namespaces/{namespace}/workflows/{execution.workflow_id}/result" + } + }; + option (temporal.api.protometa.v1.request_header) = { + header: "temporal-resource-id" + value: "workflow:{execution.workflow_id}" + }; } }