From bc13dcfb48c01adaa98fa5fe453eb03e24eb4eed Mon Sep 17 00:00:00 2001 From: Feiyang Xie Date: Tue, 20 Oct 2026 22:57:35 -0700 Subject: [PATCH 1/4] add WHN --- temporal/api/worker/v1/message.proto | 12 ++++++++++++ .../api/workflowservice/v1/request_response.proto | 2 ++ 2 files changed, 14 insertions(+) diff --git a/temporal/api/worker/v1/message.proto b/temporal/api/worker/v1/message.proto index acbbe05ed..d3c56df24 100644 --- a/temporal/api/worker/v1/message.proto +++ b/temporal/api/worker/v1/message.proto @@ -319,9 +319,16 @@ message EnvironmentInfo { message WorkerCommand { oneof type { CancelActivityCommand cancel_activity = 1; + WorkflowTaskHeartbeatNotificationCommand workflow_task_heartbeat_notification = 2; } } +// Request an early heartbeat of the identified Workflow Task if it is still running. +message WorkflowTaskHeartbeatNotificationCommand { + // The token of the Workflow Task returned to the worker. + bytes task_token = 1; +} + // Cancel an activity if it is still running. Otherwise, do nothing. message CancelActivityCommand { bytes task_token = 1; @@ -331,9 +338,14 @@ message CancelActivityCommand { message WorkerCommandResult { oneof type { CancelActivityResult cancel_activity = 1; + WorkflowTaskHeartbeatNotificationResult workflow_task_heartbeat_notification = 2; } } +// Result of a WorkflowTaskHeartbeatNotificationCommand. Stale tasks are successful no-ops. +message WorkflowTaskHeartbeatNotificationResult { +} + // Result of a CancelActivityCommand. // Treat both successful cancellation and no-op (activity is no longer running) as success. message CancelActivityResult { diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index 2ad815a5e..617fec59c 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -308,6 +308,8 @@ message PollWorkflowTaskQueueRequest { // A dedicated per-worker Nexus task queue on which the server sends control // tasks (e.g. activity cancellation) to this specific worker instance. string worker_control_task_queue = 9; + // Whether this worker can heartbeat a running Workflow Task on a worker command. + bool supports_workflow_task_heartbeat_notification = 11; // Deprecated. Use deployment_options instead. // Each worker process should provide an ID unique to the specific set of code it is running From 03251276a0ac390b43f788a4df857f07cce6fe1d Mon Sep 17 00:00:00 2001 From: Feiyang Xie Date: Fri, 23 Oct 2026 11:28:47 -0700 Subject: [PATCH 2/4] Report eager workflow worker control queue --- .../api/workflowservice/v1/request_response.proto | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index 617fec59c..e31474c0f 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -227,6 +227,11 @@ message StartWorkflowExecutionRequest { // This field is intended for use by the Temporal server, for example when a schedule // starts a workflow, and is not intended to be set by external clients. temporal.api.common.v1.TimeSkippingStatePropagation time_skipping_state_propagation = 31; + + // Experimental. A dedicated per-worker Nexus task queue for control tasks sent to + // the worker processing the eager Workflow Task. Only used when eager execution is accepted. + // Setting this field indicates that the worker supports Workflow Task heartbeat notifications. + string worker_control_task_queue = 32; } message StartWorkflowExecutionResponse { @@ -305,10 +310,10 @@ message PollWorkflowTaskQueueRequest { // This is guaranteed to be unique, whereas identity is not guaranteed to be unique. string worker_instance_key = 8; - // A dedicated per-worker Nexus task queue on which the server sends control + // Experimental. A dedicated per-worker Nexus task queue on which the server sends control // tasks (e.g. activity cancellation) to this specific worker instance. string worker_control_task_queue = 9; - // Whether this worker can heartbeat a running Workflow Task on a worker command. + // Experimental. Whether this worker can heartbeat a running Workflow Task on a worker command. bool supports_workflow_task_heartbeat_notification = 11; // Deprecated. Use deployment_options instead. @@ -455,7 +460,7 @@ message RespondWorkflowTaskCompletedRequest { // This is guaranteed to be unique, whereas identity is not guaranteed to be unique. string worker_instance_key = 19; - // A dedicated per-worker Nexus task queue on which the server sends control + // Experimental. A dedicated per-worker Nexus task queue on which the server sends control // tasks (e.g. activity cancellation) to this specific worker instance. string worker_control_task_queue = 20; @@ -540,7 +545,7 @@ message PollActivityTaskQueueRequest { // This is guaranteed to be unique, whereas identity is not guaranteed to be unique. string worker_instance_key = 8; - // A dedicated per-worker Nexus task queue on which the server sends control + // Experimental. A dedicated per-worker Nexus task queue on which the server sends control // tasks (e.g. activity cancellation) to this specific worker instance. string worker_control_task_queue = 9; From 315d579fab79dce5cbe432e5d00545131c015181 Mon Sep 17 00:00:00 2001 From: Feiyang Xie Date: Fri, 23 Oct 2026 11:32:38 -0700 Subject: [PATCH 3/4] Regenerate OpenAPI for eager worker control queue --- openapi/openapiv2.json | 4 ++++ openapi/openapiv3.yaml | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 830cf957d..d9214cb95 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -12921,6 +12921,10 @@ "timeSkippingStatePropagation": { "$ref": "#/definitions/v1TimeSkippingStatePropagation", "description": "Time-skipping state propagated by the execution that started this workflow.\nThis field is intended for use by the Temporal server, for example when a schedule\nstarts a workflow, and is not intended to be set by external clients." + }, + "workerControlTaskQueue": { + "type": "string", + "description": "Experimental. A dedicated per-worker Nexus task queue for control tasks sent to\nthe worker processing the eager Workflow Task. Only used when eager execution is accepted.\nSetting this field indicates that the worker supports Workflow Task heartbeat notifications." } } }, diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 72df3d718..c3daf4a9a 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -17901,6 +17901,12 @@ components: Time-skipping state propagated by the execution that started this workflow. This field is intended for use by the Temporal server, for example when a schedule starts a workflow, and is not intended to be set by external clients. + workerControlTaskQueue: + type: string + description: |- + Experimental. A dedicated per-worker Nexus task queue for control tasks sent to + the worker processing the eager Workflow Task. Only used when eager execution is accepted. + Setting this field indicates that the worker supports Workflow Task heartbeat notifications. StartWorkflowExecutionResponse: type: object properties: From 2227e26a905310fe69f532a079b3c5043d9b4c82 Mon Sep 17 00:00:00 2001 From: Feiyang Xie Date: Fri, 23 Oct 2026 14:30:44 -0700 Subject: [PATCH 4/4] Report workflow task heartbeat notification outcomes --- temporal/api/worker/v1/message.proto | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/temporal/api/worker/v1/message.proto b/temporal/api/worker/v1/message.proto index d3c56df24..8a40b1ea3 100644 --- a/temporal/api/worker/v1/message.proto +++ b/temporal/api/worker/v1/message.proto @@ -342,8 +342,27 @@ message WorkerCommandResult { } } -// Result of a WorkflowTaskHeartbeatNotificationCommand. Stale tasks are successful no-ops. +// Result of a WorkflowTaskHeartbeatNotificationCommand. +// A successful result acknowledges the notification, not completion of a Workflow Task heartbeat. message WorkflowTaskHeartbeatNotificationResult { + enum Outcome { + // No outcome was reported. This is also the value returned by older SDKs. + OUTCOME_UNSPECIFIED = 0; + // Success: the notification was accepted for the matching Workflow Task. + OUTCOME_HANDLED = 1; + // Success: the matching Workflow Task has already received this notification. + OUTCOME_ALREADY_RECEIVED = 2; + // Success: the matching Workflow Task has no pending Local Activity and needs no early heartbeat. + OUTCOME_NO_LOCAL_ACTIVITY = 3; + // Failure: the worker has no active Workflow Task. + OUTCOME_NO_WORKFLOW_TASK = 4; + // Failure: the worker has active Workflow Tasks, but none has the notification's task token. + OUTCOME_TASK_TOKEN_MISMATCH = 5; + } + + // The SDK's result for this notification. The failure outcomes let the server measure + // unmatched notifications and decide whether to retry while the target task is still running. + Outcome outcome = 1; } // Result of a CancelActivityCommand.