From b66af7ab522c34ef697aed6c87b7f69b422c9259 Mon Sep 17 00:00:00 2001 From: Kannan Rajah Date: Fri, 13 Feb 2026 11:42:56 -0800 Subject: [PATCH 1/5] Add worker_poll_complete_on_shutdown namespace capability (#719) ## What Changed Adds a new namespace capability `worker_poll_complete_on_shutdown` to indicate whether the server supports server-side completion of outstanding worker polls on shutdown. ## Why When this capability is enabled, the server will complete polls for workers that: 1. Send `WorkerInstanceKey` in their poll requests 2. Call `ShutdownWorker` with the same `WorkerInstanceKey` SDKs can check this capability via `DescribeNamespace` to decide whether to rely on server-side poll completion or handle it client-side. ## How - Added `bool worker_poll_complete_on_shutdown = 8` to `NamespaceInfo.Capabilities` message in `namespace/v1/message.proto` ## Related PRs - Server: temporalio/temporal#9323 --- openapi/openapiv2.json | 4 ++++ openapi/openapiv3.yaml | 8 ++++++++ temporal/api/namespace/v1/message.proto | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 85e36caa2..2f21bedcc 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -13670,6 +13670,10 @@ "standaloneActivities": { "type": "boolean", "title": "True if the namespace supports standalone activities" + }, + "workerPollCompleteOnShutdown": { + "type": "boolean", + "description": "True if the namespace supports server-side completion of outstanding worker polls on shutdown.\nWhen enabled, the server will complete polls for workers that send WorkerInstanceKey in their\npoll requests and call ShutdownWorker with the same WorkerInstanceKey. The poll will return\nan empty response. When this flag is true, workers should allow polls to return gracefully\nrather than terminating any open polls on shutdown." } }, "description": "Namespace capability details. Should contain what features are enabled in a namespace." diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 058b71005..c220f6773 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -10744,6 +10744,14 @@ components: standaloneActivities: type: boolean description: True if the namespace supports standalone activities + workerPollCompleteOnShutdown: + type: boolean + description: |- + True if the namespace supports server-side completion of outstanding worker polls on shutdown. + When enabled, the server will complete polls for workers that send WorkerInstanceKey in their + poll requests and call ShutdownWorker with the same WorkerInstanceKey. The poll will return + an empty response. When this flag is true, workers should allow polls to return gracefully + rather than terminating any open polls on shutdown. description: Namespace capability details. Should contain what features are enabled in a namespace. NamespaceInfo_Limits: type: object diff --git a/temporal/api/namespace/v1/message.proto b/temporal/api/namespace/v1/message.proto index b6f5c4cda..9f52e3452 100644 --- a/temporal/api/namespace/v1/message.proto +++ b/temporal/api/namespace/v1/message.proto @@ -42,6 +42,12 @@ message NamespaceInfo { bool workflow_pause = 6; // True if the namespace supports standalone activities bool standalone_activities = 7; + // True if the namespace supports server-side completion of outstanding worker polls on shutdown. + // When enabled, the server will complete polls for workers that send WorkerInstanceKey in their + // poll requests and call ShutdownWorker with the same WorkerInstanceKey. The poll will return + // an empty response. When this flag is true, workers should allow polls to return gracefully + // rather than terminating any open polls on shutdown. + bool worker_poll_complete_on_shutdown = 8; } // Namespace configured limits From 937084678c5234295bca14bd48e314d2951fd6f0 Mon Sep 17 00:00:00 2001 From: Justin Anderson <44687433+jmaeagle99@users.noreply.github.com> Date: Thu, 26 Feb 2026 12:53:43 -0800 Subject: [PATCH 2/5] Add storage driver info to worker heartbeats (#722) --- openapi/openapiv2.json | 17 +++++++++++++++++ openapi/openapiv3.yaml | 11 +++++++++++ temporal/api/worker/v1/message.proto | 8 ++++++++ 3 files changed, 36 insertions(+) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 2f21bedcc..fee4fdf00 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -15864,6 +15864,15 @@ "v1StopBatchOperationResponse": { "type": "object" }, + "v1StorageDriverInfo": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of the driver, required." + } + } + }, "v1StructuredCalendarSpec": { "type": "object", "properties": { @@ -16889,6 +16898,14 @@ "$ref": "#/definitions/v1PluginInfo" }, "description": "Plugins currently in use by this SDK." + }, + "drivers": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1StorageDriverInfo" + }, + "description": "Storage drivers in use by this SDK." } }, "description": "Worker info message, contains information about the worker and its current state.\nAll information is provided by the worker itself." diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index c220f6773..e0283c283 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -14042,6 +14042,12 @@ components: StopBatchOperationResponse: type: object properties: {} + StorageDriverInfo: + type: object + properties: + type: + type: string + description: The type of the driver, required. StructuredCalendarSpec: type: object properties: @@ -15515,6 +15521,11 @@ components: items: $ref: '#/components/schemas/PluginInfo' description: Plugins currently in use by this SDK. + drivers: + type: array + items: + $ref: '#/components/schemas/StorageDriverInfo' + description: Storage drivers in use by this SDK. description: |- Worker info message, contains information about the worker and its current state. All information is provided by the worker itself. diff --git a/temporal/api/worker/v1/message.proto b/temporal/api/worker/v1/message.proto index 3df3aaa33..b36a01c1e 100644 --- a/temporal/api/worker/v1/message.proto +++ b/temporal/api/worker/v1/message.proto @@ -127,6 +127,9 @@ message WorkerHeartbeat { // Plugins currently in use by this SDK. repeated PluginInfo plugins = 23; + + // Storage drivers in use by this SDK. + repeated StorageDriverInfo drivers = 24; } message WorkerInfo { @@ -139,3 +142,8 @@ message PluginInfo { // The version of the plugin, may be empty. string version = 2; } + +message StorageDriverInfo { + // The type of the driver, required. + string type = 1; +} From 57364bd43460d071cffd7f0c9a7a874f0714cfbd Mon Sep 17 00:00:00 2001 From: Kannan Rajah Date: Tue, 10 Mar 2026 14:23:02 -0700 Subject: [PATCH 3/5] Add WorkerListInfo proto for efficient worker listing (#724) ## What changed? - Add `WorkerListInfo` proto for List API (follows CHASM entity conventions like `ActivityExecutionListInfo`, `ScheduleListEntry`) - Add `workers` field to `ListWorkersResponse` returning `repeated WorkerListInfo` - Deprecate `workers_info` field in `ListWorkersResponse` [Server PR](https://github.com/temporalio/temporal/pull/9418) ## Why? Listing many workers with full `WorkerInfo` (containing dynamic metrics) is expensive. `WorkerListInfo` contains only static/slow-changing fields for efficient listing. ## How did you test it? - [x] make proto passes ## Potential risks None - backward compatible. --- openapi/openapiv2.json | 82 +++++++++++++++++- openapi/openapiv3.yaml | 85 +++++++++++++++++-- temporal/api/worker/v1/message.proto | 46 ++++++++++ .../workflowservice/v1/request_response.proto | 13 +-- 4 files changed, 209 insertions(+), 17 deletions(-) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index fee4fdf00..ea5c6c69a 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -2735,7 +2735,7 @@ }, { "name": "query", - "description": "`query` in ListWorkers is used to filter workers based on worker status info.\nThe following worker status attributes are expected are supported as part of the query:\n* WorkerInstanceKey\n* WorkerIdentity\n* HostName\n* TaskQueue\n* DeploymentName\n* BuildId\n* SdkName\n* SdkVersion\n* StartTime\n* LastHeartbeatTime\n* Status\nCurrently metrics are not supported as a part of ListWorkers query.", + "description": "`query` in ListWorkers is used to filter workers based on worker attributes.\nSupported attributes:\n* WorkerInstanceKey\n* WorkerIdentity\n* HostName\n* TaskQueue\n* DeploymentName\n* BuildId\n* SdkName\n* SdkVersion\n* StartTime\n* Status", "in": "query", "required": false, "type": "string" @@ -7235,7 +7235,7 @@ }, { "name": "query", - "description": "`query` in ListWorkers is used to filter workers based on worker status info.\nThe following worker status attributes are expected are supported as part of the query:\n* WorkerInstanceKey\n* WorkerIdentity\n* HostName\n* TaskQueue\n* DeploymentName\n* BuildId\n* SdkName\n* SdkVersion\n* StartTime\n* LastHeartbeatTime\n* Status\nCurrently metrics are not supported as a part of ListWorkers query.", + "description": "`query` in ListWorkers is used to filter workers based on worker attributes.\nSupported attributes:\n* WorkerInstanceKey\n* WorkerIdentity\n* HostName\n* TaskQueue\n* DeploymentName\n* BuildId\n* SdkName\n* SdkVersion\n* StartTime\n* Status", "in": "query", "required": false, "type": "string" @@ -13429,7 +13429,16 @@ "items": { "type": "object", "$ref": "#/definitions/v1WorkerInfo" - } + }, + "description": "Deprecated: Use workers instead. This field returns full WorkerInfo which\nincludes expensive runtime metrics. We will stop populating this field in the future." + }, + "workers": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1WorkerListInfo" + }, + "description": "Limited worker information." }, "nextPageToken": { "type": "string", @@ -16944,7 +16953,72 @@ "workerHeartbeat": { "$ref": "#/definitions/v1WorkerHeartbeat" } - } + }, + "description": "Detailed worker information." + }, + "v1WorkerListInfo": { + "type": "object", + "properties": { + "workerInstanceKey": { + "type": "string", + "description": "Worker identifier, should be unique for the namespace.\nIt is distinct from worker identity, which is not necessarily namespace-unique." + }, + "workerIdentity": { + "type": "string", + "description": "Worker identity, set by the client, may not be unique.\nUsually host_name+(user group name)+process_id, but can be overwritten by the user." + }, + "taskQueue": { + "type": "string", + "description": "Task queue this worker is polling for tasks." + }, + "deploymentVersion": { + "$ref": "#/definitions/v1WorkerDeploymentVersion" + }, + "sdkName": { + "type": "string" + }, + "sdkVersion": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/v1WorkerStatus", + "description": "Worker status. Defined by SDK." + }, + "startTime": { + "type": "string", + "format": "date-time", + "title": "Worker start time.\nIt can be used to determine worker uptime. (current time - start time)" + }, + "hostName": { + "type": "string", + "description": "Worker host identifier." + }, + "workerGroupingKey": { + "type": "string", + "title": "Worker grouping identifier. A key to group workers that share the same client+namespace+process.\nThis will be used to build the worker command nexus task queue name:\n\"temporal-sys/worker-commands/{worker_grouping_key}\"" + }, + "processId": { + "type": "string", + "description": "Worker process identifier. This id only needs to be unique\nwithin one host (so using e.g. a unix pid would be appropriate)." + }, + "plugins": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1PluginInfo" + }, + "description": "Plugins currently in use by this SDK." + }, + "drivers": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1StorageDriverInfo" + }, + "description": "Storage drivers in use by this SDK." + } + }, + "description": "Limited worker information returned in the list response.\nWhen adding fields here, ensure that it is also added to WorkerInfo (as it carries the full worker information)." }, "v1WorkerPollerInfo": { "type": "object", diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index e0283c283..4ccc94584 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -2461,8 +2461,8 @@ paths: - name: query in: query description: |- - `query` in ListWorkers is used to filter workers based on worker status info. - The following worker status attributes are expected are supported as part of the query: + `query` in ListWorkers is used to filter workers based on worker attributes. + Supported attributes: * WorkerInstanceKey * WorkerIdentity * HostName @@ -2472,9 +2472,7 @@ paths: * SdkName * SdkVersion * StartTime - * LastHeartbeatTime * Status - Currently metrics are not supported as a part of ListWorkers query. schema: type: string responses: @@ -6496,8 +6494,8 @@ paths: - name: query in: query description: |- - `query` in ListWorkers is used to filter workers based on worker status info. - The following worker status attributes are expected are supported as part of the query: + `query` in ListWorkers is used to filter workers based on worker attributes. + Supported attributes: * WorkerInstanceKey * WorkerIdentity * HostName @@ -6507,9 +6505,7 @@ paths: * SdkName * SdkVersion * StartTime - * LastHeartbeatTime * Status - Currently metrics are not supported as a part of ListWorkers query. schema: type: string responses: @@ -10550,6 +10546,14 @@ components: type: array items: $ref: '#/components/schemas/WorkerInfo' + description: |- + Deprecated: Use workers instead. This field returns full WorkerInfo which + includes expensive runtime metrics. We will stop populating this field in the future. + workers: + type: array + items: + $ref: '#/components/schemas/WorkerListInfo' + description: Limited worker information. nextPageToken: type: string description: Next page token @@ -15566,6 +15570,71 @@ components: properties: workerHeartbeat: $ref: '#/components/schemas/WorkerHeartbeat' + description: Detailed worker information. + WorkerListInfo: + type: object + properties: + workerInstanceKey: + type: string + description: |- + Worker identifier, should be unique for the namespace. + It is distinct from worker identity, which is not necessarily namespace-unique. + workerIdentity: + type: string + description: |- + Worker identity, set by the client, may not be unique. + Usually host_name+(user group name)+process_id, but can be overwritten by the user. + taskQueue: + type: string + description: Task queue this worker is polling for tasks. + deploymentVersion: + $ref: '#/components/schemas/WorkerDeploymentVersion' + sdkName: + type: string + sdkVersion: + type: string + status: + enum: + - WORKER_STATUS_UNSPECIFIED + - WORKER_STATUS_RUNNING + - WORKER_STATUS_SHUTTING_DOWN + - WORKER_STATUS_SHUTDOWN + type: string + description: Worker status. Defined by SDK. + format: enum + startTime: + type: string + description: |- + Worker start time. + It can be used to determine worker uptime. (current time - start time) + format: date-time + hostName: + type: string + description: Worker host identifier. + workerGroupingKey: + type: string + description: |- + Worker grouping identifier. A key to group workers that share the same client+namespace+process. + This will be used to build the worker command nexus task queue name: + "temporal-sys/worker-commands/{worker_grouping_key}" + processId: + type: string + description: |- + Worker process identifier. This id only needs to be unique + within one host (so using e.g. a unix pid would be appropriate). + plugins: + type: array + items: + $ref: '#/components/schemas/PluginInfo' + description: Plugins currently in use by this SDK. + drivers: + type: array + items: + $ref: '#/components/schemas/StorageDriverInfo' + description: Storage drivers in use by this SDK. + description: |- + Limited worker information returned in the list response. + When adding fields here, ensure that it is also added to WorkerInfo (as it carries the full worker information). WorkerPollerInfo: type: object properties: diff --git a/temporal/api/worker/v1/message.proto b/temporal/api/worker/v1/message.proto index b36a01c1e..b65faeb29 100644 --- a/temporal/api/worker/v1/message.proto +++ b/temporal/api/worker/v1/message.proto @@ -132,10 +132,56 @@ message WorkerHeartbeat { repeated StorageDriverInfo drivers = 24; } +// Detailed worker information. message WorkerInfo { WorkerHeartbeat worker_heartbeat = 1; } +// Limited worker information returned in the list response. +// When adding fields here, ensure that it is also added to WorkerInfo (as it carries the full worker information). +message WorkerListInfo { + // Worker identifier, should be unique for the namespace. + // It is distinct from worker identity, which is not necessarily namespace-unique. + string worker_instance_key = 1; + + // Worker identity, set by the client, may not be unique. + // Usually host_name+(user group name)+process_id, but can be overwritten by the user. + string worker_identity = 2; + + // Task queue this worker is polling for tasks. + string task_queue = 3; + + temporal.api.deployment.v1.WorkerDeploymentVersion deployment_version = 4; + + string sdk_name = 5; + string sdk_version = 6; + + // Worker status. Defined by SDK. + temporal.api.enums.v1.WorkerStatus status = 7; + + // Worker start time. + // It can be used to determine worker uptime. (current time - start time) + google.protobuf.Timestamp start_time = 8; + + // Worker host identifier. + string host_name = 9; + + // Worker grouping identifier. A key to group workers that share the same client+namespace+process. + // This will be used to build the worker command nexus task queue name: + // "temporal-sys/worker-commands/{worker_grouping_key}" + string worker_grouping_key = 10; + + // Worker process identifier. This id only needs to be unique + // within one host (so using e.g. a unix pid would be appropriate). + string process_id = 11; + + // Plugins currently in use by this SDK. + repeated PluginInfo plugins = 12; + + // Storage drivers in use by this SDK. + repeated StorageDriverInfo drivers = 13; +} + message PluginInfo { // The name of the plugin, required. string name = 1; diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index 4bf3272c6..651816e37 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -2560,8 +2560,8 @@ message ListWorkersRequest { int32 page_size = 2; bytes next_page_token = 3; - // `query` in ListWorkers is used to filter workers based on worker status info. - // The following worker status attributes are expected are supported as part of the query: + // `query` in ListWorkers is used to filter workers based on worker attributes. + // Supported attributes: //* WorkerInstanceKey //* WorkerIdentity //* HostName @@ -2571,14 +2571,17 @@ message ListWorkersRequest { //* SdkName //* SdkVersion //* StartTime - //* LastHeartbeatTime //* Status - // Currently metrics are not supported as a part of ListWorkers query. string query = 4; } message ListWorkersResponse { - repeated temporal.api.worker.v1.WorkerInfo workers_info = 1; + // Deprecated: Use workers instead. This field returns full WorkerInfo which + // includes expensive runtime metrics. We will stop populating this field in the future. + repeated temporal.api.worker.v1.WorkerInfo workers_info = 1 [deprecated = true]; + + // Limited worker information. + repeated temporal.api.worker.v1.WorkerListInfo workers = 3; // Next page token bytes next_page_token = 2; From 8baa851b94d04cd9e055392819343a2f098e0d0a Mon Sep 17 00:00:00 2001 From: Shivam <57200924+Shivs11@users.noreply.github.com> Date: Thu, 12 Mar 2026 19:29:14 -0400 Subject: [PATCH 4/5] Trampolining: addition of fields to remove the infinite loops for pinned wfs (#721) _**READ BEFORE MERGING:** All PRs require approval by both Server AND SDK teams before merging! This is why the number of required approvals is "2" and not "1"--two reviewers from the same team is NOT sufficient. If your PR is not approved by someone in BOTH teams, it may be summarily reverted._ -WISOTT - Users that could using trampolining in the near future could run into a problem, which shall only surface if the workflow author does not have AutoUpgrade as the initial CAN behaviour for their Pinned workflows. As of today, if a user does hit this case, they would have the pinned workflow CAN'ing infinite number of times. This is because a pinned workflow would commence on the pinned version (since it would have inherited pinned version set to true) and if the pinned version is different than a worker-deployment's current version, the targetDeploymentVersionChanged would be set to true in the server. This would then result in the workflow just CAN'ing all the time! - This change aims to change that by only allowing at-most one CAN for such pinned workflow executions, and it does so by remembering what the initial version was at the start of the continue-as-new. **Breaking changes** - [PR!](https://github.com/temporalio/temporal/pull/9374) --------- Co-authored-by: Claude Opus 4.6 --- openapi/openapiv2.json | 13 +++++++++++++ openapi/openapiv3.yaml | 22 ++++++++++++++++++++++ temporal/api/history/v1/message.proto | 18 ++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index ea5c6c69a..79d7c0c7d 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -12040,6 +12040,15 @@ } } }, + "v1DeclinedTargetVersionUpgrade": { + "type": "object", + "properties": { + "deploymentVersion": { + "$ref": "#/definitions/v1WorkerDeploymentVersion" + } + }, + "description": "Wrapper for a target deployment version that the SDK declined to upgrade to.\nSee declined_target_version_upgrade on WorkflowExecutionStartedEventAttributes." + }, "v1DeleteNexusEndpointResponse": { "type": "object" }, @@ -17719,6 +17728,10 @@ "eagerExecutionAccepted": { "type": "boolean", "description": "A boolean indicating whether the SDK has asked to eagerly execute the first workflow task for this workflow and\neager execution was accepted by the server.\nOnly populated by server with version >= 1.29.0." + }, + "declinedTargetVersionUpgrade": { + "$ref": "#/definitions/v1DeclinedTargetVersionUpgrade", + "description": "During a previous run of this workflow, the server may have notified the SDK\nthat the Target Worker Deployment Version changed, but the SDK declined to\nupgrade (e.g., by continuing-as-new with PINNED behavior). This field records\nthe target version that was declined.\n\nThis is a wrapper message to distinguish \"never declined\" (nil wrapper) from\n\"declined an unversioned target\" (non-nil wrapper with nil deployment_version).\n\nUsed internally by the server during continue-as-new and retry.\nShould not be read or interpreted by SDKs." } }, "title": "Always the first event in workflow history" diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 4ccc94584..24c527682 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -9226,6 +9226,14 @@ components: data: type: string format: bytes + DeclinedTargetVersionUpgrade: + type: object + properties: + deploymentVersion: + $ref: '#/components/schemas/WorkerDeploymentVersion' + description: |- + Wrapper for a target deployment version that the SDK declined to upgrade to. + See declined_target_version_upgrade on WorkflowExecutionStartedEventAttributes. DeleteNexusEndpointResponse: type: object properties: {} @@ -16528,6 +16536,20 @@ components: A boolean indicating whether the SDK has asked to eagerly execute the first workflow task for this workflow and eager execution was accepted by the server. Only populated by server with version >= 1.29.0. + declinedTargetVersionUpgrade: + allOf: + - $ref: '#/components/schemas/DeclinedTargetVersionUpgrade' + description: |- + During a previous run of this workflow, the server may have notified the SDK + that the Target Worker Deployment Version changed, but the SDK declined to + upgrade (e.g., by continuing-as-new with PINNED behavior). This field records + the target version that was declined. + + This is a wrapper message to distinguish "never declined" (nil wrapper) from + "declined an unversioned target" (non-nil wrapper with nil deployment_version). + + Used internally by the server during continue-as-new and retry. + Should not be read or interpreted by SDKs. description: Always the first event in workflow history WorkflowExecutionTerminatedEventAttributes: type: object diff --git a/temporal/api/history/v1/message.proto b/temporal/api/history/v1/message.proto index 2fb99f7e9..21fb13c5e 100644 --- a/temporal/api/history/v1/message.proto +++ b/temporal/api/history/v1/message.proto @@ -184,6 +184,24 @@ message WorkflowExecutionStartedEventAttributes { // eager execution was accepted by the server. // Only populated by server with version >= 1.29.0. bool eager_execution_accepted = 38; + + // During a previous run of this workflow, the server may have notified the SDK + // that the Target Worker Deployment Version changed, but the SDK declined to + // upgrade (e.g., by continuing-as-new with PINNED behavior). This field records + // the target version that was declined. + // + // This is a wrapper message to distinguish "never declined" (nil wrapper) from + // "declined an unversioned target" (non-nil wrapper with nil deployment_version). + // + // Used internally by the server during continue-as-new and retry. + // Should not be read or interpreted by SDKs. + DeclinedTargetVersionUpgrade declined_target_version_upgrade = 40; +} + +// Wrapper for a target deployment version that the SDK declined to upgrade to. +// See declined_target_version_upgrade on WorkflowExecutionStartedEventAttributes. +message DeclinedTargetVersionUpgrade { + temporal.api.deployment.v1.WorkerDeploymentVersion deployment_version = 1; } message WorkflowExecutionCompletedEventAttributes { From cfff488eb1b0589286fc2cbe43ff991183bf5be0 Mon Sep 17 00:00:00 2001 From: Kannan Rajah Date: Fri, 13 Mar 2026 11:07:08 -0700 Subject: [PATCH 5/5] Add worker_control_task_queue to poll and respond protos Made-with: Cursor --- .../workerservice/v1/request_response.proto | 46 +++++++++++++++++++ .../workerservice/v1/service.yaml | 32 +++++++++++++ .../workflowservice/v1/request_response.proto | 15 ++++++ 3 files changed, 93 insertions(+) create mode 100644 temporal/api/nexusservices/workerservice/v1/request_response.proto create mode 100644 temporal/api/nexusservices/workerservice/v1/service.yaml diff --git a/temporal/api/nexusservices/workerservice/v1/request_response.proto b/temporal/api/nexusservices/workerservice/v1/request_response.proto new file mode 100644 index 000000000..ef14decbd --- /dev/null +++ b/temporal/api/nexusservices/workerservice/v1/request_response.proto @@ -0,0 +1,46 @@ +syntax = "proto3"; + +package temporal.api.nexusservices.workerservice.v1; + +option go_package = "go.temporal.io/api/nexusservices/workerservice/v1;workerservice"; +option java_package = "io.temporal.api.nexusservices.workerservice.v1"; +option java_multiple_files = true; +option java_outer_classname = "RequestResponseProto"; +option ruby_package = "Temporalio::Api::Nexusservices::Workerservice::V1"; +option csharp_namespace = "Temporalio.Api.Nexusservices.Workerservice.V1"; + +// (-- +// Internal Nexus service for server-to-worker communication. +// See service.yaml for the service definition. +// --) + +// Request payload for the "executeCommands" Nexus operation. +message WorkerCommandsRequest { + repeated WorkerCommand commands = 1; + + message WorkerCommand { + oneof type { + CancelActivity cancel_activity = 1; + } + } + + // Cancel an activity if it is still running. Otherwise, do nothing. + message CancelActivity { + bytes task_token = 1; + } +} + +// Response payload for the "executeCommands" Nexus operation. +message WorkerCommandsResponse { + repeated WorkerCommandResult results = 1; + + message WorkerCommandResult { + oneof type { + CancelActivity cancel_activity = 1; + } + } + + // Treat both successful cancellation and no-op (activity is no longer running) as success. + message CancelActivity { + } +} diff --git a/temporal/api/nexusservices/workerservice/v1/service.yaml b/temporal/api/nexusservices/workerservice/v1/service.yaml new file mode 100644 index 000000000..ad42b3bba --- /dev/null +++ b/temporal/api/nexusservices/workerservice/v1/service.yaml @@ -0,0 +1,32 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nexus-rpc/nexus-rpc-gen/main/schemas/nexus-rpc-gen.json +# +# Nexus service definition for server-to-worker communication. +# See request_response.proto for message definitions. +# +# Task queue format: /temporal-sys/worker-commands/{namespace}/{worker_grouping_key} + +nexusrpc: 1.0.0 + +services: + temporal.api.nexusservices.workerservice.v1.WorkerService: + description: > + Internal Nexus service for server-to-worker communication. + Used by the Temporal server to send commands to workers. + operations: + executeCommands: + description: Executes worker commands sent by the server. + input: + $goRef: "go.temporal.io/api/nexusservices/workerservice/v1.WorkerCommandsRequest" + $javaRef: "io.temporal.api.nexusservices.workerservice.v1.WorkerCommandsRequest" + $pythonRef: "temporalio.api.nexusservices.workerservice.v1.WorkerCommandsRequest" + $typescriptRef: "@temporalio/api/nexusservices/workerservice/v1.WorkerCommandsRequest" + $dotnetRef: "Temporalio.Api.Nexusservices.Workerservice.V1.WorkerCommandsRequest" + $rubyRef: "Temporalio::Api::Nexusservices::Workerservice::V1::WorkerCommandsRequest" + output: + $goRef: "go.temporal.io/api/nexusservices/workerservice/v1.WorkerCommandsResponse" + $javaRef: "io.temporal.api.nexusservices.workerservice.v1.WorkerCommandsResponse" + $pythonRef: "temporalio.api.nexusservices.workerservice.v1.WorkerCommandsResponse" + $typescriptRef: "@temporalio/api/nexusservices/workerservice/v1.WorkerCommandsResponse" + $dotnetRef: "Temporalio.Api.Nexusservices.Workerservice.V1.WorkerCommandsResponse" + $rubyRef: "Temporalio::Api::Nexusservices::Workerservice::V1::WorkerCommandsResponse" + diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index 651816e37..e95ac8ba4 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -262,6 +262,10 @@ message PollWorkflowTaskQueueRequest { // A unique key for this worker instance, used for tracking worker lifecycle. // This is guaranteed to be unique, whereas identity is not guaranteed to be unique. string worker_instance_key = 8; + + // The task queue on which the server will send control tasks to this worker. + string worker_control_task_queue = 9; + // Deprecated. Use deployment_options instead. // Each worker process should provide an ID unique to the specific set of code it is running // "checksum" in this field name isn't very accurate, it should be though of as an id. @@ -381,6 +385,13 @@ message RespondWorkflowTaskCompletedRequest { // Worker deployment options that user has set in the worker. temporal.api.deployment.v1.WorkerDeploymentOptions deployment_options = 17; + // A unique key for this worker instance, used for tracking worker lifecycle. + // This is guaranteed to be unique, whereas identity is not guaranteed to be unique. + string worker_instance_key = 18; + + // The task queue on which the server will send control tasks to this worker. + string worker_control_task_queue = 19; + // SDK capability details. message Capabilities { // True if the SDK can handle speculative workflow task with command events. If true, the @@ -444,6 +455,10 @@ message PollActivityTaskQueueRequest { // A unique key for this worker instance, used for tracking worker lifecycle. // This is guaranteed to be unique, whereas identity is not guaranteed to be unique. string worker_instance_key = 8; + + // The task queue on which the server will send control tasks to this worker. + string worker_control_task_queue = 9; + temporal.api.taskqueue.v1.TaskQueueMetadata task_queue_metadata = 4; // Information about this worker's build identifier and if it is choosing to use the versioning // feature. See the `WorkerVersionCapabilities` docstring for more.