diff --git a/Makefile b/Makefile index d449ad033..42dbf11b8 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/applicationservice/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 @@ -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/applicationservice/v1/* \ temporal/api/operatorservice/v1/* nexus-rpc-yaml-install: diff --git a/api-linter.yaml b/api-linter.yaml index 290842854..3be6cc1d1 100644 --- a/api-linter.yaml +++ b/api-linter.yaml @@ -42,6 +42,7 @@ - included_paths: - "**/workflowservice/v1/service.proto" + - "**/applicationservice/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 ebc74b68b..6b62f3c7e 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' + temporal.api.applicationservice.v1.ApplicationService: + operations: + GetWorkflowExecutionResult: + input: + $dotnetRef: Temporalio.Api.Applicationservice.V1.GetWorkflowExecutionResultRequest + $goRef: go.temporal.io/api/applicationservice/v1.GetWorkflowExecutionResultRequest + $javaRef: io.temporal.api.applicationservice.v1.GetWorkflowExecutionResultRequest + $pythonRef: temporalio.api.applicationservice.v1.GetWorkflowExecutionResultRequest + $rubyRef: Temporalio::Api::Applicationservice::V1::GetWorkflowExecutionResultRequest + $typescriptRef: '@temporalio/api/applicationservice/v1.GetWorkflowExecutionResultRequest' + output: + $dotnetRef: Temporalio.Api.Applicationservice.V1.GetWorkflowExecutionResultResponse + $goRef: go.temporal.io/api/applicationservice/v1.GetWorkflowExecutionResultResponse + $javaRef: io.temporal.api.applicationservice.v1.GetWorkflowExecutionResultResponse + $pythonRef: temporalio.api.applicationservice.v1.GetWorkflowExecutionResultResponse + $rubyRef: Temporalio::Api::Applicationservice::V1::GetWorkflowExecutionResultResponse + $typescriptRef: '@temporalio/api/applicationservice/v1.GetWorkflowExecutionResultResponse' diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 316854a1a..f438e09dd 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -8,6 +8,9 @@ { "name": "WorkflowService" }, + { + "name": "ApplicationService" + }, { "name": "OperatorService" } diff --git a/temporal/api/applicationservice/v1/request_response.proto b/temporal/api/applicationservice/v1/request_response.proto new file mode 100644 index 000000000..9000ebb01 --- /dev/null +++ b/temporal/api/applicationservice/v1/request_response.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; + +package temporal.api.applicationservice.v1; + +option go_package = "go.temporal.io/api/applicationservice/v1;applicationservice"; +option java_package = "io.temporal.api.applicationservice.v1"; +option java_multiple_files = true; +option java_outer_classname = "RequestResponseProto"; +option ruby_package = "Temporalio::Api::Applicationservice::V1"; +option csharp_namespace = "Temporalio.Api.Applicationservice.V1"; + +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 { + // The workflow execution to wait for. This is always the latest workflow run for the given workflow ID. + // RunID is not required and will be ignored if provided. + temporal.api.common.v1.WorkflowExecution execution = 1; +} + + +message GetWorkflowExecutionResultResponse { + // 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 = 1; + temporal.api.failure.v1.Failure failure = 2; + } +} diff --git a/temporal/api/applicationservice/v1/service.proto b/temporal/api/applicationservice/v1/service.proto new file mode 100644 index 000000000..86cb26aa7 --- /dev/null +++ b/temporal/api/applicationservice/v1/service.proto @@ -0,0 +1,38 @@ +syntax = "proto3"; + +package temporal.api.applicationservice.v1; + +option go_package = "go.temporal.io/api/applicationservice/v1;applicationservice"; +option java_package = "io.temporal.api.applicationservice.v1"; +option java_multiple_files = true; +option java_outer_classname = "ServiceProto"; +option ruby_package = "Temporalio::Api::Applicationservice::V1"; +option csharp_namespace = "Temporalio.Api.Applicationservice.V1"; + +import "nexusannotations/v1/options.proto"; +import "temporal/api/applicationservice/v1/request_response.proto"; + +// ApplicationService API defines how Temporal SDKs and other clients interact with the Temporal server. +service ApplicationService { + // 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. --) + // (-- api-linter: core::0131::http-body=disabled + // aip.dev/not-precedent: This is an async long-poll, not a standard Get; it carries a request body. --) + // (-- api-linter: core::0131::http-method=disabled + // aip.dev/not-precedent: POST is used to allow a request body for the long-poll wait. --) + // (-- api-linter: core::0131::http-uri-name=disabled + // aip.dev/not-precedent: Uses a custom verb path for the wait operation. --) + // (-- api-linter: core::0131::method-signature=disabled + // aip.dev/not-precedent: Request has no `name` field; identifies the workflow by namespace + execution. --) + // (-- api-linter: core::0131::response-message-name=disabled + // aip.dev/not-precedent: Returns a dedicated response message, not the workflow resource itself. --) + // (-- api-linter: core::0127::resource-name-extraction=disabled + // aip.dev/not-precedent: Path variables use existing workflow_id field, not AIP-122 resource names. --) + // (-- api-linter: core::0127::http-annotation=disabled + // aip.dev/not-precedent: Not exposed over HTTP; this is a Nexus-only operation. --) + rpc GetWorkflowExecutionResult (GetWorkflowExecutionResultRequest) returns (GetWorkflowExecutionResultResponse) { + option (nexusannotations.v1.operation).tags = "exposed"; + } +}