From 1f1ef7349593560d27cc20124cc5787c1b8e64a7 Mon Sep 17 00:00:00 2001 From: Roey Berman Date: Fri, 18 Jul 2025 13:02:49 -0700 Subject: [PATCH 1/2] Use Temporal Failures for Nexus APIs Also add a failure representation of the Nexus SDK's OperationError. --- openapi/openapiv2.json | 31 ++++++++++++++++++- openapi/openapiv3.yaml | 9 ++++++ temporal/api/failure/v1/message.proto | 7 +++++ temporal/api/nexus/v1/message.proto | 12 +++++++ .../workflowservice/v1/request_response.proto | 6 ++-- 5 files changed, 62 insertions(+), 3 deletions(-) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index ad6aae01b..4a944475f 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -9252,6 +9252,9 @@ }, "nexusHandlerFailureInfo": { "$ref": "#/definitions/v1NexusHandlerFailureInfo" + }, + "nexusSdkOperationFailureInfo": { + "$ref": "#/definitions/v1NexusSDKOperationFailureInfo" } } }, @@ -9302,6 +9305,9 @@ "format": "date-time", "description": "The timestamp when the request was scheduled in the frontend." }, + "capabilities": { + "$ref": "#/definitions/v1RequestCapabilities" + }, "startOperation": { "$ref": "#/definitions/v1StartOperationRequest" }, @@ -12700,7 +12706,8 @@ "type": "string", "description": "Operation token - may be empty if the operation completed synchronously." } - } + }, + "description": "Representation of the Temporal SDK NexusOperationError object that is returned to workflow callers." }, "v1NexusOperationScheduledEventAttributes": { "type": "object", @@ -12790,6 +12797,15 @@ }, "description": "Nexus operation timed out." }, + "v1NexusSDKOperationFailureInfo": { + "type": "object", + "properties": { + "state": { + "type": "string" + } + }, + "description": "Representation of the Nexus SDK OperationError object." + }, "v1OnConflictOptions": { "type": "object", "properties": { @@ -13756,6 +13772,15 @@ "v1RequestCancelWorkflowExecutionResponse": { "type": "object" }, + "v1RequestCapabilities": { + "type": "object", + "properties": { + "temporalFailureResponses": { + "type": "boolean", + "description": "If set, handlers may use temporal.api.failure.v1.Failure instances to return failures to the server.\nThis also allows handler and operation errors to have their own messages and stack traces." + } + } + }, "v1RequestIdInfo": { "type": "object", "properties": { @@ -14984,6 +15009,10 @@ "operationError": { "$ref": "#/definitions/v1UnsuccessfulOperationError", "description": "The operation completed unsuccessfully (failed or canceled)." + }, + "failure": { + "$ref": "#/definitions/apifailurev1Failure", + "description": "The operation completed unsuccessfully (failed or canceled).\nFailure object must contain a NexusSDKOperationFailureInfo object." } }, "description": "Response variant for StartOperationRequest." diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index c81fcb4f8..3bb2318a6 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -8337,6 +8337,8 @@ components: $ref: '#/components/schemas/NexusOperationFailureInfo' nexusHandlerFailureInfo: $ref: '#/components/schemas/NexusHandlerFailureInfo' + nexusSdkOperationFailureInfo: + $ref: '#/components/schemas/NexusSDKOperationFailureInfo' FetchWorkerConfigRequest: type: object properties: @@ -9459,6 +9461,7 @@ components: operationToken: type: string description: Operation token - may be empty if the operation completed synchronously. + description: Representation of the Temporal SDK NexusOperationError object that is returned to workflow callers. NexusOperationScheduledEventAttributes: type: object properties: @@ -9550,6 +9553,12 @@ components: type: string description: The request ID allocated at schedule time. description: Nexus operation timed out. + NexusSDKOperationFailureInfo: + type: object + properties: + state: + type: string + description: Representation of the Nexus SDK OperationError object. OnConflictOptions: type: object properties: diff --git a/temporal/api/failure/v1/message.proto b/temporal/api/failure/v1/message.proto index 3b27f65ff..73d2531b5 100644 --- a/temporal/api/failure/v1/message.proto +++ b/temporal/api/failure/v1/message.proto @@ -66,6 +66,7 @@ message ChildWorkflowExecutionFailureInfo { temporal.api.enums.v1.RetryState retry_state = 6; } +// Representation of the Temporal SDK NexusOperationError object that is returned to workflow callers. message NexusOperationFailureInfo { // The NexusOperationScheduled event ID. int64 scheduled_event_id = 1; @@ -91,6 +92,11 @@ message NexusHandlerFailureInfo { temporal.api.enums.v1.NexusHandlerErrorRetryBehavior retry_behavior = 2; } +// Representation of the Nexus SDK OperationError object. +message NexusSDKOperationFailureInfo { + string state = 1; +} + message Failure { string message = 1; // The source this Failure originated in, e.g. TypeScriptSDK / JavaSDK @@ -125,6 +131,7 @@ message Failure { ChildWorkflowExecutionFailureInfo child_workflow_execution_failure_info = 12; NexusOperationFailureInfo nexus_operation_execution_failure_info = 13; NexusHandlerFailureInfo nexus_handler_failure_info = 14; + NexusSDKOperationFailureInfo nexus_sdk_operation_failure_info = 15; } } diff --git a/temporal/api/nexus/v1/message.proto b/temporal/api/nexus/v1/message.proto index f39890ad5..0dc149b0e 100644 --- a/temporal/api/nexus/v1/message.proto +++ b/temporal/api/nexus/v1/message.proto @@ -12,6 +12,7 @@ option csharp_namespace = "Temporalio.Api.Nexus.V1"; import "google/protobuf/timestamp.proto"; import "temporal/api/common/v1/message.proto"; import "temporal/api/enums/v1/nexus.proto"; +import "temporal/api/failure/v1/message.proto"; // A general purpose failure message. // See: https://github.com/nexus-rpc/api/blob/main/SPEC.md#failure @@ -77,6 +78,12 @@ message CancelOperationRequest { // A Nexus request. message Request { + message Capabilities { + // If set, handlers may use temporal.api.failure.v1.Failure instances to return failures to the server. + // This also allows handler and operation errors to have their own messages and stack traces. + bool temporal_failure_responses = 1; + } + // Headers extracted from the original request in the Temporal frontend. // When using Nexus over HTTP, this includes the request's HTTP headers ignoring multiple values. map header = 1; @@ -86,6 +93,8 @@ message Request { // aip.dev/not-precedent: Not following linter rules. --) google.protobuf.Timestamp scheduled_time = 2; + Capabilities capabilities = 100; + oneof variant { StartOperationRequest start_operation = 3; CancelOperationRequest cancel_operation = 4; @@ -114,6 +123,9 @@ message StartOperationResponse { Async async_success = 2; // The operation completed unsuccessfully (failed or canceled). UnsuccessfulOperationError operation_error = 3; + // The operation completed unsuccessfully (failed or canceled). + // Failure object must contain a NexusSDKOperationFailureInfo object. + temporal.api.failure.v1.Failure failure = 4; } } diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index 4636c20a0..41741bdbe 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -1834,8 +1834,10 @@ message RespondNexusTaskFailedRequest { string identity = 2; // A unique identifier for this task. bytes task_token = 3; - // The error the handler failed with. + // The error the handler failed with (DEPRECATED, use the failure field instead). temporal.api.nexus.v1.HandlerError error = 4; + // The error the handler failed with. Must contain a NexusHandlerFailureInfo object. + temporal.api.failure.v1.Failure failure = 5; } message RespondNexusTaskFailedResponse { @@ -2591,4 +2593,4 @@ message DescribeWorkerRequest { message DescribeWorkerResponse { temporal.api.worker.v1.WorkerInfo worker_info = 1; -} \ No newline at end of file +} From 7b57017cd008098addad14868a6b9e850ae41021 Mon Sep 17 00:00:00 2001 From: Roey Berman Date: Wed, 10 Sep 2025 10:12:39 -0700 Subject: [PATCH 2/2] Add NexusSDKFailureInfo --- openapi/openapiv2.json | 19 +++++++++++++++++++ openapi/openapiv3.yaml | 13 +++++++++++++ temporal/api/failure/v1/message.proto | 7 +++++++ 3 files changed, 39 insertions(+) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 4a944475f..5fc55b010 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -9255,6 +9255,9 @@ }, "nexusSdkOperationFailureInfo": { "$ref": "#/definitions/v1NexusSDKOperationFailureInfo" + }, + "nexusSdkFailureErrorInfo": { + "$ref": "#/definitions/v1NexusSDKFailureErrorFailureInfo" } } }, @@ -12797,6 +12800,22 @@ }, "description": "Nexus operation timed out." }, + "v1NexusSDKFailureErrorFailureInfo": { + "type": "object", + "properties": { + "metadata": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "data": { + "type": "string", + "format": "byte" + } + }, + "description": "Representation of the Nexus SDK FailureError object." + }, "v1NexusSDKOperationFailureInfo": { "type": "object", "properties": { diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 3bb2318a6..734ed4b75 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -8339,6 +8339,8 @@ components: $ref: '#/components/schemas/NexusHandlerFailureInfo' nexusSdkOperationFailureInfo: $ref: '#/components/schemas/NexusSDKOperationFailureInfo' + nexusSdkFailureErrorInfo: + $ref: '#/components/schemas/NexusSDKFailureErrorFailureInfo' FetchWorkerConfigRequest: type: object properties: @@ -9553,6 +9555,17 @@ components: type: string description: The request ID allocated at schedule time. description: Nexus operation timed out. + NexusSDKFailureErrorFailureInfo: + type: object + properties: + metadata: + type: object + additionalProperties: + type: string + data: + type: string + format: bytes + description: Representation of the Nexus SDK FailureError object. NexusSDKOperationFailureInfo: type: object properties: diff --git a/temporal/api/failure/v1/message.proto b/temporal/api/failure/v1/message.proto index 73d2531b5..df2c39f60 100644 --- a/temporal/api/failure/v1/message.proto +++ b/temporal/api/failure/v1/message.proto @@ -97,6 +97,12 @@ message NexusSDKOperationFailureInfo { string state = 1; } +// Representation of the Nexus SDK FailureError object. +message NexusSDKFailureErrorFailureInfo { + map metadata = 1; + bytes data = 2; +} + message Failure { string message = 1; // The source this Failure originated in, e.g. TypeScriptSDK / JavaSDK @@ -132,6 +138,7 @@ message Failure { NexusOperationFailureInfo nexus_operation_execution_failure_info = 13; NexusHandlerFailureInfo nexus_handler_failure_info = 14; NexusSDKOperationFailureInfo nexus_sdk_operation_failure_info = 15; + NexusSDKFailureErrorFailureInfo nexus_sdk_failure_error_info = 16; } }