Include transient and speculative WFT events in GetWorkflowExecutionHistoryResponse (#9138)

## What changed?
Include transient and speculative WFT events in
`GetWorkflowExecutionHistoryReponse` response, unless UI or CLI made
request.

* Adds `transient_or_speculative_events` back to
`GetMutableStateResponse`
* Reserve `transient_workflow_task` in `HisotryCOntinuation` token
* Add validation helpers
* Add query-compare-query for transient events at request start and end

Re-implements #7732

## Why?
Fix "premature end of stream" errors when workers request history after
cache eviction w/ transient/speculative workflow tasks present. This
adds transient & speculative WFT events in `GetWorkflowExecutionHistory`
(already in `PollWorkflowTask`). Worker cache eviction w/ speculative
workflow tasks causes the expected and actual event counts to be
different. #7732 passed transient events through continuation tokens,
which could become stale during pagination. This PR implements mutable
state querying at both start and end of pagination and compares
transient event IDs to detect if WFT state changed during pagination and
return a retryable error.

## How did you test it?
- [X] built
- [X] run locally and tested manually
- [X] covered by existing tests
- [ ] added new unit test(s)
- [ ] added new functional test(s)

## Potential risks
Same risks from #7732
This commit is contained in:
Sean Kane
2026-02-13 19:05:53 +00:00
committed by GitHub
parent f9761fd1d8
commit c627307e9e
24 changed files with 1453 additions and 417 deletions
+1 -1
View File
@@ -79,7 +79,7 @@ jobs:
feature-tests-ts:
needs: build-docker-image
uses: temporalio/features/.github/workflows/typescript.yaml@main
uses: temporalio/features/.github/workflows/typescript.yaml@spk/update-bug
with:
# This field is not actually used by these workflow if docker-image-artifact-name
# is set, but it's marked as required, so supply some string.
+249 -237
View File
@@ -538,8 +538,11 @@ type GetMutableStateResponse struct {
InheritedBuildId string `protobuf:"bytes,23,opt,name=inherited_build_id,json=inheritedBuildId,proto3" json:"inherited_build_id,omitempty"`
TransitionHistory []*v19.VersionedTransition `protobuf:"bytes,24,rep,name=transition_history,json=transitionHistory,proto3" json:"transition_history,omitempty"`
VersioningInfo *v15.WorkflowExecutionVersioningInfo `protobuf:"bytes,25,opt,name=versioning_info,json=versioningInfo,proto3" json:"versioning_info,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
// Transient or speculative workflow task events which are not yet persisted in the history.
// These events should be appended to the history when it is returned to the worker.
TransientOrSpeculativeTasks *v18.TransientWorkflowTaskInfo `protobuf:"bytes,26,opt,name=transient_or_speculative_tasks,json=transientOrSpeculativeTasks,proto3" json:"transient_or_speculative_tasks,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetMutableStateResponse) Reset() {
@@ -712,6 +715,13 @@ func (x *GetMutableStateResponse) GetVersioningInfo() *v15.WorkflowExecutionVers
return nil
}
func (x *GetMutableStateResponse) GetTransientOrSpeculativeTasks() *v18.TransientWorkflowTaskInfo {
if x != nil {
return x.TransientOrSpeculativeTasks
}
return nil
}
type PollMutableStateRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
NamespaceId string `protobuf:"bytes,1,opt,name=namespace_id,json=namespaceId,proto3" json:"namespace_id,omitempty"`
@@ -10211,7 +10221,7 @@ const file_temporal_server_api_historyservice_v1_request_response_proto_rawDesc
"\x16expected_next_event_id\x18\x03 \x01(\x03R\x13expectedNextEventId\x120\n" +
"\x14current_branch_token\x18\x04 \x01(\fR\x12currentBranchToken\x12d\n" +
"\x14version_history_item\x18\x05 \x01(\v22.temporal.server.api.history.v1.VersionHistoryItemR\x12versionHistoryItem\x12j\n" +
"\x14versioned_transition\x18\x06 \x01(\v27.temporal.server.api.persistence.v1.VersionedTransitionR\x13versionedTransition:\x1b\x92\xc4\x03\x17*\x15execution.workflow_id\"\xf3\v\n" +
"\x14versioned_transition\x18\x06 \x01(\v27.temporal.server.api.persistence.v1.VersionedTransitionR\x13versionedTransition:\x1b\x92\xc4\x03\x17*\x15execution.workflow_id\"\xf3\f\n" +
"\x17GetMutableStateResponse\x12G\n" +
"\texecution\x18\x01 \x01(\v2).temporal.api.common.v1.WorkflowExecutionR\texecution\x12I\n" +
"\rworkflow_type\x18\x02 \x01(\v2$.temporal.api.common.v1.WorkflowTypeR\fworkflowType\x12\"\n" +
@@ -10233,7 +10243,8 @@ const file_temporal_server_api_historyservice_v1_request_response_proto_rawDesc
"\x11assigned_build_id\x18\x16 \x01(\tR\x0fassignedBuildId\x12,\n" +
"\x12inherited_build_id\x18\x17 \x01(\tR\x10inheritedBuildId\x12f\n" +
"\x12transition_history\x18\x18 \x03(\v27.temporal.server.api.persistence.v1.VersionedTransitionR\x11transitionHistory\x12b\n" +
"\x0fversioning_info\x18\x19 \x01(\v29.temporal.api.workflow.v1.WorkflowExecutionVersioningInfoR\x0eversioningInfoJ\x04\b\b\x10\tJ\x04\b\t\x10\n" +
"\x0fversioning_info\x18\x19 \x01(\v29.temporal.api.workflow.v1.WorkflowExecutionVersioningInfoR\x0eversioningInfo\x12~\n" +
"\x1etransient_or_speculative_tasks\x18\x1a \x01(\v29.temporal.server.api.history.v1.TransientWorkflowTaskInfoR\x1btransientOrSpeculativeTasksJ\x04\b\b\x10\tJ\x04\b\t\x10\n" +
"J\x04\b\n" +
"\x10\vJ\x04\b\f\x10\rJ\x04\b\x0e\x10\x0f\"\xef\x02\n" +
"\x17PollMutableStateRequest\x12!\n" +
@@ -11107,11 +11118,11 @@ var file_temporal_server_api_historyservice_v1_request_response_proto_goTypes =
(v111.WorkflowExecutionState)(0), // 186: temporal.server.api.enums.v1.WorkflowExecutionState
(*v18.VersionHistories)(nil), // 187: temporal.server.api.history.v1.VersionHistories
(*v15.WorkflowExecutionVersioningInfo)(nil), // 188: temporal.api.workflow.v1.WorkflowExecutionVersioningInfo
(*v1.PollWorkflowTaskQueueRequest)(nil), // 189: temporal.api.workflowservice.v1.PollWorkflowTaskQueueRequest
(*v112.BuildIdRedirectInfo)(nil), // 190: temporal.server.api.taskqueue.v1.BuildIdRedirectInfo
(*v16.Deployment)(nil), // 191: temporal.api.deployment.v1.Deployment
(*v112.TaskVersionDirective)(nil), // 192: temporal.server.api.taskqueue.v1.TaskVersionDirective
(*v18.TransientWorkflowTaskInfo)(nil), // 193: temporal.server.api.history.v1.TransientWorkflowTaskInfo
(*v18.TransientWorkflowTaskInfo)(nil), // 189: temporal.server.api.history.v1.TransientWorkflowTaskInfo
(*v1.PollWorkflowTaskQueueRequest)(nil), // 190: temporal.api.workflowservice.v1.PollWorkflowTaskQueueRequest
(*v112.BuildIdRedirectInfo)(nil), // 191: temporal.server.api.taskqueue.v1.BuildIdRedirectInfo
(*v16.Deployment)(nil), // 192: temporal.api.deployment.v1.Deployment
(*v112.TaskVersionDirective)(nil), // 193: temporal.server.api.taskqueue.v1.TaskVersionDirective
(*v114.Message)(nil), // 194: temporal.api.protocol.v1.Message
(*v115.History)(nil), // 195: temporal.api.history.v1.History
(*v1.PollActivityTaskQueueRequest)(nil), // 196: temporal.api.workflowservice.v1.PollActivityTaskQueueRequest
@@ -11224,234 +11235,235 @@ var file_temporal_server_api_historyservice_v1_request_response_proto_depIdxs =
172, // 27: temporal.server.api.historyservice.v1.GetMutableStateResponse.most_recent_worker_version_stamp:type_name -> temporal.api.common.v1.WorkerVersionStamp
183, // 28: temporal.server.api.historyservice.v1.GetMutableStateResponse.transition_history:type_name -> temporal.server.api.persistence.v1.VersionedTransition
188, // 29: temporal.server.api.historyservice.v1.GetMutableStateResponse.versioning_info:type_name -> temporal.api.workflow.v1.WorkflowExecutionVersioningInfo
181, // 30: temporal.server.api.historyservice.v1.PollMutableStateRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
182, // 31: temporal.server.api.historyservice.v1.PollMutableStateRequest.version_history_item:type_name -> temporal.server.api.history.v1.VersionHistoryItem
181, // 32: temporal.server.api.historyservice.v1.PollMutableStateResponse.execution:type_name -> temporal.api.common.v1.WorkflowExecution
184, // 33: temporal.server.api.historyservice.v1.PollMutableStateResponse.workflow_type:type_name -> temporal.api.common.v1.WorkflowType
185, // 34: temporal.server.api.historyservice.v1.PollMutableStateResponse.task_queue:type_name -> temporal.api.taskqueue.v1.TaskQueue
185, // 35: temporal.server.api.historyservice.v1.PollMutableStateResponse.sticky_task_queue:type_name -> temporal.api.taskqueue.v1.TaskQueue
171, // 36: temporal.server.api.historyservice.v1.PollMutableStateResponse.sticky_task_queue_schedule_to_start_timeout:type_name -> google.protobuf.Duration
187, // 37: temporal.server.api.historyservice.v1.PollMutableStateResponse.version_histories:type_name -> temporal.server.api.history.v1.VersionHistories
186, // 38: temporal.server.api.historyservice.v1.PollMutableStateResponse.workflow_state:type_name -> temporal.server.api.enums.v1.WorkflowExecutionState
179, // 39: temporal.server.api.historyservice.v1.PollMutableStateResponse.workflow_status:type_name -> temporal.api.enums.v1.WorkflowExecutionStatus
181, // 40: temporal.server.api.historyservice.v1.ResetStickyTaskQueueRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
156, // 41: temporal.server.api.historyservice.v1.ExecuteMultiOperationRequest.operations:type_name -> temporal.server.api.historyservice.v1.ExecuteMultiOperationRequest.Operation
157, // 42: temporal.server.api.historyservice.v1.ExecuteMultiOperationResponse.responses:type_name -> temporal.server.api.historyservice.v1.ExecuteMultiOperationResponse.Response
181, // 43: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedRequest.workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
189, // 44: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedRequest.poll_request:type_name -> temporal.api.workflowservice.v1.PollWorkflowTaskQueueRequest
177, // 45: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedRequest.clock:type_name -> temporal.server.api.clock.v1.VectorClock
190, // 46: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedRequest.build_id_redirect_info:type_name -> temporal.server.api.taskqueue.v1.BuildIdRedirectInfo
191, // 47: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedRequest.scheduled_deployment:type_name -> temporal.api.deployment.v1.Deployment
192, // 48: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedRequest.version_directive:type_name -> temporal.server.api.taskqueue.v1.TaskVersionDirective
175, // 49: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedRequest.target_deployment_version:type_name -> temporal.api.deployment.v1.WorkerDeploymentVersion
184, // 50: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.workflow_type:type_name -> temporal.api.common.v1.WorkflowType
193, // 51: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.transient_workflow_task:type_name -> temporal.server.api.history.v1.TransientWorkflowTaskInfo
185, // 52: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.workflow_execution_task_queue:type_name -> temporal.api.taskqueue.v1.TaskQueue
167, // 53: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.scheduled_time:type_name -> google.protobuf.Timestamp
167, // 54: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.started_time:type_name -> google.protobuf.Timestamp
158, // 55: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.queries:type_name -> temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.QueriesEntry
177, // 56: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.clock:type_name -> temporal.server.api.clock.v1.VectorClock
194, // 57: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.messages:type_name -> temporal.api.protocol.v1.Message
195, // 58: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.history:type_name -> temporal.api.history.v1.History
195, // 59: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.raw_history:type_name -> temporal.api.history.v1.History
184, // 60: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.workflow_type:type_name -> temporal.api.common.v1.WorkflowType
193, // 61: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.transient_workflow_task:type_name -> temporal.server.api.history.v1.TransientWorkflowTaskInfo
185, // 62: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.workflow_execution_task_queue:type_name -> temporal.api.taskqueue.v1.TaskQueue
167, // 63: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.scheduled_time:type_name -> google.protobuf.Timestamp
167, // 64: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.started_time:type_name -> google.protobuf.Timestamp
159, // 65: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.queries:type_name -> temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.QueriesEntry
177, // 66: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.clock:type_name -> temporal.server.api.clock.v1.VectorClock
194, // 67: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.messages:type_name -> temporal.api.protocol.v1.Message
195, // 68: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.history:type_name -> temporal.api.history.v1.History
181, // 69: temporal.server.api.historyservice.v1.RecordActivityTaskStartedRequest.workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
196, // 70: temporal.server.api.historyservice.v1.RecordActivityTaskStartedRequest.poll_request:type_name -> temporal.api.workflowservice.v1.PollActivityTaskQueueRequest
177, // 71: temporal.server.api.historyservice.v1.RecordActivityTaskStartedRequest.clock:type_name -> temporal.server.api.clock.v1.VectorClock
190, // 72: temporal.server.api.historyservice.v1.RecordActivityTaskStartedRequest.build_id_redirect_info:type_name -> temporal.server.api.taskqueue.v1.BuildIdRedirectInfo
191, // 73: temporal.server.api.historyservice.v1.RecordActivityTaskStartedRequest.scheduled_deployment:type_name -> temporal.api.deployment.v1.Deployment
192, // 74: temporal.server.api.historyservice.v1.RecordActivityTaskStartedRequest.version_directive:type_name -> temporal.server.api.taskqueue.v1.TaskVersionDirective
197, // 75: temporal.server.api.historyservice.v1.RecordActivityTaskStartedResponse.scheduled_event:type_name -> temporal.api.history.v1.HistoryEvent
167, // 76: temporal.server.api.historyservice.v1.RecordActivityTaskStartedResponse.started_time:type_name -> google.protobuf.Timestamp
167, // 77: temporal.server.api.historyservice.v1.RecordActivityTaskStartedResponse.current_attempt_scheduled_time:type_name -> google.protobuf.Timestamp
170, // 78: temporal.server.api.historyservice.v1.RecordActivityTaskStartedResponse.heartbeat_details:type_name -> temporal.api.common.v1.Payloads
184, // 79: temporal.server.api.historyservice.v1.RecordActivityTaskStartedResponse.workflow_type:type_name -> temporal.api.common.v1.WorkflowType
177, // 80: temporal.server.api.historyservice.v1.RecordActivityTaskStartedResponse.clock:type_name -> temporal.server.api.clock.v1.VectorClock
198, // 81: temporal.server.api.historyservice.v1.RecordActivityTaskStartedResponse.priority:type_name -> temporal.api.common.v1.Priority
199, // 82: temporal.server.api.historyservice.v1.RecordActivityTaskStartedResponse.retry_policy:type_name -> temporal.api.common.v1.RetryPolicy
200, // 83: temporal.server.api.historyservice.v1.RespondWorkflowTaskCompletedRequest.complete_request:type_name -> temporal.api.workflowservice.v1.RespondWorkflowTaskCompletedRequest
12, // 84: temporal.server.api.historyservice.v1.RespondWorkflowTaskCompletedResponse.started_response:type_name -> temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse
201, // 85: temporal.server.api.historyservice.v1.RespondWorkflowTaskCompletedResponse.activity_tasks:type_name -> temporal.api.workflowservice.v1.PollActivityTaskQueueResponse
178, // 86: temporal.server.api.historyservice.v1.RespondWorkflowTaskCompletedResponse.new_workflow_task:type_name -> temporal.api.workflowservice.v1.PollWorkflowTaskQueueResponse
202, // 87: temporal.server.api.historyservice.v1.RespondWorkflowTaskFailedRequest.failed_request:type_name -> temporal.api.workflowservice.v1.RespondWorkflowTaskFailedRequest
181, // 88: temporal.server.api.historyservice.v1.IsWorkflowTaskValidRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
177, // 89: temporal.server.api.historyservice.v1.IsWorkflowTaskValidRequest.clock:type_name -> temporal.server.api.clock.v1.VectorClock
203, // 90: temporal.server.api.historyservice.v1.RecordActivityTaskHeartbeatRequest.heartbeat_request:type_name -> temporal.api.workflowservice.v1.RecordActivityTaskHeartbeatRequest
204, // 91: temporal.server.api.historyservice.v1.RespondActivityTaskCompletedRequest.complete_request:type_name -> temporal.api.workflowservice.v1.RespondActivityTaskCompletedRequest
205, // 92: temporal.server.api.historyservice.v1.RespondActivityTaskFailedRequest.failed_request:type_name -> temporal.api.workflowservice.v1.RespondActivityTaskFailedRequest
206, // 93: temporal.server.api.historyservice.v1.RespondActivityTaskCanceledRequest.cancel_request:type_name -> temporal.api.workflowservice.v1.RespondActivityTaskCanceledRequest
181, // 94: temporal.server.api.historyservice.v1.IsActivityTaskValidRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
177, // 95: temporal.server.api.historyservice.v1.IsActivityTaskValidRequest.clock:type_name -> temporal.server.api.clock.v1.VectorClock
207, // 96: temporal.server.api.historyservice.v1.SignalWorkflowExecutionRequest.signal_request:type_name -> temporal.api.workflowservice.v1.SignalWorkflowExecutionRequest
181, // 97: temporal.server.api.historyservice.v1.SignalWorkflowExecutionRequest.external_workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
208, // 98: temporal.server.api.historyservice.v1.SignalWithStartWorkflowExecutionRequest.signal_with_start_request:type_name -> temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest
181, // 99: temporal.server.api.historyservice.v1.RemoveSignalMutableStateRequest.workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
209, // 100: temporal.server.api.historyservice.v1.TerminateWorkflowExecutionRequest.terminate_request:type_name -> temporal.api.workflowservice.v1.TerminateWorkflowExecutionRequest
181, // 101: temporal.server.api.historyservice.v1.TerminateWorkflowExecutionRequest.external_workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
181, // 102: temporal.server.api.historyservice.v1.DeleteWorkflowExecutionRequest.workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
210, // 103: temporal.server.api.historyservice.v1.ResetWorkflowExecutionRequest.reset_request:type_name -> temporal.api.workflowservice.v1.ResetWorkflowExecutionRequest
211, // 104: temporal.server.api.historyservice.v1.RequestCancelWorkflowExecutionRequest.cancel_request:type_name -> temporal.api.workflowservice.v1.RequestCancelWorkflowExecutionRequest
181, // 105: temporal.server.api.historyservice.v1.RequestCancelWorkflowExecutionRequest.external_workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
181, // 106: temporal.server.api.historyservice.v1.ScheduleWorkflowTaskRequest.workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
177, // 107: temporal.server.api.historyservice.v1.ScheduleWorkflowTaskRequest.child_clock:type_name -> temporal.server.api.clock.v1.VectorClock
177, // 108: temporal.server.api.historyservice.v1.ScheduleWorkflowTaskRequest.parent_clock:type_name -> temporal.server.api.clock.v1.VectorClock
181, // 109: temporal.server.api.historyservice.v1.VerifyFirstWorkflowTaskScheduledRequest.workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
177, // 110: temporal.server.api.historyservice.v1.VerifyFirstWorkflowTaskScheduledRequest.clock:type_name -> temporal.server.api.clock.v1.VectorClock
181, // 111: temporal.server.api.historyservice.v1.RecordChildExecutionCompletedRequest.parent_execution:type_name -> temporal.api.common.v1.WorkflowExecution
181, // 112: temporal.server.api.historyservice.v1.RecordChildExecutionCompletedRequest.child_execution:type_name -> temporal.api.common.v1.WorkflowExecution
197, // 113: temporal.server.api.historyservice.v1.RecordChildExecutionCompletedRequest.completion_event:type_name -> temporal.api.history.v1.HistoryEvent
177, // 114: temporal.server.api.historyservice.v1.RecordChildExecutionCompletedRequest.clock:type_name -> temporal.server.api.clock.v1.VectorClock
181, // 115: temporal.server.api.historyservice.v1.VerifyChildExecutionCompletionRecordedRequest.parent_execution:type_name -> temporal.api.common.v1.WorkflowExecution
181, // 116: temporal.server.api.historyservice.v1.VerifyChildExecutionCompletionRecordedRequest.child_execution:type_name -> temporal.api.common.v1.WorkflowExecution
177, // 117: temporal.server.api.historyservice.v1.VerifyChildExecutionCompletionRecordedRequest.clock:type_name -> temporal.server.api.clock.v1.VectorClock
212, // 118: temporal.server.api.historyservice.v1.DescribeWorkflowExecutionRequest.request:type_name -> temporal.api.workflowservice.v1.DescribeWorkflowExecutionRequest
213, // 119: temporal.server.api.historyservice.v1.DescribeWorkflowExecutionResponse.execution_config:type_name -> temporal.api.workflow.v1.WorkflowExecutionConfig
214, // 120: temporal.server.api.historyservice.v1.DescribeWorkflowExecutionResponse.workflow_execution_info:type_name -> temporal.api.workflow.v1.WorkflowExecutionInfo
215, // 121: temporal.server.api.historyservice.v1.DescribeWorkflowExecutionResponse.pending_activities:type_name -> temporal.api.workflow.v1.PendingActivityInfo
216, // 122: temporal.server.api.historyservice.v1.DescribeWorkflowExecutionResponse.pending_children:type_name -> temporal.api.workflow.v1.PendingChildExecutionInfo
217, // 123: temporal.server.api.historyservice.v1.DescribeWorkflowExecutionResponse.pending_workflow_task:type_name -> temporal.api.workflow.v1.PendingWorkflowTaskInfo
218, // 124: temporal.server.api.historyservice.v1.DescribeWorkflowExecutionResponse.callbacks:type_name -> temporal.api.workflow.v1.CallbackInfo
219, // 125: temporal.server.api.historyservice.v1.DescribeWorkflowExecutionResponse.pending_nexus_operations:type_name -> temporal.api.workflow.v1.PendingNexusOperationInfo
220, // 126: temporal.server.api.historyservice.v1.DescribeWorkflowExecutionResponse.workflow_extended_info:type_name -> temporal.api.workflow.v1.WorkflowExecutionExtendedInfo
181, // 127: temporal.server.api.historyservice.v1.ReplicateEventsV2Request.workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
182, // 128: temporal.server.api.historyservice.v1.ReplicateEventsV2Request.version_history_items:type_name -> temporal.server.api.history.v1.VersionHistoryItem
221, // 129: temporal.server.api.historyservice.v1.ReplicateEventsV2Request.events:type_name -> temporal.api.common.v1.DataBlob
221, // 130: temporal.server.api.historyservice.v1.ReplicateEventsV2Request.new_run_events:type_name -> temporal.api.common.v1.DataBlob
222, // 131: temporal.server.api.historyservice.v1.ReplicateEventsV2Request.base_execution_info:type_name -> temporal.server.api.workflow.v1.BaseExecutionInfo
223, // 132: temporal.server.api.historyservice.v1.ReplicateWorkflowStateRequest.workflow_state:type_name -> temporal.server.api.persistence.v1.WorkflowMutableState
167, // 133: temporal.server.api.historyservice.v1.SyncShardStatusRequest.status_time:type_name -> google.protobuf.Timestamp
167, // 134: temporal.server.api.historyservice.v1.SyncActivityRequest.scheduled_time:type_name -> google.protobuf.Timestamp
167, // 135: temporal.server.api.historyservice.v1.SyncActivityRequest.started_time:type_name -> google.protobuf.Timestamp
167, // 136: temporal.server.api.historyservice.v1.SyncActivityRequest.last_heartbeat_time:type_name -> google.protobuf.Timestamp
170, // 137: temporal.server.api.historyservice.v1.SyncActivityRequest.details:type_name -> temporal.api.common.v1.Payloads
169, // 138: temporal.server.api.historyservice.v1.SyncActivityRequest.last_failure:type_name -> temporal.api.failure.v1.Failure
224, // 139: temporal.server.api.historyservice.v1.SyncActivityRequest.version_history:type_name -> temporal.server.api.history.v1.VersionHistory
222, // 140: temporal.server.api.historyservice.v1.SyncActivityRequest.base_execution_info:type_name -> temporal.server.api.workflow.v1.BaseExecutionInfo
167, // 141: temporal.server.api.historyservice.v1.SyncActivityRequest.first_scheduled_time:type_name -> google.protobuf.Timestamp
167, // 142: temporal.server.api.historyservice.v1.SyncActivityRequest.last_attempt_complete_time:type_name -> google.protobuf.Timestamp
171, // 143: temporal.server.api.historyservice.v1.SyncActivityRequest.retry_initial_interval:type_name -> google.protobuf.Duration
171, // 144: temporal.server.api.historyservice.v1.SyncActivityRequest.retry_maximum_interval:type_name -> google.protobuf.Duration
64, // 145: temporal.server.api.historyservice.v1.SyncActivitiesRequest.activities_info:type_name -> temporal.server.api.historyservice.v1.ActivitySyncInfo
167, // 146: temporal.server.api.historyservice.v1.ActivitySyncInfo.scheduled_time:type_name -> google.protobuf.Timestamp
167, // 147: temporal.server.api.historyservice.v1.ActivitySyncInfo.started_time:type_name -> google.protobuf.Timestamp
167, // 148: temporal.server.api.historyservice.v1.ActivitySyncInfo.last_heartbeat_time:type_name -> google.protobuf.Timestamp
170, // 149: temporal.server.api.historyservice.v1.ActivitySyncInfo.details:type_name -> temporal.api.common.v1.Payloads
169, // 150: temporal.server.api.historyservice.v1.ActivitySyncInfo.last_failure:type_name -> temporal.api.failure.v1.Failure
224, // 151: temporal.server.api.historyservice.v1.ActivitySyncInfo.version_history:type_name -> temporal.server.api.history.v1.VersionHistory
167, // 152: temporal.server.api.historyservice.v1.ActivitySyncInfo.first_scheduled_time:type_name -> google.protobuf.Timestamp
167, // 153: temporal.server.api.historyservice.v1.ActivitySyncInfo.last_attempt_complete_time:type_name -> google.protobuf.Timestamp
171, // 154: temporal.server.api.historyservice.v1.ActivitySyncInfo.retry_initial_interval:type_name -> google.protobuf.Duration
171, // 155: temporal.server.api.historyservice.v1.ActivitySyncInfo.retry_maximum_interval:type_name -> google.protobuf.Duration
181, // 156: temporal.server.api.historyservice.v1.DescribeMutableStateRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
223, // 157: temporal.server.api.historyservice.v1.DescribeMutableStateResponse.cache_mutable_state:type_name -> temporal.server.api.persistence.v1.WorkflowMutableState
223, // 158: temporal.server.api.historyservice.v1.DescribeMutableStateResponse.database_mutable_state:type_name -> temporal.server.api.persistence.v1.WorkflowMutableState
181, // 159: temporal.server.api.historyservice.v1.DescribeHistoryHostRequest.workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
225, // 160: temporal.server.api.historyservice.v1.DescribeHistoryHostResponse.namespace_cache:type_name -> temporal.server.api.namespace.v1.NamespaceCacheInfo
226, // 161: temporal.server.api.historyservice.v1.GetShardResponse.shard_info:type_name -> temporal.server.api.persistence.v1.ShardInfo
167, // 162: temporal.server.api.historyservice.v1.RemoveTaskRequest.visibility_time:type_name -> google.protobuf.Timestamp
227, // 163: temporal.server.api.historyservice.v1.GetReplicationMessagesRequest.tokens:type_name -> temporal.server.api.replication.v1.ReplicationToken
160, // 164: temporal.server.api.historyservice.v1.GetReplicationMessagesResponse.shard_messages:type_name -> temporal.server.api.historyservice.v1.GetReplicationMessagesResponse.ShardMessagesEntry
228, // 165: temporal.server.api.historyservice.v1.GetDLQReplicationMessagesRequest.task_infos:type_name -> temporal.server.api.replication.v1.ReplicationTaskInfo
229, // 166: temporal.server.api.historyservice.v1.GetDLQReplicationMessagesResponse.replication_tasks:type_name -> temporal.server.api.replication.v1.ReplicationTask
230, // 167: temporal.server.api.historyservice.v1.QueryWorkflowRequest.request:type_name -> temporal.api.workflowservice.v1.QueryWorkflowRequest
231, // 168: temporal.server.api.historyservice.v1.QueryWorkflowResponse.response:type_name -> temporal.api.workflowservice.v1.QueryWorkflowResponse
232, // 169: temporal.server.api.historyservice.v1.ReapplyEventsRequest.request:type_name -> temporal.server.api.adminservice.v1.ReapplyEventsRequest
233, // 170: temporal.server.api.historyservice.v1.GetDLQMessagesRequest.type:type_name -> temporal.server.api.enums.v1.DeadLetterQueueType
233, // 171: temporal.server.api.historyservice.v1.GetDLQMessagesResponse.type:type_name -> temporal.server.api.enums.v1.DeadLetterQueueType
229, // 172: temporal.server.api.historyservice.v1.GetDLQMessagesResponse.replication_tasks:type_name -> temporal.server.api.replication.v1.ReplicationTask
228, // 173: temporal.server.api.historyservice.v1.GetDLQMessagesResponse.replication_tasks_info:type_name -> temporal.server.api.replication.v1.ReplicationTaskInfo
233, // 174: temporal.server.api.historyservice.v1.PurgeDLQMessagesRequest.type:type_name -> temporal.server.api.enums.v1.DeadLetterQueueType
233, // 175: temporal.server.api.historyservice.v1.MergeDLQMessagesRequest.type:type_name -> temporal.server.api.enums.v1.DeadLetterQueueType
234, // 176: temporal.server.api.historyservice.v1.RefreshWorkflowTasksRequest.request:type_name -> temporal.server.api.adminservice.v1.RefreshWorkflowTasksRequest
181, // 177: temporal.server.api.historyservice.v1.GenerateLastHistoryReplicationTasksRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
96, // 178: temporal.server.api.historyservice.v1.GetReplicationStatusResponse.shards:type_name -> temporal.server.api.historyservice.v1.ShardReplicationStatus
167, // 179: temporal.server.api.historyservice.v1.ShardReplicationStatus.shard_local_time:type_name -> google.protobuf.Timestamp
161, // 180: temporal.server.api.historyservice.v1.ShardReplicationStatus.remote_clusters:type_name -> temporal.server.api.historyservice.v1.ShardReplicationStatus.RemoteClustersEntry
162, // 181: temporal.server.api.historyservice.v1.ShardReplicationStatus.handover_namespaces:type_name -> temporal.server.api.historyservice.v1.ShardReplicationStatus.HandoverNamespacesEntry
167, // 182: temporal.server.api.historyservice.v1.ShardReplicationStatus.max_replication_task_visibility_time:type_name -> google.protobuf.Timestamp
167, // 183: temporal.server.api.historyservice.v1.ShardReplicationStatusPerCluster.acked_task_visibility_time:type_name -> google.protobuf.Timestamp
181, // 184: temporal.server.api.historyservice.v1.RebuildMutableStateRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
181, // 185: temporal.server.api.historyservice.v1.ImportWorkflowExecutionRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
221, // 186: temporal.server.api.historyservice.v1.ImportWorkflowExecutionRequest.history_batches:type_name -> temporal.api.common.v1.DataBlob
224, // 187: temporal.server.api.historyservice.v1.ImportWorkflowExecutionRequest.version_history:type_name -> temporal.server.api.history.v1.VersionHistory
181, // 188: temporal.server.api.historyservice.v1.DeleteWorkflowVisibilityRecordRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
167, // 189: temporal.server.api.historyservice.v1.DeleteWorkflowVisibilityRecordRequest.workflow_start_time:type_name -> google.protobuf.Timestamp
167, // 190: temporal.server.api.historyservice.v1.DeleteWorkflowVisibilityRecordRequest.workflow_close_time:type_name -> google.protobuf.Timestamp
235, // 191: temporal.server.api.historyservice.v1.UpdateWorkflowExecutionRequest.request:type_name -> temporal.api.workflowservice.v1.UpdateWorkflowExecutionRequest
236, // 192: temporal.server.api.historyservice.v1.UpdateWorkflowExecutionResponse.response:type_name -> temporal.api.workflowservice.v1.UpdateWorkflowExecutionResponse
237, // 193: temporal.server.api.historyservice.v1.StreamWorkflowReplicationMessagesRequest.sync_replication_state:type_name -> temporal.server.api.replication.v1.SyncReplicationState
238, // 194: temporal.server.api.historyservice.v1.StreamWorkflowReplicationMessagesResponse.messages:type_name -> temporal.server.api.replication.v1.WorkflowReplicationMessages
239, // 195: temporal.server.api.historyservice.v1.PollWorkflowExecutionUpdateRequest.request:type_name -> temporal.api.workflowservice.v1.PollWorkflowExecutionUpdateRequest
240, // 196: temporal.server.api.historyservice.v1.PollWorkflowExecutionUpdateResponse.response:type_name -> temporal.api.workflowservice.v1.PollWorkflowExecutionUpdateResponse
241, // 197: temporal.server.api.historyservice.v1.GetWorkflowExecutionHistoryRequest.request:type_name -> temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryRequest
242, // 198: temporal.server.api.historyservice.v1.GetWorkflowExecutionHistoryResponse.response:type_name -> temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryResponse
195, // 199: temporal.server.api.historyservice.v1.GetWorkflowExecutionHistoryResponse.history:type_name -> temporal.api.history.v1.History
242, // 200: temporal.server.api.historyservice.v1.GetWorkflowExecutionHistoryResponseWithRaw.response:type_name -> temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryResponse
243, // 201: temporal.server.api.historyservice.v1.GetWorkflowExecutionHistoryReverseRequest.request:type_name -> temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryReverseRequest
244, // 202: temporal.server.api.historyservice.v1.GetWorkflowExecutionHistoryReverseResponse.response:type_name -> temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryReverseResponse
245, // 203: temporal.server.api.historyservice.v1.GetWorkflowExecutionRawHistoryV2Request.request:type_name -> temporal.server.api.adminservice.v1.GetWorkflowExecutionRawHistoryV2Request
246, // 204: temporal.server.api.historyservice.v1.GetWorkflowExecutionRawHistoryV2Response.response:type_name -> temporal.server.api.adminservice.v1.GetWorkflowExecutionRawHistoryV2Response
247, // 205: temporal.server.api.historyservice.v1.GetWorkflowExecutionRawHistoryRequest.request:type_name -> temporal.server.api.adminservice.v1.GetWorkflowExecutionRawHistoryRequest
248, // 206: temporal.server.api.historyservice.v1.GetWorkflowExecutionRawHistoryResponse.response:type_name -> temporal.server.api.adminservice.v1.GetWorkflowExecutionRawHistoryResponse
249, // 207: temporal.server.api.historyservice.v1.ForceDeleteWorkflowExecutionRequest.request:type_name -> temporal.server.api.adminservice.v1.DeleteWorkflowExecutionRequest
250, // 208: temporal.server.api.historyservice.v1.ForceDeleteWorkflowExecutionResponse.response:type_name -> temporal.server.api.adminservice.v1.DeleteWorkflowExecutionResponse
251, // 209: temporal.server.api.historyservice.v1.GetDLQTasksRequest.dlq_key:type_name -> temporal.server.api.common.v1.HistoryDLQKey
252, // 210: temporal.server.api.historyservice.v1.GetDLQTasksResponse.dlq_tasks:type_name -> temporal.server.api.common.v1.HistoryDLQTask
251, // 211: temporal.server.api.historyservice.v1.DeleteDLQTasksRequest.dlq_key:type_name -> temporal.server.api.common.v1.HistoryDLQKey
253, // 212: temporal.server.api.historyservice.v1.DeleteDLQTasksRequest.inclusive_max_task_metadata:type_name -> temporal.server.api.common.v1.HistoryDLQTaskMetadata
163, // 213: temporal.server.api.historyservice.v1.ListQueuesResponse.queues:type_name -> temporal.server.api.historyservice.v1.ListQueuesResponse.QueueInfo
164, // 214: temporal.server.api.historyservice.v1.AddTasksRequest.tasks:type_name -> temporal.server.api.historyservice.v1.AddTasksRequest.Task
254, // 215: temporal.server.api.historyservice.v1.ListTasksRequest.request:type_name -> temporal.server.api.adminservice.v1.ListHistoryTasksRequest
255, // 216: temporal.server.api.historyservice.v1.ListTasksResponse.response:type_name -> temporal.server.api.adminservice.v1.ListHistoryTasksResponse
256, // 217: temporal.server.api.historyservice.v1.CompleteNexusOperationChasmRequest.completion:type_name -> temporal.server.api.token.v1.NexusOperationCompletion
257, // 218: temporal.server.api.historyservice.v1.CompleteNexusOperationChasmRequest.success:type_name -> temporal.api.common.v1.Payload
169, // 219: temporal.server.api.historyservice.v1.CompleteNexusOperationChasmRequest.failure:type_name -> temporal.api.failure.v1.Failure
167, // 220: temporal.server.api.historyservice.v1.CompleteNexusOperationChasmRequest.close_time:type_name -> google.protobuf.Timestamp
256, // 221: temporal.server.api.historyservice.v1.CompleteNexusOperationRequest.completion:type_name -> temporal.server.api.token.v1.NexusOperationCompletion
257, // 222: temporal.server.api.historyservice.v1.CompleteNexusOperationRequest.success:type_name -> temporal.api.common.v1.Payload
258, // 223: temporal.server.api.historyservice.v1.CompleteNexusOperationRequest.failure:type_name -> temporal.api.nexus.v1.Failure
167, // 224: temporal.server.api.historyservice.v1.CompleteNexusOperationRequest.start_time:type_name -> google.protobuf.Timestamp
180, // 225: temporal.server.api.historyservice.v1.CompleteNexusOperationRequest.links:type_name -> temporal.api.common.v1.Link
259, // 226: temporal.server.api.historyservice.v1.InvokeStateMachineMethodRequest.ref:type_name -> temporal.server.api.persistence.v1.StateMachineRef
260, // 227: temporal.server.api.historyservice.v1.DeepHealthCheckResponse.state:type_name -> temporal.server.api.enums.v1.HealthState
181, // 228: temporal.server.api.historyservice.v1.SyncWorkflowStateRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
183, // 229: temporal.server.api.historyservice.v1.SyncWorkflowStateRequest.versioned_transition:type_name -> temporal.server.api.persistence.v1.VersionedTransition
187, // 230: temporal.server.api.historyservice.v1.SyncWorkflowStateRequest.version_histories:type_name -> temporal.server.api.history.v1.VersionHistories
261, // 231: temporal.server.api.historyservice.v1.SyncWorkflowStateResponse.versioned_transition_artifact:type_name -> temporal.server.api.replication.v1.VersionedTransitionArtifact
262, // 232: temporal.server.api.historyservice.v1.UpdateActivityOptionsRequest.update_request:type_name -> temporal.api.workflowservice.v1.UpdateActivityOptionsRequest
263, // 233: temporal.server.api.historyservice.v1.UpdateActivityOptionsResponse.activity_options:type_name -> temporal.api.activity.v1.ActivityOptions
264, // 234: temporal.server.api.historyservice.v1.PauseActivityRequest.frontend_request:type_name -> temporal.api.workflowservice.v1.PauseActivityRequest
265, // 235: temporal.server.api.historyservice.v1.UnpauseActivityRequest.frontend_request:type_name -> temporal.api.workflowservice.v1.UnpauseActivityRequest
266, // 236: temporal.server.api.historyservice.v1.ResetActivityRequest.frontend_request:type_name -> temporal.api.workflowservice.v1.ResetActivityRequest
267, // 237: temporal.server.api.historyservice.v1.UpdateWorkflowExecutionOptionsRequest.update_request:type_name -> temporal.api.workflowservice.v1.UpdateWorkflowExecutionOptionsRequest
268, // 238: temporal.server.api.historyservice.v1.UpdateWorkflowExecutionOptionsResponse.workflow_execution_options:type_name -> temporal.api.workflow.v1.WorkflowExecutionOptions
269, // 239: temporal.server.api.historyservice.v1.PauseWorkflowExecutionRequest.pause_request:type_name -> temporal.api.workflowservice.v1.PauseWorkflowExecutionRequest
270, // 240: temporal.server.api.historyservice.v1.UnpauseWorkflowExecutionRequest.unpause_request:type_name -> temporal.api.workflowservice.v1.UnpauseWorkflowExecutionRequest
1, // 241: temporal.server.api.historyservice.v1.ExecuteMultiOperationRequest.Operation.start_workflow:type_name -> temporal.server.api.historyservice.v1.StartWorkflowExecutionRequest
105, // 242: temporal.server.api.historyservice.v1.ExecuteMultiOperationRequest.Operation.update_workflow:type_name -> temporal.server.api.historyservice.v1.UpdateWorkflowExecutionRequest
2, // 243: temporal.server.api.historyservice.v1.ExecuteMultiOperationResponse.Response.start_workflow:type_name -> temporal.server.api.historyservice.v1.StartWorkflowExecutionResponse
106, // 244: temporal.server.api.historyservice.v1.ExecuteMultiOperationResponse.Response.update_workflow:type_name -> temporal.server.api.historyservice.v1.UpdateWorkflowExecutionResponse
271, // 245: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.QueriesEntry.value:type_name -> temporal.api.query.v1.WorkflowQuery
271, // 246: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.QueriesEntry.value:type_name -> temporal.api.query.v1.WorkflowQuery
272, // 247: temporal.server.api.historyservice.v1.GetReplicationMessagesResponse.ShardMessagesEntry.value:type_name -> temporal.server.api.replication.v1.ReplicationMessages
98, // 248: temporal.server.api.historyservice.v1.ShardReplicationStatus.RemoteClustersEntry.value:type_name -> temporal.server.api.historyservice.v1.ShardReplicationStatusPerCluster
97, // 249: temporal.server.api.historyservice.v1.ShardReplicationStatus.HandoverNamespacesEntry.value:type_name -> temporal.server.api.historyservice.v1.HandoverNamespaceInfo
221, // 250: temporal.server.api.historyservice.v1.AddTasksRequest.Task.blob:type_name -> temporal.api.common.v1.DataBlob
273, // 251: temporal.server.api.historyservice.v1.routing:extendee -> google.protobuf.MessageOptions
0, // 252: temporal.server.api.historyservice.v1.routing:type_name -> temporal.server.api.historyservice.v1.RoutingOptions
253, // [253:253] is the sub-list for method output_type
253, // [253:253] is the sub-list for method input_type
252, // [252:253] is the sub-list for extension type_name
251, // [251:252] is the sub-list for extension extendee
0, // [0:251] is the sub-list for field type_name
189, // 30: temporal.server.api.historyservice.v1.GetMutableStateResponse.transient_or_speculative_tasks:type_name -> temporal.server.api.history.v1.TransientWorkflowTaskInfo
181, // 31: temporal.server.api.historyservice.v1.PollMutableStateRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
182, // 32: temporal.server.api.historyservice.v1.PollMutableStateRequest.version_history_item:type_name -> temporal.server.api.history.v1.VersionHistoryItem
181, // 33: temporal.server.api.historyservice.v1.PollMutableStateResponse.execution:type_name -> temporal.api.common.v1.WorkflowExecution
184, // 34: temporal.server.api.historyservice.v1.PollMutableStateResponse.workflow_type:type_name -> temporal.api.common.v1.WorkflowType
185, // 35: temporal.server.api.historyservice.v1.PollMutableStateResponse.task_queue:type_name -> temporal.api.taskqueue.v1.TaskQueue
185, // 36: temporal.server.api.historyservice.v1.PollMutableStateResponse.sticky_task_queue:type_name -> temporal.api.taskqueue.v1.TaskQueue
171, // 37: temporal.server.api.historyservice.v1.PollMutableStateResponse.sticky_task_queue_schedule_to_start_timeout:type_name -> google.protobuf.Duration
187, // 38: temporal.server.api.historyservice.v1.PollMutableStateResponse.version_histories:type_name -> temporal.server.api.history.v1.VersionHistories
186, // 39: temporal.server.api.historyservice.v1.PollMutableStateResponse.workflow_state:type_name -> temporal.server.api.enums.v1.WorkflowExecutionState
179, // 40: temporal.server.api.historyservice.v1.PollMutableStateResponse.workflow_status:type_name -> temporal.api.enums.v1.WorkflowExecutionStatus
181, // 41: temporal.server.api.historyservice.v1.ResetStickyTaskQueueRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
156, // 42: temporal.server.api.historyservice.v1.ExecuteMultiOperationRequest.operations:type_name -> temporal.server.api.historyservice.v1.ExecuteMultiOperationRequest.Operation
157, // 43: temporal.server.api.historyservice.v1.ExecuteMultiOperationResponse.responses:type_name -> temporal.server.api.historyservice.v1.ExecuteMultiOperationResponse.Response
181, // 44: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedRequest.workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
190, // 45: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedRequest.poll_request:type_name -> temporal.api.workflowservice.v1.PollWorkflowTaskQueueRequest
177, // 46: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedRequest.clock:type_name -> temporal.server.api.clock.v1.VectorClock
191, // 47: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedRequest.build_id_redirect_info:type_name -> temporal.server.api.taskqueue.v1.BuildIdRedirectInfo
192, // 48: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedRequest.scheduled_deployment:type_name -> temporal.api.deployment.v1.Deployment
193, // 49: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedRequest.version_directive:type_name -> temporal.server.api.taskqueue.v1.TaskVersionDirective
175, // 50: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedRequest.target_deployment_version:type_name -> temporal.api.deployment.v1.WorkerDeploymentVersion
184, // 51: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.workflow_type:type_name -> temporal.api.common.v1.WorkflowType
189, // 52: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.transient_workflow_task:type_name -> temporal.server.api.history.v1.TransientWorkflowTaskInfo
185, // 53: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.workflow_execution_task_queue:type_name -> temporal.api.taskqueue.v1.TaskQueue
167, // 54: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.scheduled_time:type_name -> google.protobuf.Timestamp
167, // 55: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.started_time:type_name -> google.protobuf.Timestamp
158, // 56: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.queries:type_name -> temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.QueriesEntry
177, // 57: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.clock:type_name -> temporal.server.api.clock.v1.VectorClock
194, // 58: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.messages:type_name -> temporal.api.protocol.v1.Message
195, // 59: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.history:type_name -> temporal.api.history.v1.History
195, // 60: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.raw_history:type_name -> temporal.api.history.v1.History
184, // 61: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.workflow_type:type_name -> temporal.api.common.v1.WorkflowType
189, // 62: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.transient_workflow_task:type_name -> temporal.server.api.history.v1.TransientWorkflowTaskInfo
185, // 63: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.workflow_execution_task_queue:type_name -> temporal.api.taskqueue.v1.TaskQueue
167, // 64: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.scheduled_time:type_name -> google.protobuf.Timestamp
167, // 65: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.started_time:type_name -> google.protobuf.Timestamp
159, // 66: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.queries:type_name -> temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.QueriesEntry
177, // 67: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.clock:type_name -> temporal.server.api.clock.v1.VectorClock
194, // 68: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.messages:type_name -> temporal.api.protocol.v1.Message
195, // 69: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.history:type_name -> temporal.api.history.v1.History
181, // 70: temporal.server.api.historyservice.v1.RecordActivityTaskStartedRequest.workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
196, // 71: temporal.server.api.historyservice.v1.RecordActivityTaskStartedRequest.poll_request:type_name -> temporal.api.workflowservice.v1.PollActivityTaskQueueRequest
177, // 72: temporal.server.api.historyservice.v1.RecordActivityTaskStartedRequest.clock:type_name -> temporal.server.api.clock.v1.VectorClock
191, // 73: temporal.server.api.historyservice.v1.RecordActivityTaskStartedRequest.build_id_redirect_info:type_name -> temporal.server.api.taskqueue.v1.BuildIdRedirectInfo
192, // 74: temporal.server.api.historyservice.v1.RecordActivityTaskStartedRequest.scheduled_deployment:type_name -> temporal.api.deployment.v1.Deployment
193, // 75: temporal.server.api.historyservice.v1.RecordActivityTaskStartedRequest.version_directive:type_name -> temporal.server.api.taskqueue.v1.TaskVersionDirective
197, // 76: temporal.server.api.historyservice.v1.RecordActivityTaskStartedResponse.scheduled_event:type_name -> temporal.api.history.v1.HistoryEvent
167, // 77: temporal.server.api.historyservice.v1.RecordActivityTaskStartedResponse.started_time:type_name -> google.protobuf.Timestamp
167, // 78: temporal.server.api.historyservice.v1.RecordActivityTaskStartedResponse.current_attempt_scheduled_time:type_name -> google.protobuf.Timestamp
170, // 79: temporal.server.api.historyservice.v1.RecordActivityTaskStartedResponse.heartbeat_details:type_name -> temporal.api.common.v1.Payloads
184, // 80: temporal.server.api.historyservice.v1.RecordActivityTaskStartedResponse.workflow_type:type_name -> temporal.api.common.v1.WorkflowType
177, // 81: temporal.server.api.historyservice.v1.RecordActivityTaskStartedResponse.clock:type_name -> temporal.server.api.clock.v1.VectorClock
198, // 82: temporal.server.api.historyservice.v1.RecordActivityTaskStartedResponse.priority:type_name -> temporal.api.common.v1.Priority
199, // 83: temporal.server.api.historyservice.v1.RecordActivityTaskStartedResponse.retry_policy:type_name -> temporal.api.common.v1.RetryPolicy
200, // 84: temporal.server.api.historyservice.v1.RespondWorkflowTaskCompletedRequest.complete_request:type_name -> temporal.api.workflowservice.v1.RespondWorkflowTaskCompletedRequest
12, // 85: temporal.server.api.historyservice.v1.RespondWorkflowTaskCompletedResponse.started_response:type_name -> temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse
201, // 86: temporal.server.api.historyservice.v1.RespondWorkflowTaskCompletedResponse.activity_tasks:type_name -> temporal.api.workflowservice.v1.PollActivityTaskQueueResponse
178, // 87: temporal.server.api.historyservice.v1.RespondWorkflowTaskCompletedResponse.new_workflow_task:type_name -> temporal.api.workflowservice.v1.PollWorkflowTaskQueueResponse
202, // 88: temporal.server.api.historyservice.v1.RespondWorkflowTaskFailedRequest.failed_request:type_name -> temporal.api.workflowservice.v1.RespondWorkflowTaskFailedRequest
181, // 89: temporal.server.api.historyservice.v1.IsWorkflowTaskValidRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
177, // 90: temporal.server.api.historyservice.v1.IsWorkflowTaskValidRequest.clock:type_name -> temporal.server.api.clock.v1.VectorClock
203, // 91: temporal.server.api.historyservice.v1.RecordActivityTaskHeartbeatRequest.heartbeat_request:type_name -> temporal.api.workflowservice.v1.RecordActivityTaskHeartbeatRequest
204, // 92: temporal.server.api.historyservice.v1.RespondActivityTaskCompletedRequest.complete_request:type_name -> temporal.api.workflowservice.v1.RespondActivityTaskCompletedRequest
205, // 93: temporal.server.api.historyservice.v1.RespondActivityTaskFailedRequest.failed_request:type_name -> temporal.api.workflowservice.v1.RespondActivityTaskFailedRequest
206, // 94: temporal.server.api.historyservice.v1.RespondActivityTaskCanceledRequest.cancel_request:type_name -> temporal.api.workflowservice.v1.RespondActivityTaskCanceledRequest
181, // 95: temporal.server.api.historyservice.v1.IsActivityTaskValidRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
177, // 96: temporal.server.api.historyservice.v1.IsActivityTaskValidRequest.clock:type_name -> temporal.server.api.clock.v1.VectorClock
207, // 97: temporal.server.api.historyservice.v1.SignalWorkflowExecutionRequest.signal_request:type_name -> temporal.api.workflowservice.v1.SignalWorkflowExecutionRequest
181, // 98: temporal.server.api.historyservice.v1.SignalWorkflowExecutionRequest.external_workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
208, // 99: temporal.server.api.historyservice.v1.SignalWithStartWorkflowExecutionRequest.signal_with_start_request:type_name -> temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest
181, // 100: temporal.server.api.historyservice.v1.RemoveSignalMutableStateRequest.workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
209, // 101: temporal.server.api.historyservice.v1.TerminateWorkflowExecutionRequest.terminate_request:type_name -> temporal.api.workflowservice.v1.TerminateWorkflowExecutionRequest
181, // 102: temporal.server.api.historyservice.v1.TerminateWorkflowExecutionRequest.external_workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
181, // 103: temporal.server.api.historyservice.v1.DeleteWorkflowExecutionRequest.workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
210, // 104: temporal.server.api.historyservice.v1.ResetWorkflowExecutionRequest.reset_request:type_name -> temporal.api.workflowservice.v1.ResetWorkflowExecutionRequest
211, // 105: temporal.server.api.historyservice.v1.RequestCancelWorkflowExecutionRequest.cancel_request:type_name -> temporal.api.workflowservice.v1.RequestCancelWorkflowExecutionRequest
181, // 106: temporal.server.api.historyservice.v1.RequestCancelWorkflowExecutionRequest.external_workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
181, // 107: temporal.server.api.historyservice.v1.ScheduleWorkflowTaskRequest.workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
177, // 108: temporal.server.api.historyservice.v1.ScheduleWorkflowTaskRequest.child_clock:type_name -> temporal.server.api.clock.v1.VectorClock
177, // 109: temporal.server.api.historyservice.v1.ScheduleWorkflowTaskRequest.parent_clock:type_name -> temporal.server.api.clock.v1.VectorClock
181, // 110: temporal.server.api.historyservice.v1.VerifyFirstWorkflowTaskScheduledRequest.workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
177, // 111: temporal.server.api.historyservice.v1.VerifyFirstWorkflowTaskScheduledRequest.clock:type_name -> temporal.server.api.clock.v1.VectorClock
181, // 112: temporal.server.api.historyservice.v1.RecordChildExecutionCompletedRequest.parent_execution:type_name -> temporal.api.common.v1.WorkflowExecution
181, // 113: temporal.server.api.historyservice.v1.RecordChildExecutionCompletedRequest.child_execution:type_name -> temporal.api.common.v1.WorkflowExecution
197, // 114: temporal.server.api.historyservice.v1.RecordChildExecutionCompletedRequest.completion_event:type_name -> temporal.api.history.v1.HistoryEvent
177, // 115: temporal.server.api.historyservice.v1.RecordChildExecutionCompletedRequest.clock:type_name -> temporal.server.api.clock.v1.VectorClock
181, // 116: temporal.server.api.historyservice.v1.VerifyChildExecutionCompletionRecordedRequest.parent_execution:type_name -> temporal.api.common.v1.WorkflowExecution
181, // 117: temporal.server.api.historyservice.v1.VerifyChildExecutionCompletionRecordedRequest.child_execution:type_name -> temporal.api.common.v1.WorkflowExecution
177, // 118: temporal.server.api.historyservice.v1.VerifyChildExecutionCompletionRecordedRequest.clock:type_name -> temporal.server.api.clock.v1.VectorClock
212, // 119: temporal.server.api.historyservice.v1.DescribeWorkflowExecutionRequest.request:type_name -> temporal.api.workflowservice.v1.DescribeWorkflowExecutionRequest
213, // 120: temporal.server.api.historyservice.v1.DescribeWorkflowExecutionResponse.execution_config:type_name -> temporal.api.workflow.v1.WorkflowExecutionConfig
214, // 121: temporal.server.api.historyservice.v1.DescribeWorkflowExecutionResponse.workflow_execution_info:type_name -> temporal.api.workflow.v1.WorkflowExecutionInfo
215, // 122: temporal.server.api.historyservice.v1.DescribeWorkflowExecutionResponse.pending_activities:type_name -> temporal.api.workflow.v1.PendingActivityInfo
216, // 123: temporal.server.api.historyservice.v1.DescribeWorkflowExecutionResponse.pending_children:type_name -> temporal.api.workflow.v1.PendingChildExecutionInfo
217, // 124: temporal.server.api.historyservice.v1.DescribeWorkflowExecutionResponse.pending_workflow_task:type_name -> temporal.api.workflow.v1.PendingWorkflowTaskInfo
218, // 125: temporal.server.api.historyservice.v1.DescribeWorkflowExecutionResponse.callbacks:type_name -> temporal.api.workflow.v1.CallbackInfo
219, // 126: temporal.server.api.historyservice.v1.DescribeWorkflowExecutionResponse.pending_nexus_operations:type_name -> temporal.api.workflow.v1.PendingNexusOperationInfo
220, // 127: temporal.server.api.historyservice.v1.DescribeWorkflowExecutionResponse.workflow_extended_info:type_name -> temporal.api.workflow.v1.WorkflowExecutionExtendedInfo
181, // 128: temporal.server.api.historyservice.v1.ReplicateEventsV2Request.workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
182, // 129: temporal.server.api.historyservice.v1.ReplicateEventsV2Request.version_history_items:type_name -> temporal.server.api.history.v1.VersionHistoryItem
221, // 130: temporal.server.api.historyservice.v1.ReplicateEventsV2Request.events:type_name -> temporal.api.common.v1.DataBlob
221, // 131: temporal.server.api.historyservice.v1.ReplicateEventsV2Request.new_run_events:type_name -> temporal.api.common.v1.DataBlob
222, // 132: temporal.server.api.historyservice.v1.ReplicateEventsV2Request.base_execution_info:type_name -> temporal.server.api.workflow.v1.BaseExecutionInfo
223, // 133: temporal.server.api.historyservice.v1.ReplicateWorkflowStateRequest.workflow_state:type_name -> temporal.server.api.persistence.v1.WorkflowMutableState
167, // 134: temporal.server.api.historyservice.v1.SyncShardStatusRequest.status_time:type_name -> google.protobuf.Timestamp
167, // 135: temporal.server.api.historyservice.v1.SyncActivityRequest.scheduled_time:type_name -> google.protobuf.Timestamp
167, // 136: temporal.server.api.historyservice.v1.SyncActivityRequest.started_time:type_name -> google.protobuf.Timestamp
167, // 137: temporal.server.api.historyservice.v1.SyncActivityRequest.last_heartbeat_time:type_name -> google.protobuf.Timestamp
170, // 138: temporal.server.api.historyservice.v1.SyncActivityRequest.details:type_name -> temporal.api.common.v1.Payloads
169, // 139: temporal.server.api.historyservice.v1.SyncActivityRequest.last_failure:type_name -> temporal.api.failure.v1.Failure
224, // 140: temporal.server.api.historyservice.v1.SyncActivityRequest.version_history:type_name -> temporal.server.api.history.v1.VersionHistory
222, // 141: temporal.server.api.historyservice.v1.SyncActivityRequest.base_execution_info:type_name -> temporal.server.api.workflow.v1.BaseExecutionInfo
167, // 142: temporal.server.api.historyservice.v1.SyncActivityRequest.first_scheduled_time:type_name -> google.protobuf.Timestamp
167, // 143: temporal.server.api.historyservice.v1.SyncActivityRequest.last_attempt_complete_time:type_name -> google.protobuf.Timestamp
171, // 144: temporal.server.api.historyservice.v1.SyncActivityRequest.retry_initial_interval:type_name -> google.protobuf.Duration
171, // 145: temporal.server.api.historyservice.v1.SyncActivityRequest.retry_maximum_interval:type_name -> google.protobuf.Duration
64, // 146: temporal.server.api.historyservice.v1.SyncActivitiesRequest.activities_info:type_name -> temporal.server.api.historyservice.v1.ActivitySyncInfo
167, // 147: temporal.server.api.historyservice.v1.ActivitySyncInfo.scheduled_time:type_name -> google.protobuf.Timestamp
167, // 148: temporal.server.api.historyservice.v1.ActivitySyncInfo.started_time:type_name -> google.protobuf.Timestamp
167, // 149: temporal.server.api.historyservice.v1.ActivitySyncInfo.last_heartbeat_time:type_name -> google.protobuf.Timestamp
170, // 150: temporal.server.api.historyservice.v1.ActivitySyncInfo.details:type_name -> temporal.api.common.v1.Payloads
169, // 151: temporal.server.api.historyservice.v1.ActivitySyncInfo.last_failure:type_name -> temporal.api.failure.v1.Failure
224, // 152: temporal.server.api.historyservice.v1.ActivitySyncInfo.version_history:type_name -> temporal.server.api.history.v1.VersionHistory
167, // 153: temporal.server.api.historyservice.v1.ActivitySyncInfo.first_scheduled_time:type_name -> google.protobuf.Timestamp
167, // 154: temporal.server.api.historyservice.v1.ActivitySyncInfo.last_attempt_complete_time:type_name -> google.protobuf.Timestamp
171, // 155: temporal.server.api.historyservice.v1.ActivitySyncInfo.retry_initial_interval:type_name -> google.protobuf.Duration
171, // 156: temporal.server.api.historyservice.v1.ActivitySyncInfo.retry_maximum_interval:type_name -> google.protobuf.Duration
181, // 157: temporal.server.api.historyservice.v1.DescribeMutableStateRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
223, // 158: temporal.server.api.historyservice.v1.DescribeMutableStateResponse.cache_mutable_state:type_name -> temporal.server.api.persistence.v1.WorkflowMutableState
223, // 159: temporal.server.api.historyservice.v1.DescribeMutableStateResponse.database_mutable_state:type_name -> temporal.server.api.persistence.v1.WorkflowMutableState
181, // 160: temporal.server.api.historyservice.v1.DescribeHistoryHostRequest.workflow_execution:type_name -> temporal.api.common.v1.WorkflowExecution
225, // 161: temporal.server.api.historyservice.v1.DescribeHistoryHostResponse.namespace_cache:type_name -> temporal.server.api.namespace.v1.NamespaceCacheInfo
226, // 162: temporal.server.api.historyservice.v1.GetShardResponse.shard_info:type_name -> temporal.server.api.persistence.v1.ShardInfo
167, // 163: temporal.server.api.historyservice.v1.RemoveTaskRequest.visibility_time:type_name -> google.protobuf.Timestamp
227, // 164: temporal.server.api.historyservice.v1.GetReplicationMessagesRequest.tokens:type_name -> temporal.server.api.replication.v1.ReplicationToken
160, // 165: temporal.server.api.historyservice.v1.GetReplicationMessagesResponse.shard_messages:type_name -> temporal.server.api.historyservice.v1.GetReplicationMessagesResponse.ShardMessagesEntry
228, // 166: temporal.server.api.historyservice.v1.GetDLQReplicationMessagesRequest.task_infos:type_name -> temporal.server.api.replication.v1.ReplicationTaskInfo
229, // 167: temporal.server.api.historyservice.v1.GetDLQReplicationMessagesResponse.replication_tasks:type_name -> temporal.server.api.replication.v1.ReplicationTask
230, // 168: temporal.server.api.historyservice.v1.QueryWorkflowRequest.request:type_name -> temporal.api.workflowservice.v1.QueryWorkflowRequest
231, // 169: temporal.server.api.historyservice.v1.QueryWorkflowResponse.response:type_name -> temporal.api.workflowservice.v1.QueryWorkflowResponse
232, // 170: temporal.server.api.historyservice.v1.ReapplyEventsRequest.request:type_name -> temporal.server.api.adminservice.v1.ReapplyEventsRequest
233, // 171: temporal.server.api.historyservice.v1.GetDLQMessagesRequest.type:type_name -> temporal.server.api.enums.v1.DeadLetterQueueType
233, // 172: temporal.server.api.historyservice.v1.GetDLQMessagesResponse.type:type_name -> temporal.server.api.enums.v1.DeadLetterQueueType
229, // 173: temporal.server.api.historyservice.v1.GetDLQMessagesResponse.replication_tasks:type_name -> temporal.server.api.replication.v1.ReplicationTask
228, // 174: temporal.server.api.historyservice.v1.GetDLQMessagesResponse.replication_tasks_info:type_name -> temporal.server.api.replication.v1.ReplicationTaskInfo
233, // 175: temporal.server.api.historyservice.v1.PurgeDLQMessagesRequest.type:type_name -> temporal.server.api.enums.v1.DeadLetterQueueType
233, // 176: temporal.server.api.historyservice.v1.MergeDLQMessagesRequest.type:type_name -> temporal.server.api.enums.v1.DeadLetterQueueType
234, // 177: temporal.server.api.historyservice.v1.RefreshWorkflowTasksRequest.request:type_name -> temporal.server.api.adminservice.v1.RefreshWorkflowTasksRequest
181, // 178: temporal.server.api.historyservice.v1.GenerateLastHistoryReplicationTasksRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
96, // 179: temporal.server.api.historyservice.v1.GetReplicationStatusResponse.shards:type_name -> temporal.server.api.historyservice.v1.ShardReplicationStatus
167, // 180: temporal.server.api.historyservice.v1.ShardReplicationStatus.shard_local_time:type_name -> google.protobuf.Timestamp
161, // 181: temporal.server.api.historyservice.v1.ShardReplicationStatus.remote_clusters:type_name -> temporal.server.api.historyservice.v1.ShardReplicationStatus.RemoteClustersEntry
162, // 182: temporal.server.api.historyservice.v1.ShardReplicationStatus.handover_namespaces:type_name -> temporal.server.api.historyservice.v1.ShardReplicationStatus.HandoverNamespacesEntry
167, // 183: temporal.server.api.historyservice.v1.ShardReplicationStatus.max_replication_task_visibility_time:type_name -> google.protobuf.Timestamp
167, // 184: temporal.server.api.historyservice.v1.ShardReplicationStatusPerCluster.acked_task_visibility_time:type_name -> google.protobuf.Timestamp
181, // 185: temporal.server.api.historyservice.v1.RebuildMutableStateRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
181, // 186: temporal.server.api.historyservice.v1.ImportWorkflowExecutionRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
221, // 187: temporal.server.api.historyservice.v1.ImportWorkflowExecutionRequest.history_batches:type_name -> temporal.api.common.v1.DataBlob
224, // 188: temporal.server.api.historyservice.v1.ImportWorkflowExecutionRequest.version_history:type_name -> temporal.server.api.history.v1.VersionHistory
181, // 189: temporal.server.api.historyservice.v1.DeleteWorkflowVisibilityRecordRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
167, // 190: temporal.server.api.historyservice.v1.DeleteWorkflowVisibilityRecordRequest.workflow_start_time:type_name -> google.protobuf.Timestamp
167, // 191: temporal.server.api.historyservice.v1.DeleteWorkflowVisibilityRecordRequest.workflow_close_time:type_name -> google.protobuf.Timestamp
235, // 192: temporal.server.api.historyservice.v1.UpdateWorkflowExecutionRequest.request:type_name -> temporal.api.workflowservice.v1.UpdateWorkflowExecutionRequest
236, // 193: temporal.server.api.historyservice.v1.UpdateWorkflowExecutionResponse.response:type_name -> temporal.api.workflowservice.v1.UpdateWorkflowExecutionResponse
237, // 194: temporal.server.api.historyservice.v1.StreamWorkflowReplicationMessagesRequest.sync_replication_state:type_name -> temporal.server.api.replication.v1.SyncReplicationState
238, // 195: temporal.server.api.historyservice.v1.StreamWorkflowReplicationMessagesResponse.messages:type_name -> temporal.server.api.replication.v1.WorkflowReplicationMessages
239, // 196: temporal.server.api.historyservice.v1.PollWorkflowExecutionUpdateRequest.request:type_name -> temporal.api.workflowservice.v1.PollWorkflowExecutionUpdateRequest
240, // 197: temporal.server.api.historyservice.v1.PollWorkflowExecutionUpdateResponse.response:type_name -> temporal.api.workflowservice.v1.PollWorkflowExecutionUpdateResponse
241, // 198: temporal.server.api.historyservice.v1.GetWorkflowExecutionHistoryRequest.request:type_name -> temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryRequest
242, // 199: temporal.server.api.historyservice.v1.GetWorkflowExecutionHistoryResponse.response:type_name -> temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryResponse
195, // 200: temporal.server.api.historyservice.v1.GetWorkflowExecutionHistoryResponse.history:type_name -> temporal.api.history.v1.History
242, // 201: temporal.server.api.historyservice.v1.GetWorkflowExecutionHistoryResponseWithRaw.response:type_name -> temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryResponse
243, // 202: temporal.server.api.historyservice.v1.GetWorkflowExecutionHistoryReverseRequest.request:type_name -> temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryReverseRequest
244, // 203: temporal.server.api.historyservice.v1.GetWorkflowExecutionHistoryReverseResponse.response:type_name -> temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryReverseResponse
245, // 204: temporal.server.api.historyservice.v1.GetWorkflowExecutionRawHistoryV2Request.request:type_name -> temporal.server.api.adminservice.v1.GetWorkflowExecutionRawHistoryV2Request
246, // 205: temporal.server.api.historyservice.v1.GetWorkflowExecutionRawHistoryV2Response.response:type_name -> temporal.server.api.adminservice.v1.GetWorkflowExecutionRawHistoryV2Response
247, // 206: temporal.server.api.historyservice.v1.GetWorkflowExecutionRawHistoryRequest.request:type_name -> temporal.server.api.adminservice.v1.GetWorkflowExecutionRawHistoryRequest
248, // 207: temporal.server.api.historyservice.v1.GetWorkflowExecutionRawHistoryResponse.response:type_name -> temporal.server.api.adminservice.v1.GetWorkflowExecutionRawHistoryResponse
249, // 208: temporal.server.api.historyservice.v1.ForceDeleteWorkflowExecutionRequest.request:type_name -> temporal.server.api.adminservice.v1.DeleteWorkflowExecutionRequest
250, // 209: temporal.server.api.historyservice.v1.ForceDeleteWorkflowExecutionResponse.response:type_name -> temporal.server.api.adminservice.v1.DeleteWorkflowExecutionResponse
251, // 210: temporal.server.api.historyservice.v1.GetDLQTasksRequest.dlq_key:type_name -> temporal.server.api.common.v1.HistoryDLQKey
252, // 211: temporal.server.api.historyservice.v1.GetDLQTasksResponse.dlq_tasks:type_name -> temporal.server.api.common.v1.HistoryDLQTask
251, // 212: temporal.server.api.historyservice.v1.DeleteDLQTasksRequest.dlq_key:type_name -> temporal.server.api.common.v1.HistoryDLQKey
253, // 213: temporal.server.api.historyservice.v1.DeleteDLQTasksRequest.inclusive_max_task_metadata:type_name -> temporal.server.api.common.v1.HistoryDLQTaskMetadata
163, // 214: temporal.server.api.historyservice.v1.ListQueuesResponse.queues:type_name -> temporal.server.api.historyservice.v1.ListQueuesResponse.QueueInfo
164, // 215: temporal.server.api.historyservice.v1.AddTasksRequest.tasks:type_name -> temporal.server.api.historyservice.v1.AddTasksRequest.Task
254, // 216: temporal.server.api.historyservice.v1.ListTasksRequest.request:type_name -> temporal.server.api.adminservice.v1.ListHistoryTasksRequest
255, // 217: temporal.server.api.historyservice.v1.ListTasksResponse.response:type_name -> temporal.server.api.adminservice.v1.ListHistoryTasksResponse
256, // 218: temporal.server.api.historyservice.v1.CompleteNexusOperationChasmRequest.completion:type_name -> temporal.server.api.token.v1.NexusOperationCompletion
257, // 219: temporal.server.api.historyservice.v1.CompleteNexusOperationChasmRequest.success:type_name -> temporal.api.common.v1.Payload
169, // 220: temporal.server.api.historyservice.v1.CompleteNexusOperationChasmRequest.failure:type_name -> temporal.api.failure.v1.Failure
167, // 221: temporal.server.api.historyservice.v1.CompleteNexusOperationChasmRequest.close_time:type_name -> google.protobuf.Timestamp
256, // 222: temporal.server.api.historyservice.v1.CompleteNexusOperationRequest.completion:type_name -> temporal.server.api.token.v1.NexusOperationCompletion
257, // 223: temporal.server.api.historyservice.v1.CompleteNexusOperationRequest.success:type_name -> temporal.api.common.v1.Payload
258, // 224: temporal.server.api.historyservice.v1.CompleteNexusOperationRequest.failure:type_name -> temporal.api.nexus.v1.Failure
167, // 225: temporal.server.api.historyservice.v1.CompleteNexusOperationRequest.start_time:type_name -> google.protobuf.Timestamp
180, // 226: temporal.server.api.historyservice.v1.CompleteNexusOperationRequest.links:type_name -> temporal.api.common.v1.Link
259, // 227: temporal.server.api.historyservice.v1.InvokeStateMachineMethodRequest.ref:type_name -> temporal.server.api.persistence.v1.StateMachineRef
260, // 228: temporal.server.api.historyservice.v1.DeepHealthCheckResponse.state:type_name -> temporal.server.api.enums.v1.HealthState
181, // 229: temporal.server.api.historyservice.v1.SyncWorkflowStateRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
183, // 230: temporal.server.api.historyservice.v1.SyncWorkflowStateRequest.versioned_transition:type_name -> temporal.server.api.persistence.v1.VersionedTransition
187, // 231: temporal.server.api.historyservice.v1.SyncWorkflowStateRequest.version_histories:type_name -> temporal.server.api.history.v1.VersionHistories
261, // 232: temporal.server.api.historyservice.v1.SyncWorkflowStateResponse.versioned_transition_artifact:type_name -> temporal.server.api.replication.v1.VersionedTransitionArtifact
262, // 233: temporal.server.api.historyservice.v1.UpdateActivityOptionsRequest.update_request:type_name -> temporal.api.workflowservice.v1.UpdateActivityOptionsRequest
263, // 234: temporal.server.api.historyservice.v1.UpdateActivityOptionsResponse.activity_options:type_name -> temporal.api.activity.v1.ActivityOptions
264, // 235: temporal.server.api.historyservice.v1.PauseActivityRequest.frontend_request:type_name -> temporal.api.workflowservice.v1.PauseActivityRequest
265, // 236: temporal.server.api.historyservice.v1.UnpauseActivityRequest.frontend_request:type_name -> temporal.api.workflowservice.v1.UnpauseActivityRequest
266, // 237: temporal.server.api.historyservice.v1.ResetActivityRequest.frontend_request:type_name -> temporal.api.workflowservice.v1.ResetActivityRequest
267, // 238: temporal.server.api.historyservice.v1.UpdateWorkflowExecutionOptionsRequest.update_request:type_name -> temporal.api.workflowservice.v1.UpdateWorkflowExecutionOptionsRequest
268, // 239: temporal.server.api.historyservice.v1.UpdateWorkflowExecutionOptionsResponse.workflow_execution_options:type_name -> temporal.api.workflow.v1.WorkflowExecutionOptions
269, // 240: temporal.server.api.historyservice.v1.PauseWorkflowExecutionRequest.pause_request:type_name -> temporal.api.workflowservice.v1.PauseWorkflowExecutionRequest
270, // 241: temporal.server.api.historyservice.v1.UnpauseWorkflowExecutionRequest.unpause_request:type_name -> temporal.api.workflowservice.v1.UnpauseWorkflowExecutionRequest
1, // 242: temporal.server.api.historyservice.v1.ExecuteMultiOperationRequest.Operation.start_workflow:type_name -> temporal.server.api.historyservice.v1.StartWorkflowExecutionRequest
105, // 243: temporal.server.api.historyservice.v1.ExecuteMultiOperationRequest.Operation.update_workflow:type_name -> temporal.server.api.historyservice.v1.UpdateWorkflowExecutionRequest
2, // 244: temporal.server.api.historyservice.v1.ExecuteMultiOperationResponse.Response.start_workflow:type_name -> temporal.server.api.historyservice.v1.StartWorkflowExecutionResponse
106, // 245: temporal.server.api.historyservice.v1.ExecuteMultiOperationResponse.Response.update_workflow:type_name -> temporal.server.api.historyservice.v1.UpdateWorkflowExecutionResponse
271, // 246: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponse.QueriesEntry.value:type_name -> temporal.api.query.v1.WorkflowQuery
271, // 247: temporal.server.api.historyservice.v1.RecordWorkflowTaskStartedResponseWithRawHistory.QueriesEntry.value:type_name -> temporal.api.query.v1.WorkflowQuery
272, // 248: temporal.server.api.historyservice.v1.GetReplicationMessagesResponse.ShardMessagesEntry.value:type_name -> temporal.server.api.replication.v1.ReplicationMessages
98, // 249: temporal.server.api.historyservice.v1.ShardReplicationStatus.RemoteClustersEntry.value:type_name -> temporal.server.api.historyservice.v1.ShardReplicationStatusPerCluster
97, // 250: temporal.server.api.historyservice.v1.ShardReplicationStatus.HandoverNamespacesEntry.value:type_name -> temporal.server.api.historyservice.v1.HandoverNamespaceInfo
221, // 251: temporal.server.api.historyservice.v1.AddTasksRequest.Task.blob:type_name -> temporal.api.common.v1.DataBlob
273, // 252: temporal.server.api.historyservice.v1.routing:extendee -> google.protobuf.MessageOptions
0, // 253: temporal.server.api.historyservice.v1.routing:type_name -> temporal.server.api.historyservice.v1.RoutingOptions
254, // [254:254] is the sub-list for method output_type
254, // [254:254] is the sub-list for method input_type
253, // [253:254] is the sub-list for extension type_name
252, // [252:253] is the sub-list for extension extendee
0, // [0:252] is the sub-list for field type_name
}
func init() { file_temporal_server_api_historyservice_v1_request_response_proto_init() }
+38 -49
View File
@@ -27,18 +27,17 @@ const (
)
type HistoryContinuation struct {
state protoimpl.MessageState `protogen:"open.v1"`
RunId string `protobuf:"bytes,1,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"`
FirstEventId int64 `protobuf:"varint,2,opt,name=first_event_id,json=firstEventId,proto3" json:"first_event_id,omitempty"`
NextEventId int64 `protobuf:"varint,3,opt,name=next_event_id,json=nextEventId,proto3" json:"next_event_id,omitempty"`
IsWorkflowRunning bool `protobuf:"varint,5,opt,name=is_workflow_running,json=isWorkflowRunning,proto3" json:"is_workflow_running,omitempty"`
PersistenceToken []byte `protobuf:"bytes,6,opt,name=persistence_token,json=persistenceToken,proto3" json:"persistence_token,omitempty"`
TransientWorkflowTask *v1.TransientWorkflowTaskInfo `protobuf:"bytes,7,opt,name=transient_workflow_task,json=transientWorkflowTask,proto3" json:"transient_workflow_task,omitempty"`
BranchToken []byte `protobuf:"bytes,8,opt,name=branch_token,json=branchToken,proto3" json:"branch_token,omitempty"`
VersionHistoryItem *v1.VersionHistoryItem `protobuf:"bytes,10,opt,name=version_history_item,json=versionHistoryItem,proto3" json:"version_history_item,omitempty"`
VersionedTransition *v11.VersionedTransition `protobuf:"bytes,11,opt,name=versioned_transition,json=versionedTransition,proto3" json:"versioned_transition,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
RunId string `protobuf:"bytes,1,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"`
FirstEventId int64 `protobuf:"varint,2,opt,name=first_event_id,json=firstEventId,proto3" json:"first_event_id,omitempty"`
NextEventId int64 `protobuf:"varint,3,opt,name=next_event_id,json=nextEventId,proto3" json:"next_event_id,omitempty"`
IsWorkflowRunning bool `protobuf:"varint,5,opt,name=is_workflow_running,json=isWorkflowRunning,proto3" json:"is_workflow_running,omitempty"`
PersistenceToken []byte `protobuf:"bytes,6,opt,name=persistence_token,json=persistenceToken,proto3" json:"persistence_token,omitempty"`
BranchToken []byte `protobuf:"bytes,8,opt,name=branch_token,json=branchToken,proto3" json:"branch_token,omitempty"`
VersionHistoryItem *v1.VersionHistoryItem `protobuf:"bytes,10,opt,name=version_history_item,json=versionHistoryItem,proto3" json:"version_history_item,omitempty"`
VersionedTransition *v11.VersionedTransition `protobuf:"bytes,11,opt,name=versioned_transition,json=versionedTransition,proto3" json:"versioned_transition,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HistoryContinuation) Reset() {
@@ -106,13 +105,6 @@ func (x *HistoryContinuation) GetPersistenceToken() []byte {
return nil
}
func (x *HistoryContinuation) GetTransientWorkflowTask() *v1.TransientWorkflowTaskInfo {
if x != nil {
return x.TransientWorkflowTask
}
return nil
}
func (x *HistoryContinuation) GetBranchToken() []byte {
if x != nil {
return x.BranchToken
@@ -663,18 +655,17 @@ var File_temporal_server_api_token_v1_message_proto protoreflect.FileDescriptor
const file_temporal_server_api_token_v1_message_proto_rawDesc = "" +
"\n" +
"*temporal/server/api/token/v1/message.proto\x12\x1ctemporal.server.api.token.v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a*temporal/server/api/clock/v1/message.proto\x1a,temporal/server/api/history/v1/message.proto\x1a,temporal/server/api/persistence/v1/hsm.proto\"\xc1\x04\n" +
"*temporal/server/api/token/v1/message.proto\x12\x1ctemporal.server.api.token.v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a*temporal/server/api/clock/v1/message.proto\x1a,temporal/server/api/history/v1/message.proto\x1a,temporal/server/api/persistence/v1/hsm.proto\"\xd4\x03\n" +
"\x13HistoryContinuation\x12\x15\n" +
"\x06run_id\x18\x01 \x01(\tR\x05runId\x12$\n" +
"\x0efirst_event_id\x18\x02 \x01(\x03R\ffirstEventId\x12\"\n" +
"\rnext_event_id\x18\x03 \x01(\x03R\vnextEventId\x12.\n" +
"\x13is_workflow_running\x18\x05 \x01(\bR\x11isWorkflowRunning\x12+\n" +
"\x11persistence_token\x18\x06 \x01(\fR\x10persistenceToken\x12q\n" +
"\x17transient_workflow_task\x18\a \x01(\v29.temporal.server.api.history.v1.TransientWorkflowTaskInfoR\x15transientWorkflowTask\x12!\n" +
"\x11persistence_token\x18\x06 \x01(\fR\x10persistenceToken\x12!\n" +
"\fbranch_token\x18\b \x01(\fR\vbranchToken\x12d\n" +
"\x14version_history_item\x18\n" +
" \x01(\v22.temporal.server.api.history.v1.VersionHistoryItemR\x12versionHistoryItem\x12j\n" +
"\x14versioned_transition\x18\v \x01(\v27.temporal.server.api.persistence.v1.VersionedTransitionR\x13versionedTransitionJ\x04\b\t\x10\n" +
"\x14versioned_transition\x18\v \x01(\v27.temporal.server.api.persistence.v1.VersionedTransitionR\x13versionedTransitionJ\x04\b\a\x10\bJ\x04\b\t\x10\n" +
"\"\xa9\x03\n" +
"\x16RawHistoryContinuation\x12!\n" +
"\fnamespace_id\x18\n" +
@@ -744,34 +735,32 @@ func file_temporal_server_api_token_v1_message_proto_rawDescGZIP() []byte {
var file_temporal_server_api_token_v1_message_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_temporal_server_api_token_v1_message_proto_goTypes = []any{
(*HistoryContinuation)(nil), // 0: temporal.server.api.token.v1.HistoryContinuation
(*RawHistoryContinuation)(nil), // 1: temporal.server.api.token.v1.RawHistoryContinuation
(*Task)(nil), // 2: temporal.server.api.token.v1.Task
(*QueryTask)(nil), // 3: temporal.server.api.token.v1.QueryTask
(*NexusTask)(nil), // 4: temporal.server.api.token.v1.NexusTask
(*HistoryEventRef)(nil), // 5: temporal.server.api.token.v1.HistoryEventRef
(*NexusOperationCompletion)(nil), // 6: temporal.server.api.token.v1.NexusOperationCompletion
(*v1.TransientWorkflowTaskInfo)(nil), // 7: temporal.server.api.history.v1.TransientWorkflowTaskInfo
(*v1.VersionHistoryItem)(nil), // 8: temporal.server.api.history.v1.VersionHistoryItem
(*v11.VersionedTransition)(nil), // 9: temporal.server.api.persistence.v1.VersionedTransition
(*v1.VersionHistories)(nil), // 10: temporal.server.api.history.v1.VersionHistories
(*v12.VectorClock)(nil), // 11: temporal.server.api.clock.v1.VectorClock
(*timestamppb.Timestamp)(nil), // 12: google.protobuf.Timestamp
(*v11.StateMachineRef)(nil), // 13: temporal.server.api.persistence.v1.StateMachineRef
(*HistoryContinuation)(nil), // 0: temporal.server.api.token.v1.HistoryContinuation
(*RawHistoryContinuation)(nil), // 1: temporal.server.api.token.v1.RawHistoryContinuation
(*Task)(nil), // 2: temporal.server.api.token.v1.Task
(*QueryTask)(nil), // 3: temporal.server.api.token.v1.QueryTask
(*NexusTask)(nil), // 4: temporal.server.api.token.v1.NexusTask
(*HistoryEventRef)(nil), // 5: temporal.server.api.token.v1.HistoryEventRef
(*NexusOperationCompletion)(nil), // 6: temporal.server.api.token.v1.NexusOperationCompletion
(*v1.VersionHistoryItem)(nil), // 7: temporal.server.api.history.v1.VersionHistoryItem
(*v11.VersionedTransition)(nil), // 8: temporal.server.api.persistence.v1.VersionedTransition
(*v1.VersionHistories)(nil), // 9: temporal.server.api.history.v1.VersionHistories
(*v12.VectorClock)(nil), // 10: temporal.server.api.clock.v1.VectorClock
(*timestamppb.Timestamp)(nil), // 11: google.protobuf.Timestamp
(*v11.StateMachineRef)(nil), // 12: temporal.server.api.persistence.v1.StateMachineRef
}
var file_temporal_server_api_token_v1_message_proto_depIdxs = []int32{
7, // 0: temporal.server.api.token.v1.HistoryContinuation.transient_workflow_task:type_name -> temporal.server.api.history.v1.TransientWorkflowTaskInfo
8, // 1: temporal.server.api.token.v1.HistoryContinuation.version_history_item:type_name -> temporal.server.api.history.v1.VersionHistoryItem
9, // 2: temporal.server.api.token.v1.HistoryContinuation.versioned_transition:type_name -> temporal.server.api.persistence.v1.VersionedTransition
10, // 3: temporal.server.api.token.v1.RawHistoryContinuation.version_histories:type_name -> temporal.server.api.history.v1.VersionHistories
11, // 4: temporal.server.api.token.v1.Task.clock:type_name -> temporal.server.api.clock.v1.VectorClock
12, // 5: temporal.server.api.token.v1.Task.started_time:type_name -> google.protobuf.Timestamp
13, // 6: temporal.server.api.token.v1.NexusOperationCompletion.ref:type_name -> temporal.server.api.persistence.v1.StateMachineRef
7, // [7:7] is the sub-list for method output_type
7, // [7:7] is the sub-list for method input_type
7, // [7:7] is the sub-list for extension type_name
7, // [7:7] is the sub-list for extension extendee
0, // [0:7] is the sub-list for field type_name
7, // 0: temporal.server.api.token.v1.HistoryContinuation.version_history_item:type_name -> temporal.server.api.history.v1.VersionHistoryItem
8, // 1: temporal.server.api.token.v1.HistoryContinuation.versioned_transition:type_name -> temporal.server.api.persistence.v1.VersionedTransition
9, // 2: temporal.server.api.token.v1.RawHistoryContinuation.version_histories:type_name -> temporal.server.api.history.v1.VersionHistories
10, // 3: temporal.server.api.token.v1.Task.clock:type_name -> temporal.server.api.clock.v1.VectorClock
11, // 4: temporal.server.api.token.v1.Task.started_time:type_name -> google.protobuf.Timestamp
12, // 5: temporal.server.api.token.v1.NexusOperationCompletion.ref:type_name -> temporal.server.api.persistence.v1.StateMachineRef
6, // [6:6] is the sub-list for method output_type
6, // [6:6] is the sub-list for method input_type
6, // [6:6] is the sub-list for extension type_name
6, // [6:6] is the sub-list for extension extendee
0, // [0:6] is the sub-list for field type_name
}
func init() { file_temporal_server_api_token_v1_message_proto_init() }
@@ -49,12 +49,14 @@ a special [in-memory-queue](./in-memory-queue.md) is used for speculative Workfl
> #### TODO
> It is important to point out that the `WorkflowTaskScheduled` and `WorkflowTaskStarted` events
> for transient and speculative Workflow Task are only added to the `PollWorkflowTask` response - and
> not to the `GetWorkflowExecutionHistory` response. This has an unfortunate consequence: when the
> not to the `GetWorkflowExecutionHistory` response. This has an unfortunate consequence: when the
> worker receives a speculative Workflow Task on a sticky task queue, but the Workflow is already
> evicted from its cache, it issues a `GetWorkflowExecutionHistory` request, which returns the
> history *without* speculative events. This leads to a `premature end of stream` error on the
> evicted from its cache, it issues a `GetWorkflowExecutionHistory` request, which returns the
> history *without* speculative events. This leads to a `premature end of stream` error on the
> worker side. The worker fails the Workflow Task, clears stickiness, and everything works fine
> after that - but a failed Workflow Task appears in the history. Fortunately, it doesn't happen often.
>
> See PR #9138 for related work on ensuring transient events are not incorrectly returned to CLI/UI clients.
## Speculative Workflow Task & Workflow Update
Speculative Workflow Task was introduced to make it possible for Workflow Update to have zero writes
@@ -154,6 +154,9 @@ message GetMutableStateResponse {
string inherited_build_id = 23;
repeated temporal.server.api.persistence.v1.VersionedTransition transition_history = 24;
temporal.api.workflow.v1.WorkflowExecutionVersioningInfo versioning_info = 25;
// Transient or speculative workflow task events which are not yet persisted in the history.
// These events should be appended to the history when it is returned to the worker.
temporal.server.api.history.v1.TransientWorkflowTaskInfo transient_or_speculative_tasks = 26;
}
message PollMutableStateRequest {
@@ -15,7 +15,7 @@ message HistoryContinuation {
int64 next_event_id = 3;
bool is_workflow_running = 5;
bytes persistence_token = 6;
temporal.server.api.history.v1.TransientWorkflowTaskInfo transient_workflow_task = 7;
reserved 7; // Was: transient_workflow_task - no longer passed through continuation token
bytes branch_token = 8;
reserved 9;
temporal.server.api.history.v1.VersionHistoryItem version_history_item = 10;
+108 -27
View File
@@ -40,6 +40,7 @@ func GetRawHistory(
token []byte,
transientWorkflowTaskInfo *historyspb.TransientWorkflowTaskInfo,
branchToken []byte,
isWorkflowRunning bool,
) (_ []*commonpb.DataBlob, _ []byte, retError error) {
defer func() {
var dataLossErr *serviceerror.DataLoss
@@ -115,24 +116,27 @@ func GetRawHistory(
metrics.HistorySize.With(metricsHandler).Record(int64(size))
if len(nextToken) == 0 && transientWorkflowTaskInfo != nil {
if err := validateTransientWorkflowTaskEvents(nextEventID, transientWorkflowTaskInfo); err != nil {
logger := shardContext.GetLogger()
metricsHandler := interceptor.GetMetricsHandlerFromContext(ctx, logger).WithTags(metrics.OperationTag(metrics.HistoryGetRawHistoryScope))
metrics.ServiceErrIncompleteHistoryCounter.With(metricsHandler).Record(1)
logger.Error("getHistory error",
tag.WorkflowNamespaceID(namespaceID.String()),
tag.WorkflowID(execution.GetWorkflowId()),
tag.WorkflowRunID(execution.GetRunId()),
tag.Error(err))
return nil, nil, err
}
if len(transientWorkflowTaskInfo.HistorySuffix) > 0 {
blob, err := shardContext.GetPayloadSerializer().SerializeEvents(transientWorkflowTaskInfo.HistorySuffix)
if err != nil {
return nil, nil, err
// Check if we should include transient/speculative events
if shouldIncludeTransientOrSpeculativeTasks(ctx, transientWorkflowTaskInfo, isWorkflowRunning) {
// Validate before appending
if err := ValidateTransientWorkflowTaskEvents(nextEventID, transientWorkflowTaskInfo); err != nil {
logger := shardContext.GetLogger()
metricsHandler := interceptor.GetMetricsHandlerFromContext(ctx, logger).WithTags(metrics.OperationTag(metrics.HistoryGetRawHistoryScope))
metrics.ServiceErrIncompleteHistoryCounter.With(metricsHandler).Record(1)
logger.Warn("Transient event validation failed, skipping events",
tag.WorkflowNamespaceID(namespaceID.String()),
tag.WorkflowID(execution.GetWorkflowId()),
tag.WorkflowRunID(execution.GetRunId()),
tag.Error(err))
} else {
if len(transientWorkflowTaskInfo.HistorySuffix) > 0 {
blob, err := shardContext.GetPayloadSerializer().SerializeEvents(transientWorkflowTaskInfo.HistorySuffix)
if err != nil {
return nil, nil, err
}
rawHistory = append(rawHistory, blob)
}
}
rawHistory = append(rawHistory, blob)
}
}
return rawHistory, nextToken, nil
@@ -151,6 +155,7 @@ func GetHistory(
transientWorkflowTaskInfo *historyspb.TransientWorkflowTaskInfo,
branchToken []byte,
persistenceVisibilityMgr manager.VisibilityManager,
isWorkflowRunning bool,
) (history *historypb.History, token []byte, retError error) {
defer func() {
var dataLossErr *serviceerror.DataLoss
@@ -227,16 +232,23 @@ func GetHistory(
tag.Error(err))
}
if len(nextPageToken) == 0 && transientWorkflowTaskInfo != nil {
if err := validateTransientWorkflowTaskEvents(nextEventID, transientWorkflowTaskInfo); err != nil {
metrics.ServiceErrIncompleteHistoryCounter.With(metricsHandler).Record(1)
logger.Error("getHistory error",
tag.WorkflowNamespaceID(namespaceID.String()),
tag.WorkflowID(execution.GetWorkflowId()),
tag.WorkflowRunID(execution.GetRunId()),
tag.Error(err))
// Check if we should include transient/speculative events
if shouldIncludeTransientOrSpeculativeTasks(ctx, transientWorkflowTaskInfo, isWorkflowRunning) {
// Validate before appending
if err := ValidateTransientWorkflowTaskEvents(nextEventID, transientWorkflowTaskInfo); err != nil {
metrics.ServiceErrIncompleteHistoryCounter.With(metricsHandler).Record(1)
logger.Warn("Transient event validation failed, skipping events",
tag.WorkflowNamespaceID(namespaceID.String()),
tag.WorkflowID(execution.GetWorkflowId()),
tag.WorkflowRunID(execution.GetRunId()),
tag.Error(err))
// Don't append events, but don't fail request
} else {
// Validation passed, append events
// Append the transient workflow task events once we are done enumerating everything from the events table
historyEvents = append(historyEvents, transientWorkflowTaskInfo.HistorySuffix...)
}
}
// Append the transient workflow task events once we are done enumerating everything from the events table
historyEvents = append(historyEvents, transientWorkflowTaskInfo.HistorySuffix...)
}
if err := ProcessOutgoingSearchAttributes(
@@ -378,7 +390,76 @@ func ProcessOutgoingSearchAttributes(
return nil
}
func validateTransientWorkflowTaskEvents(
// shouldIncludeTransientOrSpeculativeTasks determines if transient/speculative events should be included.
// This function is called only when on the last page of history pagination (nextToken is empty).
func shouldIncludeTransientOrSpeculativeTasks(
ctx context.Context,
tranOrSpecEvents *historyspb.TransientWorkflowTaskInfo,
isWorkflowRunning bool,
) bool {
return len(tranOrSpecEvents.GetHistorySuffix()) > 0 &&
clientSupportsTranOrSpecEvents(ctx) &&
isWorkflowRunning &&
areValidTransientOrSpecEvents(tranOrSpecEvents)
}
// areValidTransientOrSpecEvents validates that transient/speculative workflow task events
// are properly formed before including them in GetWorkflowExecutionHistory responses.
//
// Transient events represent workflow tasks that exist in mutable state but may not be
// persisted to the event history (e.g., retry attempts after task failure). Speculative
// events represent workflow tasks created for processing updates that may be rejected.
//
// Valid transient/speculative events must be:
// 1. A WorkflowTaskScheduled event (always required)
// 2. Optionally followed by a WorkflowTaskStarted event with consecutive event ID
//
// This validation ensures we only include well-formed workflow task events and prevents
// corruption of the history view returned to clients. Invalid events are silently dropped
// with a warning logged.
//
// Returns true if events are valid and should be included in history, false otherwise.
func areValidTransientOrSpecEvents(tranOrSpecEvents *historyspb.TransientWorkflowTaskInfo) bool {
events := tranOrSpecEvents.GetHistorySuffix()
if len(events) == 0 || len(events) > 2 {
return false
}
// First must be WFT_SCHEDULED
if events[0].GetEventType() != enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED {
return false
}
// If 2 events, second must be WFT_STARTED immediately after
if len(events) == 2 {
if events[1].GetEventType() != enumspb.EVENT_TYPE_WORKFLOW_TASK_STARTED {
return false
}
if events[1].GetEventId() != events[0].GetEventId()+1 {
return false
}
}
return true
}
// clientSupportsTranOrSpecEvents detects if client supports transient events
// Default to include transient events for clients, only CLI and UI are
// explicitly excluded for backward compatability
func clientSupportsTranOrSpecEvents(ctx context.Context) bool {
clientName, _ := headers.GetClientNameAndVersion(ctx)
switch clientName {
case headers.ClientNameCLI, headers.ClientNameUI:
return false
default:
return true
}
}
// ValidateTransientWorkflowTaskEvents validates that transient workflow task events have sequential event IDs
// starting from the given offset. Returns an error if any event ID doesn't match the expected sequence.
func ValidateTransientWorkflowTaskEvents(
eventIDOffset int64,
transientWorkflowTaskInfo *historyspb.TransientWorkflowTaskInfo,
) error {
@@ -0,0 +1,336 @@
package api
import (
"context"
"testing"
"github.com/stretchr/testify/require"
enumspb "go.temporal.io/api/enums/v1"
historypb "go.temporal.io/api/history/v1"
historyspb "go.temporal.io/server/api/history/v1"
"go.temporal.io/server/common/headers"
)
func TestShouldIncludeTransientOrSpeculativeTasks(t *testing.T) {
t.Parallel()
tests := []struct {
name string
clientName string
historySuffix []*historypb.HistoryEvent
isWorkflowRunning bool
expected bool
}{
{
name: "all conditions met",
clientName: headers.ClientNameGoSDK,
historySuffix: []*historypb.HistoryEvent{
{
EventId: 10,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED,
},
},
isWorkflowRunning: true,
expected: true,
},
{
name: "empty history suffix",
clientName: headers.ClientNameGoSDK,
historySuffix: []*historypb.HistoryEvent{},
isWorkflowRunning: true,
expected: false,
},
{
name: "nil history suffix",
clientName: headers.ClientNameGoSDK,
historySuffix: nil,
isWorkflowRunning: true,
expected: false,
},
{
name: "CLI client",
clientName: headers.ClientNameCLI,
historySuffix: []*historypb.HistoryEvent{
{
EventId: 10,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED,
},
},
isWorkflowRunning: true,
expected: false,
},
{
name: "UI client",
clientName: headers.ClientNameUI,
historySuffix: []*historypb.HistoryEvent{
{
EventId: 10,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED,
},
},
isWorkflowRunning: true,
expected: false,
},
{
name: "workflow not running",
clientName: headers.ClientNameGoSDK,
historySuffix: []*historypb.HistoryEvent{
{
EventId: 10,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED,
},
},
isWorkflowRunning: false,
expected: false,
},
{
name: "invalid events - first event not scheduled",
clientName: headers.ClientNameGoSDK,
historySuffix: []*historypb.HistoryEvent{
{
EventId: 10,
EventType: enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_STARTED,
},
},
isWorkflowRunning: true,
expected: false,
},
{
name: "two valid events",
clientName: headers.ClientNameGoSDK,
historySuffix: []*historypb.HistoryEvent{
{
EventId: 10,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED,
},
{
EventId: 11,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_STARTED,
},
},
isWorkflowRunning: true,
expected: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
r := require.New(t)
ctx := headers.SetVersionsForTests(context.Background(), "1.0.0", tt.clientName, "", "")
tranOrSpecEvents := &historyspb.TransientWorkflowTaskInfo{
HistorySuffix: tt.historySuffix,
}
result := shouldIncludeTransientOrSpeculativeTasks(ctx, tranOrSpecEvents, tt.isWorkflowRunning)
r.Equal(tt.expected, result)
})
}
}
func TestClientSupportsTranOrSpecTasks(t *testing.T) {
t.Parallel()
tests := []struct {
name string
clientName string
expected bool
}{
{
name: "CLI client returns false",
clientName: headers.ClientNameCLI,
expected: false,
},
{
name: "UI client returns false",
clientName: headers.ClientNameUI,
expected: false,
},
{
name: "Go SDK returns true",
clientName: headers.ClientNameGoSDK,
expected: true,
},
{
name: "Java SDK returns true",
clientName: headers.ClientNameJavaSDK,
expected: true,
},
{
name: "TypeScript SDK returns true",
clientName: headers.ClientNameTypeScriptSDK,
expected: true,
},
{
name: "Python SDK returns true",
clientName: headers.ClientNamePythonSDK,
expected: true,
},
{
name: "PHP SDK returns true",
clientName: headers.ClientNamePHPSDK,
expected: true,
},
{
name: "no client name returns true",
clientName: "",
expected: true,
},
{
name: "unknown client returns true",
clientName: "unknown-client",
expected: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
r := require.New(t)
ctx := headers.SetVersionsForTests(context.Background(), "1.0.0", tt.clientName, "", "")
result := clientSupportsTranOrSpecEvents(ctx)
r.Equal(tt.expected, result)
})
}
// Test empty context without any headers set
t.Run("empty context without headers returns true", func(t *testing.T) {
t.Parallel()
r := require.New(t)
ctx := context.Background()
result := clientSupportsTranOrSpecEvents(ctx)
r.True(result)
})
}
func TestAreValidTransientOrSpecTasks(t *testing.T) {
t.Parallel()
tests := []struct {
name string
historySuffix []*historypb.HistoryEvent
expected bool
}{
{
name: "single scheduled event",
historySuffix: []*historypb.HistoryEvent{
{
EventId: 10,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED,
},
},
expected: true,
},
{
name: "two events with consecutive IDs",
historySuffix: []*historypb.HistoryEvent{
{
EventId: 10,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED,
},
{
EventId: 11,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_STARTED,
},
},
expected: true,
},
{
name: "empty events",
historySuffix: []*historypb.HistoryEvent{},
expected: false,
},
{
name: "nil events",
historySuffix: nil,
expected: false,
},
{
name: "more than two events",
historySuffix: []*historypb.HistoryEvent{
{
EventId: 10,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED,
},
{
EventId: 11,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_STARTED,
},
{
EventId: 12,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_COMPLETED,
},
},
expected: false,
},
{
name: "first event not scheduled",
historySuffix: []*historypb.HistoryEvent{
{
EventId: 10,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_STARTED,
},
},
expected: false,
},
{
name: "second event not started",
historySuffix: []*historypb.HistoryEvent{
{
EventId: 10,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED,
},
{
EventId: 11,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_COMPLETED,
},
},
expected: false,
},
{
name: "non-consecutive event IDs",
historySuffix: []*historypb.HistoryEvent{
{
EventId: 10,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED,
},
{
EventId: 12,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_STARTED,
},
},
expected: false,
},
{
name: "same event IDs",
historySuffix: []*historypb.HistoryEvent{
{
EventId: 10,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED,
},
{
EventId: 10,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_STARTED,
},
},
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
r := require.New(t)
tranOrSpecEvents := &historyspb.TransientWorkflowTaskInfo{
HistorySuffix: tt.historySuffix,
}
result := areValidTransientOrSpecEvents(tranOrSpecEvents)
r.Equal(tt.expected, result)
})
}
}
+10
View File
@@ -9,6 +9,7 @@ import (
enumspb "go.temporal.io/api/enums/v1"
"go.temporal.io/api/serviceerror"
taskqueuepb "go.temporal.io/api/taskqueue/v1"
historyspb "go.temporal.io/server/api/history/v1"
"go.temporal.io/server/api/historyservice/v1"
persistencespb "go.temporal.io/server/api/persistence/v1"
"go.temporal.io/server/common"
@@ -373,6 +374,14 @@ func MutableStateToGetResponse(
}
}
// Get transient/speculative workflow task events if present
var transientOrSpeculativeTasks *historyspb.TransientWorkflowTaskInfo
if workflowTask := mutableState.GetPendingWorkflowTask(); workflowTask != nil {
transientOrSpeculativeTasks = mutableState.GetTransientWorkflowTaskInfo(workflowTask, "")
} else if workflowTask := mutableState.GetStartedWorkflowTask(); workflowTask != nil {
transientOrSpeculativeTasks = mutableState.GetTransientWorkflowTaskInfo(workflowTask, "")
}
return &historyservice.GetMutableStateResponse{
Execution: &commonpb.WorkflowExecution{
WorkflowId: mutableState.GetExecutionInfo().WorkflowId,
@@ -406,5 +415,6 @@ func MutableStateToGetResponse(
MostRecentWorkerVersionStamp: mostRecentWorkerVersionStamp,
TransitionHistory: transitionhistory.CopyVersionedTransitions(mutableState.GetExecutionInfo().TransitionHistory),
VersioningInfo: mutableState.GetExecutionInfo().VersioningInfo,
TransientOrSpeculativeTasks: transientOrSpeculativeTasks,
}, nil
}
@@ -29,6 +29,94 @@ import (
historyi "go.temporal.io/server/service/history/interfaces"
)
// appendTransientEvents queries mutable state for transient/speculative events and appends them to the response.
// This function attempts to use cached transient tasks from the initial mutable state call to avoid a second call.
// If cached tasks are nil or stale (validation fails), it falls back to querying mutable state.
// Validation of event IDs is handled by validateTransientWorkflowTaskEvents.
func appendTransientTasks(
ctx context.Context,
shardContext historyi.ShardContext,
workflowConsistencyChecker api.WorkflowConsistencyChecker,
eventNotifier events.Notifier,
namespaceID namespace.ID,
execution *commonpb.WorkflowExecution,
useRawHistory bool,
history *historypb.History,
historyBlob *[]*commonpb.DataBlob,
cachedTransientTasks *historyspb.TransientWorkflowTaskInfo,
nextEventID int64,
) {
// CLI and UI clients should not receive transient events for backward compatibility
// Check this FIRST before doing any work
clientName, _ := headers.GetClientNameAndVersion(ctx)
if clientName == headers.ClientNameCLI || clientName == headers.ClientNameUI {
return
}
var transientWorkflowTask *historyspb.TransientWorkflowTaskInfo
// Try cached tasks first
if cachedTransientTasks != nil {
// Validate cached tasks are still valid (not stale)
if err := api.ValidateTransientWorkflowTaskEvents(nextEventID, cachedTransientTasks); err == nil {
// Cache is valid, use it (FAST PATH - no second mutable state call)
transientWorkflowTask = cachedTransientTasks
} else {
// Cache is stale, log and fall through to refetch
shardContext.GetLogger().Warn("Cached transient tasks are stale, refetching",
tag.WorkflowNamespaceID(namespaceID.String()),
tag.WorkflowID(execution.GetWorkflowId()),
tag.WorkflowRunID(execution.GetRunId()),
tag.Error(err))
}
}
// Fallback: If no cache or cache is stale, make the query
if transientWorkflowTask == nil {
msResp, err := api.GetOrPollWorkflowMutableState(
ctx,
shardContext,
&historyservice.GetMutableStateRequest{
NamespaceId: namespaceID.String(),
Execution: execution,
},
workflowConsistencyChecker,
eventNotifier,
)
if err != nil || msResp.GetTransientOrSpeculativeTasks() == nil {
// Transient events don't exist or are already committed - this is OK
// Just return without appending (events are in persisted history)
if err != nil {
shardContext.GetLogger().Warn("Failed to refetch transient events",
tag.WorkflowNamespaceID(namespaceID.String()),
tag.WorkflowID(execution.GetWorkflowId()),
tag.WorkflowRunID(execution.GetRunId()),
tag.Error(err))
}
return
}
transientWorkflowTask = msResp.GetTransientOrSpeculativeTasks()
}
// Manually append transient events to the response
if useRawHistory {
transientEventsBlob, err := shardContext.GetPayloadSerializer().SerializeEvents(transientWorkflowTask.GetHistorySuffix())
if err == nil {
*historyBlob = append(*historyBlob, transientEventsBlob)
} else {
softassert.Fail(shardContext.GetLogger(), "GetWorkflowExecutionHistory could not serialize transient workflow tasks")
shardContext.GetLogger().Error("Failed to serialize transient workflow tasks",
tag.WorkflowNamespaceID(namespaceID.String()),
tag.WorkflowID(execution.GetWorkflowId()),
tag.WorkflowRunID(execution.GetRunId()),
tag.Error(err),
)
}
} else {
history.Events = append(history.Events, transientWorkflowTask.GetHistorySuffix()...)
}
}
func Invoke(
ctx context.Context,
shardContext historyi.ShardContext,
@@ -47,22 +135,24 @@ func Invoke(
isCloseEventOnly := request.Request.GetHistoryEventFilterType() == enumspb.HISTORY_EVENT_FILTER_TYPE_CLOSE_EVENT
// this function returns the following 7 things,
// 1. the current branch token (to use to retrieve history events)
// 2. the workflow run ID
// 3. the last first event ID (the event ID of the last batch of events in the history)
// 4. the last first event transaction id
// 5. the next event ID
// 6. whether the workflow is running
// 7. error if any
queryHistory := func(
queryMutableState := func(
namespaceUUID namespace.ID,
execution *commonpb.WorkflowExecution,
expectedNextEventID int64,
currentBranchToken []byte,
versionHistoryItem *historyspb.VersionHistoryItem,
versionedTransition *persistencespb.VersionedTransition,
) ([]byte, string, int64, int64, bool, *historyspb.VersionHistoryItem, *persistencespb.VersionedTransition, error) {
) (
[]byte, // current branch token (to use to retrieve history events)
string, // workflow run ID
int64, // last first event ID (the event ID of the last batch of events in the history)
int64, // last first event transaction id
bool, // whether the workflow is running
*historyspb.VersionHistoryItem, // version history item for the current branch
*persistencespb.VersionedTransition, // last versioned transition
*historyspb.TransientWorkflowTaskInfo, // transient workflow task info
error, // error if any
) {
response, err := api.GetOrPollWorkflowMutableState(
ctx,
shardContext,
@@ -103,17 +193,17 @@ func Invoke(
)
}
if err != nil {
return nil, "", 0, 0, false, nil, nil, err
return nil, "", 0, 0, false, nil, nil, nil, err
}
isWorkflowRunning := response.GetWorkflowStatus() == enumspb.WORKFLOW_EXECUTION_STATUS_RUNNING
currentVersionHistory, err := versionhistory.GetCurrentVersionHistory(response.GetVersionHistories())
if err != nil {
return nil, "", 0, 0, false, nil, nil, err
return nil, "", 0, 0, false, nil, nil, nil, err
}
lastVersionHistoryItem, err := versionhistory.GetLastVersionHistoryItem(currentVersionHistory)
if err != nil {
return nil, "", 0, 0, false, nil, nil, err
return nil, "", 0, 0, false, nil, nil, nil, err
}
lastVersionedTransition := transitionhistory.LastVersionedTransition(response.GetTransitionHistory())
@@ -124,6 +214,7 @@ func Invoke(
isWorkflowRunning,
lastVersionHistoryItem,
lastVersionedTransition,
response.GetTransientOrSpeculativeTasks(),
nil
}
@@ -135,6 +226,7 @@ func Invoke(
lastFirstEventID := common.FirstEventID
var nextEventID int64
var isWorkflowRunning bool
var cachedTransientTasks *historyspb.TransientWorkflowTaskInfo
// process the token for paging
queryNextEventID := common.EndEventID
@@ -149,13 +241,16 @@ func Invoke(
execution.RunId = continuationToken.GetRunId()
// Set isWorkflowRunning from continuation token for pagination
isWorkflowRunning = continuationToken.IsWorkflowRunning
// we need to update the current next event ID and whether workflow is running
if len(continuationToken.PersistenceToken) == 0 && isLongPoll && continuationToken.IsWorkflowRunning {
if !isCloseEventOnly {
queryNextEventID = continuationToken.GetNextEventId()
}
continuationToken.BranchToken, _, lastFirstEventID, nextEventID, isWorkflowRunning, continuationToken.VersionHistoryItem, continuationToken.VersionedTransition, err =
queryHistory(namespaceID, execution, queryNextEventID, continuationToken.BranchToken, continuationToken.VersionHistoryItem, continuationToken.VersionedTransition)
continuationToken.BranchToken, _, lastFirstEventID, nextEventID, isWorkflowRunning, continuationToken.VersionHistoryItem, continuationToken.VersionedTransition, cachedTransientTasks, err =
queryMutableState(namespaceID, execution, queryNextEventID, continuationToken.BranchToken, continuationToken.VersionHistoryItem, continuationToken.VersionedTransition)
if err != nil {
return nil, err
}
@@ -168,8 +263,8 @@ func Invoke(
if !isCloseEventOnly {
queryNextEventID = common.FirstEventID
}
continuationToken.BranchToken, runID, lastFirstEventID, nextEventID, isWorkflowRunning, continuationToken.VersionHistoryItem, continuationToken.VersionedTransition, err =
queryHistory(namespaceID, execution, queryNextEventID, nil, nil, nil)
continuationToken.BranchToken, runID, lastFirstEventID, nextEventID, isWorkflowRunning, continuationToken.VersionHistoryItem, continuationToken.VersionedTransition, cachedTransientTasks, err =
queryMutableState(namespaceID, execution, queryNextEventID, nil, nil, nil)
if err != nil {
return nil, err
}
@@ -220,8 +315,9 @@ func Invoke(
nextEventID,
request.Request.GetMaximumPageSize(),
nil,
continuationToken.TransientWorkflowTask,
nil,
continuationToken.BranchToken,
continuationToken.IsWorkflowRunning,
)
if err != nil {
return nil, err
@@ -239,9 +335,10 @@ func Invoke(
nextEventID,
request.Request.GetMaximumPageSize(),
nil,
continuationToken.TransientWorkflowTask,
nil,
continuationToken.BranchToken,
persistenceVisibilityMgr,
continuationToken.IsWorkflowRunning,
)
if err != nil {
return nil, err
@@ -299,8 +396,9 @@ func Invoke(
continuationToken.NextEventId,
request.Request.GetMaximumPageSize(),
continuationToken.PersistenceToken,
continuationToken.TransientWorkflowTask,
nil,
continuationToken.BranchToken,
continuationToken.IsWorkflowRunning,
)
} else {
history, continuationToken.PersistenceToken, err = api.GetHistory(
@@ -313,9 +411,10 @@ func Invoke(
continuationToken.NextEventId,
request.Request.GetMaximumPageSize(),
continuationToken.PersistenceToken,
continuationToken.TransientWorkflowTask,
nil,
continuationToken.BranchToken,
persistenceVisibilityMgr,
continuationToken.IsWorkflowRunning,
)
}
@@ -323,6 +422,23 @@ func Invoke(
return nil, err
}
// Query and append transient/speculative tasks if on last page
if isWorkflowRunning && len(continuationToken.PersistenceToken) == 0 {
appendTransientTasks(
ctx,
shardContext,
workflowConsistencyChecker,
eventNotifier,
namespaceID,
execution,
sendRawWorkflowHistoryForNamespace || sendRawHistoryBetweenInternalServices,
history,
&historyBlob,
cachedTransientTasks,
continuationToken.NextEventId,
)
}
// here, for long pull on history events, we need to intercept the paging token from cassandra
// and do something clever
if len(continuationToken.PersistenceToken) == 0 && (!continuationToken.IsWorkflowRunning || !isLongPoll) {
@@ -357,6 +473,7 @@ func Invoke(
}
historyBlob = nil
}
return &historyservice.GetWorkflowExecutionHistoryResponseWithRaw{
Response: &workflowservice.GetWorkflowExecutionHistoryResponse{
History: history,
@@ -299,6 +299,7 @@ func setHistoryForRecordWfTaskStartedResp(
var persistenceToken []byte
var history *historypb.History
var err error
if isInternalRawHistoryEnabled {
rawHistory, persistenceToken, err = api.GetRawHistory(
ctx,
@@ -312,6 +313,7 @@ func setHistoryForRecordWfTaskStartedResp(
nil,
response.GetTransientWorkflowTask(),
response.GetBranchToken(),
true,
)
} else {
history, persistenceToken, err = api.GetHistory(
@@ -327,6 +329,7 @@ func setHistoryForRecordWfTaskStartedResp(
response.GetTransientWorkflowTask(),
response.GetBranchToken(),
persistenceVisibilityMgr,
true,
)
}
if err != nil {
@@ -336,12 +339,11 @@ func setHistoryForRecordWfTaskStartedResp(
var continuation []byte
if len(persistenceToken) != 0 {
continuation, err = api.SerializeHistoryToken(&tokenspb.HistoryContinuation{
RunId: workflowKey.GetRunID(),
FirstEventId: firstEventID,
NextEventId: nextEventID,
PersistenceToken: persistenceToken,
TransientWorkflowTask: response.GetTransientWorkflowTask(),
BranchToken: response.GetBranchToken(),
RunId: workflowKey.GetRunID(),
FirstEventId: firstEventID,
NextEventId: nextEventID,
PersistenceToken: persistenceToken,
BranchToken: response.GetBranchToken(),
})
if err != nil {
return err
@@ -839,6 +839,11 @@ func (handler *WorkflowTaskCompletedHandler) createPollWorkflowTaskQueueResponse
)
}
}()
// Note: We pass nil for transientWorkflowTaskInfo here because the current task's
// scheduled/started events should not be visible in the history returned to that task.
// Transient events are only included in GetWorkflowExecutionHistory API responses,
// not in PollWorkflowTask responses. Including them here would show the worker its own
// task events, which is incorrect (see issue #7741).
history, persistenceToken, err = api.GetHistory(
ctx,
handler.shardContext,
@@ -849,9 +854,10 @@ func (handler *WorkflowTaskCompletedHandler) createPollWorkflowTaskQueueResponse
nextEventID,
maximumPageSize,
nil,
matchingResp.GetTransientWorkflowTask(),
nil,
branchToken,
handler.persistenceVisibilityMgr,
true,
)
if err != nil {
return nil, err
@@ -859,12 +865,11 @@ func (handler *WorkflowTaskCompletedHandler) createPollWorkflowTaskQueueResponse
if len(persistenceToken) != 0 {
continuation, err = api.SerializeHistoryToken(&tokenspb.HistoryContinuation{
RunId: matchingResp.WorkflowExecution.GetRunId(),
FirstEventId: firstEventID,
NextEventId: nextEventID,
PersistenceToken: persistenceToken,
TransientWorkflowTask: matchingResp.GetTransientWorkflowTask(),
BranchToken: branchToken,
RunId: matchingResp.WorkflowExecution.GetRunId(),
FirstEventId: firstEventID,
NextEventId: nextEventID,
PersistenceToken: persistenceToken,
BranchToken: branchToken,
})
if err != nil {
return nil, err
+41 -17
View File
@@ -5611,6 +5611,7 @@ func (s *engineSuite) TestGetHistory() {
nil,
branchToken,
s.mockVisibilityMgr,
false, // isWorkflowRunning
)
s.NoError(err)
s.NotNil(history)
@@ -5855,23 +5856,12 @@ func (s *engineSuite) TestGetWorkflowExecutionHistory_RawHistoryWithTransientDec
branchToken := []byte{1, 2, 3}
persistenceToken := []byte("some random persistence token")
nextPageToken, err := api.SerializeHistoryToken(&tokenspb.HistoryContinuation{
RunId: we.GetRunId(),
FirstEventId: common.FirstEventID,
NextEventId: 5,
PersistenceToken: persistenceToken,
TransientWorkflowTask: &historyspb.TransientWorkflowTaskInfo{
HistorySuffix: []*historypb.HistoryEvent{
{
EventId: 5,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED,
},
{
EventId: 6,
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_STARTED,
},
},
},
BranchToken: branchToken,
RunId: we.GetRunId(),
FirstEventId: common.FirstEventID,
NextEventId: 5,
PersistenceToken: persistenceToken,
BranchToken: branchToken,
IsWorkflowRunning: true, // Workflow is running, so we'll query MS for transient events
})
s.NoError(err)
s.config.SendRawWorkflowHistory = func(string) bool { return true }
@@ -5888,6 +5878,40 @@ func (s *engineSuite) TestGetWorkflowExecutionHistory_RawHistoryWithTransientDec
}
s.mockNamespaceCache.EXPECT().GetNamespaceID(tests.Namespace).Return(tests.NamespaceID, nil).AnyTimes()
// Mock GetMutableState to return transient workflow task events
s.mockExecutionMgr.EXPECT().GetWorkflowExecution(gomock.Any(), gomock.Any()).Return(&persistence.GetWorkflowExecutionResponse{
State: &persistencespb.WorkflowMutableState{
ExecutionState: &persistencespb.WorkflowExecutionState{
State: enumsspb.WORKFLOW_EXECUTION_STATE_RUNNING,
Status: enumspb.WORKFLOW_EXECUTION_STATUS_RUNNING,
RunId: we.RunId,
},
NextEventId: 5,
ExecutionInfo: &persistencespb.WorkflowExecutionInfo{
NamespaceId: tests.NamespaceID.String(),
WorkflowId: we.WorkflowId,
WorkflowTaskScheduledEventId: 5,
WorkflowTaskStartedEventId: 6,
WorkflowTaskAttempt: 2, // Attempt > 1 makes it transient
TaskQueue: "test-task-queue",
WorkflowTypeName: "test-workflow-type",
VersionHistories: &historyspb.VersionHistories{
CurrentVersionHistoryIndex: 0,
Histories: []*historyspb.VersionHistory{
{
BranchToken: branchToken,
Items: []*historyspb.VersionHistoryItem{
{EventId: 4, Version: 0},
},
},
},
},
},
},
MutableStateStats: persistence.MutableStateStatistics{},
}, nil).Times(1)
historyBlob1, err := s.mockShard.GetPayloadSerializer().SerializeEvents(
[]*historypb.HistoryEvent{
{
@@ -1159,7 +1159,7 @@ func (m *workflowTaskStateMachine) GetTransientWorkflowTaskInfo(
identity string,
) *historyspb.TransientWorkflowTaskInfo {
// Create scheduled and started events which are not written to the history yet.
// Create scheduled event which is not written to the history yet.
scheduledEvent := &historypb.HistoryEvent{
EventId: workflowTask.ScheduledEventID,
EventTime: timestamppb.New(workflowTask.ScheduledTime),
@@ -1174,6 +1174,15 @@ func (m *workflowTaskStateMachine) GetTransientWorkflowTaskInfo(
},
}
// Check if WFT is started
if workflowTask.StartedEventID == common.EmptyEventID {
// WFT only scheduled, not started yet
return &historyspb.TransientWorkflowTaskInfo{
HistorySuffix: []*historypb.HistoryEvent{scheduledEvent},
}
}
// WFT both scheduled and started
var versioningStamp *commonpb.WorkerVersionStamp
if workflowTask.BuildId != "" {
// fill out the stamp value of the transient WFT based on MS data
+4 -2
View File
@@ -1643,14 +1643,16 @@ func (s *AdvancedVisibilitySuite) TestUpsertWorkflowExecution_InvalidKey() {
1 WorkflowExecutionStarted
2 WorkflowTaskScheduled
3 WorkflowTaskStarted
4 WorkflowTaskFailed {"Cause":23,"Failure":{"Message":"BadSearchAttributes: search attribute INVALIDKEY is not defined"}}`, historyEvents)
4 WorkflowTaskFailed {"Cause":23,"Failure":{"Message":"BadSearchAttributes: search attribute INVALIDKEY is not defined"}}
5 WorkflowTaskScheduled`, historyEvents)
} else {
s.ErrorContains(err, fmt.Sprintf("BadSearchAttributes: Namespace %s has no mapping defined for search attribute INVALIDKEY", s.Namespace().String()))
s.EqualHistoryEvents(fmt.Sprintf(`
1 WorkflowExecutionStarted
2 WorkflowTaskScheduled
3 WorkflowTaskStarted
4 WorkflowTaskFailed {"Cause":23,"Failure":{"Message":"BadSearchAttributes: Namespace %s has no mapping defined for search attribute INVALIDKEY"}}`, s.Namespace().String()), historyEvents)
4 WorkflowTaskFailed {"Cause":23,"Failure":{"Message":"BadSearchAttributes: Namespace %s has no mapping defined for search attribute INVALIDKEY"}}
5 WorkflowTaskScheduled`, s.Namespace().String()), historyEvents)
}
}
+2 -1
View File
@@ -616,7 +616,8 @@ func (s *CancelWorkflowSuite) TestImmediateChildCancellation_WorkflowTaskFailed(
2 WorkflowTaskScheduled
3 WorkflowExecutionCancelRequested
4 WorkflowTaskStarted
5 WorkflowTaskFailed`, s.GetHistory(s.Namespace().String(), &commonpb.WorkflowExecution{
5 WorkflowTaskFailed
6 WorkflowTaskScheduled`, s.GetHistory(s.Namespace().String(), &commonpb.WorkflowExecution{
WorkflowId: id,
}))
+8 -4
View File
@@ -96,9 +96,9 @@ func (s *ClientMiscTestSuite) TestTooManyChildWorkflows() {
s.NoError(err)
s.WaitForHistoryEventsSuffix(`
WorkflowTaskScheduled
WorkflowTaskStarted // 26 below is enumspb.WORKFLOW_TASK_FAILED_CAUSE_PENDING_CHILD_WORKFLOWS_LIMIT_EXCEEDED
WorkflowTaskFailed {"Cause":26,"Failure":{"Message":"PendingChildWorkflowsLimitExceeded: the number of pending child workflow executions, 10, has reached the per-workflow limit of 10"}}
WorkflowTaskScheduled
WorkflowTaskStarted
`, func() []*historypb.HistoryEvent {
return s.GetHistory(s.Namespace().String(), &commonpb.WorkflowExecution{WorkflowId: parentWorkflowID})
}, 10*time.Second, 500*time.Millisecond)
@@ -180,9 +180,9 @@ func (s *ClientMiscTestSuite) TestTooManyPendingActivities() {
// verify that the workflow's history contains a task that failed because it would otherwise exceed the pending
// child workflow limit
s.WaitForHistoryEventsSuffix(`
19 WorkflowTaskScheduled
20 WorkflowTaskStarted // 27 below is enumspb.WORKFLOW_TASK_FAILED_CAUSE_PENDING_ACTIVITIES_LIMIT_EXCEEDED
21 WorkflowTaskFailed {"Cause":27,"Failure":{"Message":"PendingActivitiesLimitExceeded: the number of pending activities, 10, has reached the per-workflow limit of 10"}}
22 WorkflowTaskScheduled
23 WorkflowTaskStarted
`, func() []*historypb.HistoryEvent {
return s.GetHistory(s.Namespace().String(), &commonpb.WorkflowExecution{WorkflowId: workflowRun.GetID(), RunId: workflowRun.GetRunID()})
}, 3*time.Second, 500*time.Millisecond)
@@ -243,6 +243,8 @@ func (s *ClientMiscTestSuite) TestTooManyCancelRequests() {
2 WorkflowTaskScheduled
3 WorkflowTaskStarted // 29 below is enumspb.WORKFLOW_TASK_FAILED_CAUSE_PENDING_REQUEST_CANCEL_LIMIT_EXCEEDED
4 WorkflowTaskFailed {"Cause":29,"Failure":{"Message":"PendingRequestCancelLimitExceeded: the number of pending requests to cancel external workflows, 10, has reached the per-workflow limit of 10"}}
5 WorkflowTaskScheduled
6 WorkflowTaskStarted
`, func() []*historypb.HistoryEvent {
return s.GetHistory(s.Namespace().String(), &commonpb.WorkflowExecution{WorkflowId: run.GetID(), RunId: run.GetRunID()})
}, 5*time.Second, 500*time.Millisecond)
@@ -331,6 +333,8 @@ func (s *ClientMiscTestSuite) TestTooManyPendingSignals() {
2 WorkflowTaskScheduled
3 WorkflowTaskStarted // 28 below is enumspb.WORKFLOW_TASK_FAILED_CAUSE_PENDING_SIGNALS_LIMIT_EXCEEDED
4 WorkflowTaskFailed {"Cause":28,"Failure":{"Message":"PendingSignalsLimitExceeded: the number of pending signals to external workflows, 10, has reached the per-workflow limit of 10"}}
5 WorkflowTaskScheduled
6 WorkflowTaskStarted
`, func() []*historypb.HistoryEvent {
return s.GetHistory(s.Namespace().String(), &commonpb.WorkflowExecution{WorkflowId: senderRun.GetID(), RunId: senderRun.GetRunID()})
}, 3*time.Second, 500*time.Millisecond)
+3 -2
View File
@@ -97,7 +97,7 @@ func (s *RelayTaskTestSuite) TestRelayWorkflowTaskTimeout() {
workflowTaskTimeout := false
for i := 0; i < 3; i++ {
events := s.GetHistory(s.Namespace().String(), workflowExecution)
if len(events) == 8 {
if len(events) >= 8 {
s.EqualHistoryEvents(`
1 WorkflowExecutionStarted
2 WorkflowTaskScheduled
@@ -106,7 +106,8 @@ func (s *RelayTaskTestSuite) TestRelayWorkflowTaskTimeout() {
5 MarkerRecorded
6 WorkflowTaskScheduled
7 WorkflowTaskStarted
8 WorkflowTaskTimedOut {"ScheduledEventId":6,"StartedEventId":7,"TimeoutType":1} // TIMEOUT_TYPE_START_TO_CLOSE`, events)
8 WorkflowTaskTimedOut {"ScheduledEventId":6,"StartedEventId":7,"TimeoutType":1} // TIMEOUT_TYPE_START_TO_CLOSE
9 WorkflowTaskScheduled`, events)
workflowTaskTimeout = true
break
}
+4 -2
View File
@@ -193,7 +193,8 @@ WaitForStickyTimeoutLoop:
12 WorkflowExecutionSignaled
13 WorkflowTaskScheduled
14 WorkflowTaskStarted
15 WorkflowTaskFailed`, events)
15 WorkflowTaskFailed
16 WorkflowTaskScheduled`, events)
// Complete workflow execution
_, err = poller.PollAndProcessWorkflowTask(testcore.WithDumpHistory, testcore.WithRespondSticky, testcore.WithExpectedAttemptCount(3))
@@ -381,7 +382,8 @@ WaitForStickyTimeoutLoop:
12 WorkflowExecutionSignaled
13 WorkflowTaskScheduled
14 WorkflowTaskStarted
15 WorkflowTaskFailed`, events)
15 WorkflowTaskFailed
16 WorkflowTaskScheduled`, events)
// Complete workflow execution
_, err = poller.PollAndProcessWorkflowTask(testcore.WithDumpHistory, testcore.WithRespondSticky, testcore.WithExpectedAttemptCount(3))
+13 -16
View File
@@ -567,10 +567,8 @@ func TestWorkflowUpdateSuite(t *testing.T) {
return nil, nil
case 2:
s.EqualHistory(`
4 WorkflowTaskCompleted
5 WorkflowTaskScheduled // Speculative WT2 which was created while completing WT1.
6 WorkflowTaskStarted`, task.History)
// Message handler rejects update.
4 WorkflowTaskCompleted`, task.History)
// Message handled rejects update.
return nil, nil
case 3:
s.EqualHistory(`
@@ -691,10 +689,8 @@ func TestWorkflowUpdateSuite(t *testing.T) {
case 2:
s.EqualHistory(`
4 WorkflowTaskCompleted
5 ActivityTaskScheduled
6 WorkflowTaskScheduled // Speculative WFT2 with event (5) which was created while completing WFT1.
7 WorkflowTaskStarted`, task.History)
// Message handler rejects update.
5 ActivityTaskScheduled`, task.History)
// Message handled rejects update.
return nil, nil
case 3:
s.EqualHistory(`
@@ -2200,7 +2196,7 @@ func TestWorkflowUpdateSuite(t *testing.T) {
s.ErrorAs(updateResult.err, &wfNotReady)
s.Contains(updateResult.err.Error(), "Unable to perform workflow execution update due to unexpected workflow task failure.")
// New transient WFT is created, but it is not shown in the history.
// New transient WFT is created and is now included in the history.
events := s.GetHistory(s.Namespace().String(), s.Tv().WorkflowExecution())
s.EqualHistoryEvents(`
1 WorkflowExecutionStarted
@@ -2209,7 +2205,8 @@ func TestWorkflowUpdateSuite(t *testing.T) {
4 WorkflowTaskCompleted
5 WorkflowTaskScheduled
6 WorkflowTaskStarted
7 WorkflowTaskFailed`, events)
7 WorkflowTaskFailed
8 WorkflowTaskScheduled`, events)
// Send Update again. It will be delivered on existing transient WFT.
updateResultCh = sendUpdate(timeoutCtx, s, s.Tv())
@@ -2243,7 +2240,7 @@ func TestWorkflowUpdateSuite(t *testing.T) {
s.True(common.IsContextDeadlineExceededErr(updateResult.err), "UpdateWorkflowExecution must timeout after 2 seconds")
s.Nil(updateResult.response)
// This WFT failure wasn't recorded because WFT was transient.
// This WFT failure wasn't recorded because WFT was transient, but the scheduled event is included.
events = s.GetHistory(s.Namespace().String(), s.Tv().WorkflowExecution())
s.EqualHistoryEvents(`
1 WorkflowExecutionStarted
@@ -2252,7 +2249,8 @@ func TestWorkflowUpdateSuite(t *testing.T) {
4 WorkflowTaskCompleted
5 WorkflowTaskScheduled
6 WorkflowTaskStarted
7 WorkflowTaskFailed`, events)
7 WorkflowTaskFailed
8 WorkflowTaskScheduled`, events)
// Try to accept 2nd update in workflow 2nd time: get error. Poller will fail WT. Update is not aborted.
_, err = s.TaskPoller().PollAndHandleWorkflowTask(s.Tv(),
@@ -2277,7 +2275,8 @@ func TestWorkflowUpdateSuite(t *testing.T) {
4 WorkflowTaskCompleted
5 WorkflowTaskScheduled
6 WorkflowTaskStarted
7 WorkflowTaskFailed`, events)
7 WorkflowTaskFailed
8 WorkflowTaskScheduled`, events)
// Complete Update and workflow.
_, err = s.TaskPoller().PollAndHandleWorkflowTask(s.Tv(),
@@ -4432,9 +4431,7 @@ func TestWorkflowUpdateSuite(t *testing.T) {
return nil, nil
case 3:
s.EqualHistory(`
4 WorkflowTaskCompleted // Speculative WT was dropped and history starts from 4 again.
5 WorkflowTaskScheduled
6 WorkflowTaskStarted`, task.History)
4 WorkflowTaskCompleted`, task.History)
commands := append(s.UpdateAcceptCompleteCommands(tv2),
&commandpb.Command{
CommandType: enumspb.COMMAND_TYPE_COMPLETE_WORKFLOW_EXECUTION,
+26 -11
View File
@@ -871,13 +871,14 @@ func (s *Versioning3Suite) TestUnpinnedWorkflow_SuccessfulUpdate_TransitionsToNe
6 WorkflowTaskStarted
`, task.History)
// Verify that events from the speculative task are *not* written to the workflow history before being processed by the poller
events := s.GetHistory(s.Namespace().String(), execution)
s.EqualHistoryEvents(`
1 WorkflowExecutionStarted
2 WorkflowTaskScheduled
3 WorkflowTaskStarted
4 WorkflowTaskCompleted
5 WorkflowTaskScheduled
6 WorkflowTaskStarted
`, events)
// VersioningInfo should not have changed before the update has been processed by the poller.
@@ -957,13 +958,14 @@ func (s *Versioning3Suite) TestUnpinnedWorkflow_FailedUpdate_DoesNotTransitionTo
6 WorkflowTaskStarted
`, task.History)
// Verify that events from the speculative task are *not* written to the workflow history before being processed by the poller
events := s.GetHistory(s.Namespace().String(), execution)
s.EqualHistoryEvents(`
1 WorkflowExecutionStarted
2 WorkflowTaskScheduled
3 WorkflowTaskStarted
4 WorkflowTaskCompleted
5 WorkflowTaskScheduled
6 WorkflowTaskStarted
`, events)
// VersioningInfo should not have changed before the update has been processed by the poller.
@@ -2445,8 +2447,7 @@ func (s *Versioning3Suite) testPinnedCaNUpgradeOnCaN(normalTask, speculativeTask
s.verifySpeculativeTask(execution)
} else if transientTask {
s.verifyTransientTask(task)
// Get events from server-side history instead of task.History.Events, because task.History.Events has an
// extra started event with the CaN suggestion in the transient task case
// Get events from server-side history, this includes transient events.
historyEvents = s.GetHistory(s.Namespace().String(), execution)
}
@@ -2457,18 +2458,31 @@ func (s *Versioning3Suite) testPinnedCaNUpgradeOnCaN(normalTask, speculativeTask
}
}
if enableSendTargetVersionChanged {
// Verify ContinueAsNewSuggested and reasons were sent on the last WFT started event (but not the earlier ones).
s.Greater(len(wfTaskStartedEvents), 2) // make sure there are at least 2 WFT started events
// Verify TargetWorkerDeploymentVersionChanged was sent on WFT started events after deployment change.
// Events BEFORE deployment change (events 3, 7) should NOT have the flag.
// Events AFTER deployment change (all subsequent WFTs) SHOULD have the flag, regardless of success/failure.
// The flag is recomputed on every WFT, so both failed attempts and retries will have it if conditions persist.
s.Greater(len(wfTaskStartedEvents), 2) // make sure there are at least 3 WFT started events
// In this test, deployment is changed after event 7 (`s.setCurrentDeployment(tv2)`).
// So the first 2 WFT started events should NOT have the flag,
// and all subsequent events SHOULD have the flag.
eventsBeforeDeploymentChange := 2 // Events 3 and 7
for i, event := range wfTaskStartedEvents {
attr := event.GetWorkflowTaskStartedEventAttributes()
if i == len(wfTaskStartedEvents)-1 { // last event
if i < eventsBeforeDeploymentChange {
// Events before deployment change should NOT have the flag
s.False(attr.GetSuggestContinueAsNew())
s.Require().Empty(attr.GetSuggestContinueAsNewReasons())
s.True(attr.GetTargetWorkerDeploymentVersionChanged())
} else { // earlier events
s.False(attr.GetTargetWorkerDeploymentVersionChanged(),
"Event %d should not have flag (before deployment change)", event.GetEventId())
} else {
// Events after deployment change SHOULD have the flag (including failed attempts and transient retries)
s.False(attr.GetSuggestContinueAsNew())
s.Require().Empty(attr.GetSuggestContinueAsNewReasons())
s.False(attr.GetTargetWorkerDeploymentVersionChanged())
s.True(attr.GetTargetWorkerDeploymentVersionChanged(),
"Event %d should have flag (after deployment change)", event.GetEventId())
}
}
} else {
@@ -2578,7 +2592,6 @@ func (s *Versioning3Suite) triggerTransientWFT(ctx context.Context, tv *testvars
// Verify this is a speculative task - events not yet in persisted history
func (s *Versioning3Suite) verifySpeculativeTask(execution *commonpb.WorkflowExecution) {
// use history events instead of task events because some of the task.History.Events aren't persisted yet
events := s.GetHistory(s.Namespace().String(), execution)
s.EqualHistoryEvents(`
1 WorkflowExecutionStarted
@@ -2589,6 +2602,8 @@ func (s *Versioning3Suite) verifySpeculativeTask(execution *commonpb.WorkflowExe
6 WorkflowTaskScheduled
7 WorkflowTaskStarted
8 WorkflowTaskCompleted
9 WorkflowTaskScheduled
10 WorkflowTaskStarted
`, events)
}
+2 -1
View File
@@ -378,5 +378,6 @@ func (s *WorkflowFailuresTestSuite) TestRespondWorkflowTaskCompleted_ReturnsErro
1 WorkflowExecutionStarted
2 WorkflowTaskScheduled
3 WorkflowTaskStarted
4 WorkflowTaskFailed`, historyEvents)
4 WorkflowTaskFailed
5 WorkflowTaskScheduled`, historyEvents)
}
+21 -8
View File
@@ -649,7 +649,8 @@ func (s *WorkflowTaskTestSuite) TestWorkflowTerminationSignalBeforeTransientWork
1 WorkflowExecutionStarted
2 WorkflowTaskScheduled
3 WorkflowTaskStarted
4 WorkflowTaskFailed`, s.GetHistory(s.Namespace().String(), we))
4 WorkflowTaskFailed
5 WorkflowTaskScheduled`, s.GetHistory(s.Namespace().String(), we))
_, err0 = s.FrontendClient().SignalWorkflowExecution(testcore.NewContext(), &workflowservice.SignalWorkflowExecutionRequest{
Namespace: s.Namespace().String(),
@@ -660,12 +661,14 @@ func (s *WorkflowTaskTestSuite) TestWorkflowTerminationSignalBeforeTransientWork
RequestId: uuid.NewString(),
})
s.NoError(err0)
histAfterSignal := s.GetHistory(s.Namespace().String(), we)
s.GreaterOrEqual(len(histAfterSignal), 5, "Should have at least 5 events after signal")
s.EqualHistoryEvents(`
1 WorkflowExecutionStarted
2 WorkflowTaskScheduled
3 WorkflowTaskStarted
4 WorkflowTaskFailed
5 WorkflowExecutionSignaled`, s.GetHistory(s.Namespace().String(), we))
5 WorkflowExecutionSignaled`, histAfterSignal[:5])
// start this transient workflow task, the attempt should be cleared and it becomes again a regular workflow task
resp1, err1 := s.FrontendClient().PollWorkflowTaskQueue(testcore.NewContext(), &workflowservice.PollWorkflowTaskQueueRequest{
@@ -769,7 +772,8 @@ func (s *WorkflowTaskTestSuite) TestWorkflowTerminationSignalAfterTransientWorkf
1 WorkflowExecutionStarted
2 WorkflowTaskScheduled
3 WorkflowTaskStarted
4 WorkflowTaskFailed`, s.GetHistory(s.Namespace().String(), we))
4 WorkflowTaskFailed
5 WorkflowTaskScheduled`, s.GetHistory(s.Namespace().String(), we))
// start workflow task to make signals into bufferedEvents
_, err1 := s.FrontendClient().PollWorkflowTaskQueue(testcore.NewContext(), &workflowservice.PollWorkflowTaskQueueRequest{
@@ -783,7 +787,9 @@ func (s *WorkflowTaskTestSuite) TestWorkflowTerminationSignalAfterTransientWorkf
1 WorkflowExecutionStarted
2 WorkflowTaskScheduled
3 WorkflowTaskStarted
4 WorkflowTaskFailed`, s.GetHistory(s.Namespace().String(), we))
4 WorkflowTaskFailed
5 WorkflowTaskScheduled
6 WorkflowTaskStarted`, s.GetHistory(s.Namespace().String(), we))
// this signal should be buffered
_, err0 = s.FrontendClient().SignalWorkflowExecution(testcore.NewContext(), &workflowservice.SignalWorkflowExecutionRequest{
@@ -799,7 +805,9 @@ func (s *WorkflowTaskTestSuite) TestWorkflowTerminationSignalAfterTransientWorkf
1 WorkflowExecutionStarted
2 WorkflowTaskScheduled
3 WorkflowTaskStarted
4 WorkflowTaskFailed`, s.GetHistory(s.Namespace().String(), we))
4 WorkflowTaskFailed
5 WorkflowTaskScheduled
6 WorkflowTaskStarted`, s.GetHistory(s.Namespace().String(), we))
// then terminate the workflow
_, err := s.FrontendClient().TerminateWorkflowExecution(testcore.NewContext(), &workflowservice.TerminateWorkflowExecutionRequest{
@@ -882,7 +890,8 @@ func (s *WorkflowTaskTestSuite) TestWorkflowTerminationSignalAfterTransientWorkf
1 WorkflowExecutionStarted
2 WorkflowTaskScheduled
3 WorkflowTaskStarted
4 WorkflowTaskFailed`, s.GetHistory(s.Namespace().String(), we))
4 WorkflowTaskFailed
5 WorkflowTaskScheduled`, s.GetHistory(s.Namespace().String(), we))
// start workflow task to make signals into bufferedEvents
resp1, err1 := s.FrontendClient().PollWorkflowTaskQueue(testcore.NewContext(), &workflowservice.PollWorkflowTaskQueueRequest{
@@ -896,7 +905,9 @@ func (s *WorkflowTaskTestSuite) TestWorkflowTerminationSignalAfterTransientWorkf
1 WorkflowExecutionStarted
2 WorkflowTaskScheduled
3 WorkflowTaskStarted
4 WorkflowTaskFailed`, s.GetHistory(s.Namespace().String(), we))
4 WorkflowTaskFailed
5 WorkflowTaskScheduled
6 WorkflowTaskStarted`, s.GetHistory(s.Namespace().String(), we))
// this signal should be buffered
_, err0 = s.FrontendClient().SignalWorkflowExecution(testcore.NewContext(), &workflowservice.SignalWorkflowExecutionRequest{
@@ -912,7 +923,9 @@ func (s *WorkflowTaskTestSuite) TestWorkflowTerminationSignalAfterTransientWorkf
1 WorkflowExecutionStarted
2 WorkflowTaskScheduled
3 WorkflowTaskStarted
4 WorkflowTaskFailed`, s.GetHistory(s.Namespace().String(), we))
4 WorkflowTaskFailed
5 WorkflowTaskScheduled
6 WorkflowTaskStarted`, s.GetHistory(s.Namespace().String(), we))
// fail this workflow task to flush buffer
_, err2 := s.FrontendClient().RespondWorkflowTaskFailed(testcore.NewContext(), &workflowservice.RespondWorkflowTaskFailedRequest{
@@ -0,0 +1,410 @@
package tests
import (
"context"
"errors"
"testing"
"time"
"github.com/google/uuid"
"github.com/stretchr/testify/suite"
commandpb "go.temporal.io/api/command/v1"
commonpb "go.temporal.io/api/common/v1"
enumspb "go.temporal.io/api/enums/v1"
"go.temporal.io/api/serviceerror"
taskqueuepb "go.temporal.io/api/taskqueue/v1"
"go.temporal.io/api/workflowservice/v1"
"go.temporal.io/server/common/headers"
"go.temporal.io/server/common/payloads"
"go.temporal.io/server/tests/testcore"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/types/known/durationpb"
)
type TransientWorkflowTaskHistorySuite struct {
testcore.FunctionalTestBase //nolint:forbidigo // Temporary usage until migration to testcore.NewEnv(t)
}
func TestTransientWorkflowTaskHistorySuite(t *testing.T) {
t.Parallel()
suite.Run(t, new(TransientWorkflowTaskHistorySuite))
}
// newSDKContext creates a context that identifies as a Go SDK client.
// This allows the tests to receive transient/speculative events in GetWorkflowExecutionHistory responses.
func newSDKContext() context.Context {
ctx := testcore.NewContext()
// Override the server client name with Go SDK client name.
// This ensures transient/speculative events are included in history responses.
ctx = metadata.AppendToOutgoingContext(ctx,
headers.ClientNameHeaderName, headers.ClientNameGoSDK,
)
return ctx
}
// TestGetHistoryAfterCacheEviction_TransientWFT is the core regression test.
// It replicates the scenario where a worker's cache is evicted and then requests
// history that should include transient events.
func (s *TransientWorkflowTaskHistorySuite) TestGetHistoryAfterCacheEviction_TransientWFT() {
id := "functional-get-history-after-cache-eviction-transient-wft"
wt := "functional-get-history-after-cache-eviction-transient-wft-type"
tl := "functional-get-history-after-cache-eviction-transient-wft-taskqueue"
identity := "worker1"
// Start workflow execution
request := &workflowservice.StartWorkflowExecutionRequest{
RequestId: uuid.NewString(),
Namespace: s.Namespace().String(),
WorkflowId: id,
WorkflowType: &commonpb.WorkflowType{Name: wt},
TaskQueue: &taskqueuepb.TaskQueue{Name: tl, Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
Input: nil,
WorkflowRunTimeout: durationpb.New(100 * time.Second),
WorkflowTaskTimeout: durationpb.New(2 * time.Second),
Identity: identity,
}
we, err := s.FrontendClient().StartWorkflowExecution(testcore.NewContext(), request)
s.NoError(err)
workflowExecution := &commonpb.WorkflowExecution{
WorkflowId: id,
RunId: we.RunId,
}
// Step 1: Fail the first workflow task to create a transient WFT (attempt=2)
failWorkflowTask := true
wtHandler := func(task *workflowservice.PollWorkflowTaskQueueResponse) ([]*commandpb.Command, error) {
if failWorkflowTask {
failWorkflowTask = false
return nil, errors.New("simulated workflow task failure")
}
// Complete workflow on second attempt
return []*commandpb.Command{{
CommandType: enumspb.COMMAND_TYPE_COMPLETE_WORKFLOW_EXECUTION,
Attributes: &commandpb.Command_CompleteWorkflowExecutionCommandAttributes{
CompleteWorkflowExecutionCommandAttributes: &commandpb.CompleteWorkflowExecutionCommandAttributes{
Result: payloads.EncodeString("Done"),
}},
}}, nil
}
//nolint:staticcheck // SA1019 Using deprecated testcore.TaskPoller for backwards compatibility
poller := &testcore.TaskPoller{
Client: s.FrontendClient(),
Namespace: s.Namespace().String(),
TaskQueue: &taskqueuepb.TaskQueue{Name: tl, Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
Identity: identity,
WorkflowTaskHandler: wtHandler,
Logger: s.Logger,
T: s.T(),
}
// Poll and fail the first workflow task - this creates transient WFT (attempt=2)
_, err = poller.PollAndProcessWorkflowTask()
s.NoError(err)
// Step 2: Poll the transient task and start it (but don't complete yet)
// This simulates having both scheduled + started transient events
ctx := newSDKContext()
resp2, err := s.FrontendClient().PollWorkflowTaskQueue(ctx, &workflowservice.PollWorkflowTaskQueueRequest{
Namespace: s.Namespace().String(),
TaskQueue: &taskqueuepb.TaskQueue{Name: tl, Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
Identity: identity,
})
s.NoError(err)
s.NotNil(resp2)
s.NotEmpty(resp2.TaskToken)
// Step 3: Call GetWorkflowExecutionHistory, simulating worker cache eviction
histResp, err := s.FrontendClient().GetWorkflowExecutionHistory(ctx,
&workflowservice.GetWorkflowExecutionHistoryRequest{
Namespace: s.Namespace().String(),
Execution: workflowExecution,
MaximumPageSize: 100,
})
s.NoError(err, "GetWorkflowExecutionHistory should not return 'premature end of stream' error")
s.NotNil(histResp)
s.NotNil(histResp.History)
s.NotEmpty(histResp.History.Events)
// Step 5: Verify history includes transient WorkflowTaskScheduled (attempt=2) and WorkflowTaskStarted events
events := histResp.History.Events
foundScheduled := false
foundStarted := false
for _, event := range events {
if event.GetEventType() == enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED {
attrs := event.GetWorkflowTaskScheduledEventAttributes()
if attrs.GetAttempt() == 2 {
foundScheduled = true
}
}
if event.GetEventType() == enumspb.EVENT_TYPE_WORKFLOW_TASK_STARTED {
// Check if this is the started event for the transient task (attempt 2)
// by checking if it comes after a scheduled event with attempt=2
for i, e := range events {
if e.GetEventId() == event.GetEventId() && i > 0 {
prevEvent := events[i-1]
if prevEvent.GetEventType() == enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED &&
prevEvent.GetWorkflowTaskScheduledEventAttributes().GetAttempt() == 2 {
foundStarted = true
}
}
}
}
}
s.True(foundScheduled, "History should include transient WorkflowTaskScheduled event (attempt=2)")
s.True(foundStarted, "History should include transient WorkflowTaskStarted event")
// The last event ID in history should match or exceed what worker expects from PollWorkflowTask
lastEventID := events[len(events)-1].GetEventId()
s.GreaterOrEqual(lastEventID, resp2.GetStartedEventId(),
"Last event ID in history should be >= StartedEventId from poll response to prevent 'premature end of stream'")
// Clean up by completing the workflow task
_, err = s.FrontendClient().RespondWorkflowTaskCompleted(ctx, &workflowservice.RespondWorkflowTaskCompletedRequest{
Namespace: s.Namespace().String(),
TaskToken: resp2.TaskToken,
Identity: identity,
Commands: []*commandpb.Command{{
CommandType: enumspb.COMMAND_TYPE_COMPLETE_WORKFLOW_EXECUTION,
Attributes: &commandpb.Command_CompleteWorkflowExecutionCommandAttributes{
CompleteWorkflowExecutionCommandAttributes: &commandpb.CompleteWorkflowExecutionCommandAttributes{
Result: payloads.EncodeString("Done"),
}},
}},
})
s.NoError(err)
}
// TestGetHistory_TransientWFT_ScheduledOnly verifies transient events are included
// even when WFT is scheduled but not yet started.
func (s *TransientWorkflowTaskHistorySuite) TestGetHistory_TransientWFT_ScheduledOnly() {
id := "functional-get-history-transient-wft-scheduled-only"
wt := "functional-get-history-transient-wft-scheduled-only-type"
tl := "functional-get-history-transient-wft-scheduled-only-taskqueue"
identity := "worker1"
// Start workflow execution
request := &workflowservice.StartWorkflowExecutionRequest{
RequestId: uuid.NewString(),
Namespace: s.Namespace().String(),
WorkflowId: id,
WorkflowType: &commonpb.WorkflowType{Name: wt},
TaskQueue: &taskqueuepb.TaskQueue{Name: tl, Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
Input: nil,
WorkflowRunTimeout: durationpb.New(100 * time.Second),
WorkflowTaskTimeout: durationpb.New(2 * time.Second),
Identity: identity,
}
we, err := s.FrontendClient().StartWorkflowExecution(testcore.NewContext(), request)
s.NoError(err)
workflowExecution := &commonpb.WorkflowExecution{
WorkflowId: id,
RunId: we.RunId,
}
// Step 1: Fail first task to create transient WFT (attempt=2)
failWorkflowTask := true
wtHandler := func(task *workflowservice.PollWorkflowTaskQueueResponse) ([]*commandpb.Command, error) {
if failWorkflowTask {
failWorkflowTask = false
return nil, errors.New("simulated workflow task failure")
}
return []*commandpb.Command{{
CommandType: enumspb.COMMAND_TYPE_COMPLETE_WORKFLOW_EXECUTION,
Attributes: &commandpb.Command_CompleteWorkflowExecutionCommandAttributes{
CompleteWorkflowExecutionCommandAttributes: &commandpb.CompleteWorkflowExecutionCommandAttributes{
Result: payloads.EncodeString("Done"),
}},
}}, nil
}
//nolint:staticcheck // SA1019 Using deprecated testcore.TaskPoller for backwards compatibility
poller := &testcore.TaskPoller{
Client: s.FrontendClient(),
Namespace: s.Namespace().String(),
TaskQueue: &taskqueuepb.TaskQueue{Name: tl, Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
Identity: identity,
WorkflowTaskHandler: wtHandler,
Logger: s.Logger,
T: s.T(),
}
// Poll and fail the first workflow task
_, err = poller.PollAndProcessWorkflowTask()
s.NoError(err)
// Step 2: Call GetWorkflowExecutionHistory BEFORE polling the transient task
ctx := newSDKContext()
histResp, err := s.FrontendClient().GetWorkflowExecutionHistory(ctx,
&workflowservice.GetWorkflowExecutionHistoryRequest{
Namespace: s.Namespace().String(),
Execution: workflowExecution,
MaximumPageSize: 100,
})
s.NoError(err)
s.NotNil(histResp)
s.NotNil(histResp.History)
s.NotEmpty(histResp.History.Events)
// Step 3: Verify history includes transient WorkflowTaskScheduled event (attempt=2)
events := histResp.History.Events
foundScheduled := false
foundStarted := false
for _, event := range events {
if event.GetEventType() == enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED {
attrs := event.GetWorkflowTaskScheduledEventAttributes()
if attrs.GetAttempt() == 2 {
foundScheduled = true
}
}
if event.GetEventType() == enumspb.EVENT_TYPE_WORKFLOW_TASK_STARTED {
// Check if this corresponds to the transient task
for i, e := range events {
if e.GetEventId() == event.GetEventId() && i > 0 {
prevEvent := events[i-1]
if prevEvent.GetEventType() == enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED &&
prevEvent.GetWorkflowTaskScheduledEventAttributes().GetAttempt() == 2 {
foundStarted = true
}
}
}
}
}
s.True(foundScheduled, "History should include transient WorkflowTaskScheduled event (attempt=2)")
s.False(foundStarted, "History should NOT include transient WorkflowTaskStarted event (task not polled yet)")
// Clean up: Poll and complete the transient task
_, err = poller.PollAndProcessWorkflowTask()
s.NoError(err)
}
// TestGetHistory_RaceCondition_RetryableError verifies that pagination handles the case
// where the workflow completes during multi-page history retrieval.
func (s *TransientWorkflowTaskHistorySuite) TestGetHistory_RaceCondition_RetryableError() {
id := "functional-get-history-race-condition-retryable-error"
wt := "functional-get-history-race-condition-retryable-error-type"
tl := "functional-get-history-race-condition-retryable-error-taskqueue"
identity := "worker1"
// Start workflow execution
request := &workflowservice.StartWorkflowExecutionRequest{
RequestId: uuid.NewString(),
Namespace: s.Namespace().String(),
WorkflowId: id,
WorkflowType: &commonpb.WorkflowType{Name: wt},
TaskQueue: &taskqueuepb.TaskQueue{Name: tl, Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
Input: nil,
WorkflowRunTimeout: durationpb.New(100 * time.Second),
WorkflowTaskTimeout: durationpb.New(2 * time.Second),
Identity: identity,
}
we, err := s.FrontendClient().StartWorkflowExecution(testcore.NewContext(), request)
s.NoError(err)
workflowExecution := &commonpb.WorkflowExecution{
WorkflowId: id,
RunId: we.RunId,
}
// Step 1: Create a transient WFT by failing the first task
failWorkflowTask := true
wtHandler := func(task *workflowservice.PollWorkflowTaskQueueResponse) ([]*commandpb.Command, error) {
if failWorkflowTask {
failWorkflowTask = false
return nil, errors.New("simulated workflow task failure")
}
return []*commandpb.Command{{
CommandType: enumspb.COMMAND_TYPE_COMPLETE_WORKFLOW_EXECUTION,
Attributes: &commandpb.Command_CompleteWorkflowExecutionCommandAttributes{
CompleteWorkflowExecutionCommandAttributes: &commandpb.CompleteWorkflowExecutionCommandAttributes{
Result: payloads.EncodeString("Done"),
}},
}}, nil
}
//nolint:staticcheck // SA1019 Using deprecated testcore.TaskPoller for backwards compatibility
poller := &testcore.TaskPoller{
Client: s.FrontendClient(),
Namespace: s.Namespace().String(),
TaskQueue: &taskqueuepb.TaskQueue{Name: tl, Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
Identity: identity,
WorkflowTaskHandler: wtHandler,
Logger: s.Logger,
T: s.T(),
}
// Poll and fail the first workflow task
_, err = poller.PollAndProcessWorkflowTask()
s.NoError(err)
// Step 2: Poll the transient task to start it
ctx := newSDKContext()
resp2, err := s.FrontendClient().PollWorkflowTaskQueue(ctx, &workflowservice.PollWorkflowTaskQueueRequest{
Namespace: s.Namespace().String(),
TaskQueue: &taskqueuepb.TaskQueue{Name: tl, Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
Identity: identity,
})
s.NoError(err)
s.NotNil(resp2)
s.NotEmpty(resp2.TaskToken)
// Step 3: Start fetching history with pagination (small page size to force pagination)
histResp, err := s.FrontendClient().GetWorkflowExecutionHistory(ctx,
&workflowservice.GetWorkflowExecutionHistoryRequest{
Namespace: s.Namespace().String(),
Execution: workflowExecution,
MaximumPageSize: 2, // Small page size to force pagination
})
s.NoError(err)
s.NotNil(histResp)
// Step 4: Complete the transient WFT (changes event IDs) DURING pagination
_, err = s.FrontendClient().RespondWorkflowTaskCompleted(ctx, &workflowservice.RespondWorkflowTaskCompletedRequest{
Namespace: s.Namespace().String(),
TaskToken: resp2.TaskToken,
Identity: identity,
Commands: []*commandpb.Command{{
CommandType: enumspb.COMMAND_TYPE_COMPLETE_WORKFLOW_EXECUTION,
Attributes: &commandpb.Command_CompleteWorkflowExecutionCommandAttributes{
CompleteWorkflowExecutionCommandAttributes: &commandpb.CompleteWorkflowExecutionCommandAttributes{
Result: payloads.EncodeString("Done"),
}},
}},
})
s.NoError(err)
// Step 5: Continue pagination with the next page token
// Tests that pagination handles workflow completion gracefully during multi-page retrieval
if histResp.NextPageToken != nil {
histResp2, err := s.FrontendClient().GetWorkflowExecutionHistory(ctx,
&workflowservice.GetWorkflowExecutionHistoryRequest{
Namespace: s.Namespace().String(),
Execution: workflowExecution,
MaximumPageSize: 2,
NextPageToken: histResp.NextPageToken,
})
// Depending on timing, we might get:
// 1. An Unavailable error if transient events changed (e.g., validation failed)
// 2. Success if the workflow completed and pagination succeeded
// We verify that if there's an error, it's the expected type
if err != nil {
var unavailableErr *serviceerror.Unavailable
s.ErrorAs(err, &unavailableErr)
} else {
// If no error, the pagination completed successfully
// This can happen if the workflow completed before the second page was fetched
s.NotNil(histResp2)
}
}
}