diff --git a/Makefile b/Makefile index ea42652e9..94a79cb25 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,7 @@ http-api-docs: --openapiv2_out=openapi \ --openapiv2_opt=allow_merge=true,merge_file_name=openapiv2,simple_operation_ids=true \ temporal/api/workflowservice/v1/* \ + temporal/api/workflownexusservice/v1/* \ temporal/api/operatorservice/v1/* jq --rawfile desc $(OAPI_OUT)/payload_description.txt < $(OAPI_OUT)/openapiv2.swagger.json '.definitions.v1Payload={description: $$desc}' > $(OAPI_OUT)/v2.tmp @@ -119,7 +120,7 @@ buf-lint: $(STAMPDIR)/buf-mod-prune buf-breaking: @printf $(COLOR) "Run buf breaking changes check against master branch..." - @(cd $(PROTO_ROOT) && buf breaking --against 'https://github.com/temporalio/api.git#branch=master') + @(cd $(PROTO_ROOT) && buf breaking --against 'https://github.com/temporalio/api.git#branch=master') nexus-rpc-yaml: nexus-rpc-yaml-install printf $(COLOR) "Generate nexus/temporal-proto-models-nexusrpc.yaml..." @@ -131,6 +132,7 @@ nexus-rpc-yaml: nexus-rpc-yaml-install --nexus-rpc-yaml_opt=include_operation_tags=exposed \ --nexus-rpc-yaml_out=. \ temporal/api/workflowservice/v1/* \ + temporal/api/workflownexusservice/v1/* \ temporal/api/operatorservice/v1/* nexus-rpc-yaml-install: diff --git a/api-linter.yaml b/api-linter.yaml index 290842854..19766fe1f 100644 --- a/api-linter.yaml +++ b/api-linter.yaml @@ -42,6 +42,7 @@ - included_paths: - "**/workflowservice/v1/service.proto" + - "**/workflownexusservice/v1/service.proto" - "**/operatorservice/v1/service.proto" disabled_rules: - "core::0127::resource-name-extraction" # We extract specific fields in URL since the gRPC API predates the HTTP API -- https://linter.aip.dev/127/resource-name-extraction diff --git a/nexus/temporal-proto-models-nexusrpc.yaml b/nexus/temporal-proto-models-nexusrpc.yaml index e0761fd15..31840834b 100644 --- a/nexus/temporal-proto-models-nexusrpc.yaml +++ b/nexus/temporal-proto-models-nexusrpc.yaml @@ -17,3 +17,20 @@ services: $pythonRef: temporalio.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse $rubyRef: Temporalio::Api::WorkflowService::V1::SignalWithStartWorkflowExecutionResponse $typescriptRef: '@temporalio/api/workflowservice/v1.SignalWithStartWorkflowExecutionResponse' + WorkflowNexusService: + operations: + GetWorkflowExecutionResult: + input: + $dotnetRef: Temporalio.Api.Workflownexusservice.V1.GetWorkflowExecutionResultRequest + $goRef: go.temporal.io/api/workflownexusservice/v1.GetWorkflowExecutionResultRequest + $javaRef: io.temporal.api.workflownexusservice.v1.GetWorkflowExecutionResultRequest + $pythonRef: temporalio.api.workflownexusservice.v1.GetWorkflowExecutionResultRequest + $rubyRef: Temporalio::Api::Workflownexusservice::V1::GetWorkflowExecutionResultRequest + $typescriptRef: '@temporalio/api/workflownexusservice/v1.GetWorkflowExecutionResultRequest' + output: + $dotnetRef: Temporalio.Api.Workflownexusservice.V1.GetWorkflowExecutionResultResponse + $goRef: go.temporal.io/api/workflownexusservice/v1.GetWorkflowExecutionResultResponse + $javaRef: io.temporal.api.workflownexusservice.v1.GetWorkflowExecutionResultResponse + $pythonRef: temporalio.api.workflownexusservice.v1.GetWorkflowExecutionResultResponse + $rubyRef: Temporalio::Api::Workflownexusservice::V1::GetWorkflowExecutionResultResponse + $typescriptRef: '@temporalio/api/workflownexusservice/v1.GetWorkflowExecutionResultResponse' diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 12d163654..191f0a1a9 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -8,6 +8,9 @@ { "name": "WorkflowService" }, + { + "name": "WorkflowNexusService" + }, { "name": "OperatorService" } @@ -4179,6 +4182,51 @@ ] } }, + "/api/v1/namespaces/{namespace}/workflows/{execution.workflowId}/wait-for-external-workflow": { + "post": { + "summary": "GetWorkflowExecutionResult asynchronously waits for an external workflow to complete.", + "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": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/WorkflowNexusServiceGetWorkflowExecutionResultBody" + } + } + ], + "tags": [ + "WorkflowNexusService" + ] + } + }, "/api/v1/namespaces/{namespace}/workflows/{workflowExecution.workflowId}/cancel": { "post": { "summary": "RequestCancelWorkflowExecution is called by workers when they want to request cancellation of\na workflow execution.", @@ -9654,6 +9702,51 @@ ] } }, + "/namespaces/{namespace}/workflows/{execution.workflowId}/wait-for-external-workflow": { + "post": { + "summary": "GetWorkflowExecutionResult asynchronously waits for an external workflow to complete.", + "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": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/WorkflowNexusServiceGetWorkflowExecutionResultBody" + } + } + ], + "tags": [ + "WorkflowNexusService" + ] + } + }, "/namespaces/{namespace}/workflows/{workflowExecution.workflowId}/cancel": { "post": { "summary": "RequestCancelWorkflowExecution is called by workers when they want to request cancellation of\na workflow execution.", @@ -11082,6 +11175,21 @@ }, "description": "RequestIdReference is a indirect reference to a history event through the request ID." }, + "WorkflowNexusServiceGetWorkflowExecutionResultBody": { + "type": "object", + "properties": { + "execution": { + "type": "object", + "properties": { + "runId": { + "type": "string" + } + }, + "description": "The workflow execution to wait for.", + "title": "The workflow execution to wait for." + } + } + }, "WorkflowRuleActionActionActivityPause": { "type": "object" }, @@ -15655,6 +15763,21 @@ } } }, + "v1GetWorkflowExecutionResultResponse": { + "type": "object", + "properties": { + "status": { + "$ref": "#/definitions/v1WorkflowExecutionStatus", + "description": "The status of the workflow execution being waited on. This is needed to determine whether the workflow completed successfully or failed." + }, + "result": { + "$ref": "#/definitions/v1Payload" + }, + "failure": { + "$ref": "#/definitions/v1Failure" + } + } + }, "v1Header": { "type": "object", "properties": { diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 14a6a130c..a56b9786e 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -3754,6 +3754,46 @@ paths: application/json: schema: $ref: '#/components/schemas/Status' + /api/v1/namespaces/{namespace}/workflows/{execution.workflow_id}/wait-for-external-workflow: + post: + tags: + - WorkflowNexusService + description: |- + GetWorkflowExecutionResult asynchronously waits for an external workflow to complete. + + (-- api-linter: core::0136::prepositions=disabled + aip.dev/not-precedent: GetWorkflowExecutionResult is the established name for this operation. --) + operationId: GetWorkflowExecutionResult + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: execution.workflow_id + in: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/GetWorkflowExecutionResultRequest' + required: true + 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/{workflowId}: post: tags: @@ -8699,6 +8739,46 @@ paths: application/json: schema: $ref: '#/components/schemas/Status' + /namespaces/{namespace}/workflows/{execution.workflow_id}/wait-for-external-workflow: + post: + tags: + - WorkflowNexusService + description: |- + GetWorkflowExecutionResult asynchronously waits for an external workflow to complete. + + (-- api-linter: core::0136::prepositions=disabled + aip.dev/not-precedent: GetWorkflowExecutionResult is the established name for this operation. --) + operationId: GetWorkflowExecutionResult + parameters: + - name: namespace + in: path + required: true + schema: + type: string + - name: execution.workflow_id + in: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/GetWorkflowExecutionResultRequest' + required: true + 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/{workflowId}: post: tags: @@ -12149,6 +12229,36 @@ components: type: string description: Will be set if there are more history events than were included in this response format: bytes + GetWorkflowExecutionResultRequest: + type: object + properties: + namespace: + type: string + execution: + allOf: + - $ref: '#/components/schemas/WorkflowExecution' + description: The workflow execution to wait for. + GetWorkflowExecutionResultResponse: + type: object + properties: + 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 + description: The status of the workflow execution being waited on. This is needed to determine whether the workflow completed successfully or failed. + format: enum + result: + $ref: '#/components/schemas/Payload' + failure: + $ref: '#/components/schemas/Failure' GoogleProtobufAny: type: object properties: @@ -20300,6 +20410,10 @@ tags: to perform administrative functions like registering a search attribute or a namespace. APIs in this file could be not compatible with Temporal Cloud, hence it's usage in SDKs should be limited by designated APIs that clearly state that they shouldn't be used by the main Application (Workflows & Activities) framework. + - name: WorkflowNexusService + description: |- + WorkflowNexusService API defines how Temporal SDKs and other clients interact with the Temporal server + through Nexus operations. Nexus operations can be sync or async. - name: WorkflowService description: |- WorkflowService API defines how Temporal SDKs and other clients interact with the Temporal server diff --git a/temporal/api/workflownexusservice/v1/request_response.proto b/temporal/api/workflownexusservice/v1/request_response.proto new file mode 100644 index 000000000..d8d8fffe2 --- /dev/null +++ b/temporal/api/workflownexusservice/v1/request_response.proto @@ -0,0 +1,35 @@ +syntax = "proto3"; + +package temporal.api.workflownexusservice.v1; + +option go_package = "go.temporal.io/api/workflownexusservice/v1;workflownexusservice"; +option java_package = "io.temporal.api.workflownexusservice.v1"; +option java_multiple_files = true; +option java_outer_classname = "RequestResponseProto"; +option ruby_package = "Temporalio::Api::Workflownexusservice::V1"; +option csharp_namespace = "Temporalio.Api.Workflownexusservice.V1"; + +import "temporal/api/enums/v1/workflow.proto"; +import "temporal/api/common/v1/message.proto"; +import "temporal/api/failure/v1/message.proto"; + +// (-- api-linter: core::0131::request-name-required=disabled --) +// (-- api-linter: core::0131::request-unknown-fields=disabled --) +message GetWorkflowExecutionResultRequest { + string namespace = 1; + // The workflow execution to wait for. + temporal.api.common.v1.WorkflowExecution execution = 2; +} + + +message GetWorkflowExecutionResultResponse { + // The status of the workflow execution being waited on. This is needed to determine whether the workflow completed successfully or failed. + temporal.api.enums.v1.WorkflowExecutionStatus status = 1; + + // If the workflow execution being waited on completed successfully, the result will be set. If it failed, the failure will be set. + // If the workflow execution is still running, neither field will be set. + oneof completion_status { + temporal.api.common.v1.Payload result = 2; + temporal.api.failure.v1.Failure failure = 3; + } +} diff --git a/temporal/api/workflownexusservice/v1/service.proto b/temporal/api/workflownexusservice/v1/service.proto new file mode 100644 index 000000000..ff22665c9 --- /dev/null +++ b/temporal/api/workflownexusservice/v1/service.proto @@ -0,0 +1,40 @@ +syntax = "proto3"; + +package temporal.api.workflownexusservice.v1; + +option go_package = "go.temporal.io/api/workflownexusservice/v1;workflownexusservice"; +option java_package = "io.temporal.api.workflownexusservice.v1"; +option java_multiple_files = true; +option java_outer_classname = "ServiceProto"; +option ruby_package = "Temporalio::Api::Workflownexusservice::V1"; +option csharp_namespace = "Temporalio.Api.Workflownexusservice.V1"; + +import "google/api/annotations.proto"; +import "nexusannotations/v1/options.proto"; +import "temporal/api/protometa/v1/annotations.proto"; +import "temporal/api/workflownexusservice/v1/request_response.proto"; + +// WorkflowNexusService API defines how Temporal SDKs and other clients interact with the Temporal server +// through Nexus operations. Nexus operations can be sync or async. +service WorkflowNexusService { + // GetWorkflowExecutionResult asynchronously waits for an external workflow to complete. + // + // (-- api-linter: core::0136::prepositions=disabled + // aip.dev/not-precedent: GetWorkflowExecutionResult is the established name for this operation. --) + rpc GetWorkflowExecutionResult (GetWorkflowExecutionResultRequest) returns (GetWorkflowExecutionResultResponse) { + option (nexusannotations.v1.operation).tags = "exposed"; + + option (google.api.http) = { + post: "/namespaces/{namespace}/workflows/{execution.workflow_id}/wait-for-external-workflow" + body: "*" + additional_bindings { + post: "/api/v1/namespaces/{namespace}/workflows/{execution.workflow_id}/wait-for-external-workflow" + body: "*" + } + }; + option (temporal.api.protometa.v1.request_header) = { + header: "temporal-resource-id" + value : "workflow:{execution.workflow_id}" + }; + } +}