From fbc9eb4e1ef207173ca47ca044cb9433e7fd2812 Mon Sep 17 00:00:00 2001 From: Albert Callarisa Date: Wed, 6 May 2026 15:37:04 +0200 Subject: [PATCH 1/3] Implements detached workflows from a workflow contexts Signed-off-by: Albert Callarisa --- api/protos/history_events.pb.go | 926 ++++++++++++++------------ api/protos/orchestrator_actions.pb.go | 592 ++++++++++------ backend/runtimestate/applier.go | 81 +++ submodules/durabletask-protobuf | 2 +- task/detached_workflow_test.go | 234 +++++++ task/orchestrator.go | 231 +++++++ tests/orchestrations_test.go | 164 +++++ tests/runtimestate_test.go | 360 ++++++++++ workflow/workflow.go | 81 ++- 9 files changed, 2062 insertions(+), 609 deletions(-) create mode 100644 task/detached_workflow_test.go diff --git a/api/protos/history_events.pb.go b/api/protos/history_events.pb.go index 419cef3..96c8a72 100644 --- a/api/protos/history_events.pb.go +++ b/api/protos/history_events.pb.go @@ -781,6 +781,59 @@ func (x *ChildWorkflowInstanceFailedEvent) GetSignerCertificate() []byte { return nil } +// DetachedWorkflowInstanceCreatedEvent records that a running workflow +// created a new, detached workflow instance via CreateDetachedWorkflowAction. +// The new workflow has no parent linkage (no completion or failure flows +// back), so this event only stores a pointer to the spawned instance — the +// inputs themselves are consumed directly from the action when scheduling. +// Replay matches on instanceId, so it is the same value the action carried. +type DetachedWorkflowInstanceCreatedEvent struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + InstanceId string `protobuf:"bytes,1,opt,name=instanceId,proto3" json:"instanceId,omitempty"` +} + +func (x *DetachedWorkflowInstanceCreatedEvent) Reset() { + *x = DetachedWorkflowInstanceCreatedEvent{} + if protoimpl.UnsafeEnabled { + mi := &file_history_events_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DetachedWorkflowInstanceCreatedEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DetachedWorkflowInstanceCreatedEvent) ProtoMessage() {} + +func (x *DetachedWorkflowInstanceCreatedEvent) ProtoReflect() protoreflect.Message { + mi := &file_history_events_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DetachedWorkflowInstanceCreatedEvent.ProtoReflect.Descriptor instead. +func (*DetachedWorkflowInstanceCreatedEvent) Descriptor() ([]byte, []int) { + return file_history_events_proto_rawDescGZIP(), []int{9} +} + +func (x *DetachedWorkflowInstanceCreatedEvent) GetInstanceId() string { + if x != nil { + return x.InstanceId + } + return "" +} + // Indicates the timer was created by a createTimer call with no special origin. type TimerOriginCreateTimer struct { state protoimpl.MessageState @@ -791,7 +844,7 @@ type TimerOriginCreateTimer struct { func (x *TimerOriginCreateTimer) Reset() { *x = TimerOriginCreateTimer{} if protoimpl.UnsafeEnabled { - mi := &file_history_events_proto_msgTypes[9] + mi := &file_history_events_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -804,7 +857,7 @@ func (x *TimerOriginCreateTimer) String() string { func (*TimerOriginCreateTimer) ProtoMessage() {} func (x *TimerOriginCreateTimer) ProtoReflect() protoreflect.Message { - mi := &file_history_events_proto_msgTypes[9] + mi := &file_history_events_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -817,7 +870,7 @@ func (x *TimerOriginCreateTimer) ProtoReflect() protoreflect.Message { // Deprecated: Use TimerOriginCreateTimer.ProtoReflect.Descriptor instead. func (*TimerOriginCreateTimer) Descriptor() ([]byte, []int) { - return file_history_events_proto_rawDescGZIP(), []int{9} + return file_history_events_proto_rawDescGZIP(), []int{10} } // Indicates the timer was created as a timeout for a waitForExternalEvent call. @@ -833,7 +886,7 @@ type TimerOriginExternalEvent struct { func (x *TimerOriginExternalEvent) Reset() { *x = TimerOriginExternalEvent{} if protoimpl.UnsafeEnabled { - mi := &file_history_events_proto_msgTypes[10] + mi := &file_history_events_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -846,7 +899,7 @@ func (x *TimerOriginExternalEvent) String() string { func (*TimerOriginExternalEvent) ProtoMessage() {} func (x *TimerOriginExternalEvent) ProtoReflect() protoreflect.Message { - mi := &file_history_events_proto_msgTypes[10] + mi := &file_history_events_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -859,7 +912,7 @@ func (x *TimerOriginExternalEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use TimerOriginExternalEvent.ProtoReflect.Descriptor instead. func (*TimerOriginExternalEvent) Descriptor() ([]byte, []int) { - return file_history_events_proto_rawDescGZIP(), []int{10} + return file_history_events_proto_rawDescGZIP(), []int{11} } func (x *TimerOriginExternalEvent) GetName() string { @@ -882,7 +935,7 @@ type TimerOriginActivityRetry struct { func (x *TimerOriginActivityRetry) Reset() { *x = TimerOriginActivityRetry{} if protoimpl.UnsafeEnabled { - mi := &file_history_events_proto_msgTypes[11] + mi := &file_history_events_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -895,7 +948,7 @@ func (x *TimerOriginActivityRetry) String() string { func (*TimerOriginActivityRetry) ProtoMessage() {} func (x *TimerOriginActivityRetry) ProtoReflect() protoreflect.Message { - mi := &file_history_events_proto_msgTypes[11] + mi := &file_history_events_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -908,7 +961,7 @@ func (x *TimerOriginActivityRetry) ProtoReflect() protoreflect.Message { // Deprecated: Use TimerOriginActivityRetry.ProtoReflect.Descriptor instead. func (*TimerOriginActivityRetry) Descriptor() ([]byte, []int) { - return file_history_events_proto_rawDescGZIP(), []int{11} + return file_history_events_proto_rawDescGZIP(), []int{12} } func (x *TimerOriginActivityRetry) GetTaskExecutionId() string { @@ -931,7 +984,7 @@ type TimerOriginChildWorkflowRetry struct { func (x *TimerOriginChildWorkflowRetry) Reset() { *x = TimerOriginChildWorkflowRetry{} if protoimpl.UnsafeEnabled { - mi := &file_history_events_proto_msgTypes[12] + mi := &file_history_events_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -944,7 +997,7 @@ func (x *TimerOriginChildWorkflowRetry) String() string { func (*TimerOriginChildWorkflowRetry) ProtoMessage() {} func (x *TimerOriginChildWorkflowRetry) ProtoReflect() protoreflect.Message { - mi := &file_history_events_proto_msgTypes[12] + mi := &file_history_events_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -957,7 +1010,7 @@ func (x *TimerOriginChildWorkflowRetry) ProtoReflect() protoreflect.Message { // Deprecated: Use TimerOriginChildWorkflowRetry.ProtoReflect.Descriptor instead. func (*TimerOriginChildWorkflowRetry) Descriptor() ([]byte, []int) { - return file_history_events_proto_rawDescGZIP(), []int{12} + return file_history_events_proto_rawDescGZIP(), []int{13} } func (x *TimerOriginChildWorkflowRetry) GetInstanceId() string { @@ -991,7 +1044,7 @@ type TimerCreatedEvent struct { func (x *TimerCreatedEvent) Reset() { *x = TimerCreatedEvent{} if protoimpl.UnsafeEnabled { - mi := &file_history_events_proto_msgTypes[13] + mi := &file_history_events_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1004,7 +1057,7 @@ func (x *TimerCreatedEvent) String() string { func (*TimerCreatedEvent) ProtoMessage() {} func (x *TimerCreatedEvent) ProtoReflect() protoreflect.Message { - mi := &file_history_events_proto_msgTypes[13] + mi := &file_history_events_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1017,7 +1070,7 @@ func (x *TimerCreatedEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use TimerCreatedEvent.ProtoReflect.Descriptor instead. func (*TimerCreatedEvent) Descriptor() ([]byte, []int) { - return file_history_events_proto_rawDescGZIP(), []int{13} + return file_history_events_proto_rawDescGZIP(), []int{14} } func (x *TimerCreatedEvent) GetFireAt() *timestamppb.Timestamp { @@ -1116,7 +1169,7 @@ type TimerFiredEvent struct { func (x *TimerFiredEvent) Reset() { *x = TimerFiredEvent{} if protoimpl.UnsafeEnabled { - mi := &file_history_events_proto_msgTypes[14] + mi := &file_history_events_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1129,7 +1182,7 @@ func (x *TimerFiredEvent) String() string { func (*TimerFiredEvent) ProtoMessage() {} func (x *TimerFiredEvent) ProtoReflect() protoreflect.Message { - mi := &file_history_events_proto_msgTypes[14] + mi := &file_history_events_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1142,7 +1195,7 @@ func (x *TimerFiredEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use TimerFiredEvent.ProtoReflect.Descriptor instead. func (*TimerFiredEvent) Descriptor() ([]byte, []int) { - return file_history_events_proto_rawDescGZIP(), []int{14} + return file_history_events_proto_rawDescGZIP(), []int{15} } func (x *TimerFiredEvent) GetFireAt() *timestamppb.Timestamp { @@ -1170,7 +1223,7 @@ type WorkflowStartedEvent struct { func (x *WorkflowStartedEvent) Reset() { *x = WorkflowStartedEvent{} if protoimpl.UnsafeEnabled { - mi := &file_history_events_proto_msgTypes[15] + mi := &file_history_events_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1183,7 +1236,7 @@ func (x *WorkflowStartedEvent) String() string { func (*WorkflowStartedEvent) ProtoMessage() {} func (x *WorkflowStartedEvent) ProtoReflect() protoreflect.Message { - mi := &file_history_events_proto_msgTypes[15] + mi := &file_history_events_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1196,7 +1249,7 @@ func (x *WorkflowStartedEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkflowStartedEvent.ProtoReflect.Descriptor instead. func (*WorkflowStartedEvent) Descriptor() ([]byte, []int) { - return file_history_events_proto_rawDescGZIP(), []int{15} + return file_history_events_proto_rawDescGZIP(), []int{16} } func (x *WorkflowStartedEvent) GetVersion() *WorkflowVersion { @@ -1215,7 +1268,7 @@ type WorkflowCompletedEvent struct { func (x *WorkflowCompletedEvent) Reset() { *x = WorkflowCompletedEvent{} if protoimpl.UnsafeEnabled { - mi := &file_history_events_proto_msgTypes[16] + mi := &file_history_events_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1228,7 +1281,7 @@ func (x *WorkflowCompletedEvent) String() string { func (*WorkflowCompletedEvent) ProtoMessage() {} func (x *WorkflowCompletedEvent) ProtoReflect() protoreflect.Message { - mi := &file_history_events_proto_msgTypes[16] + mi := &file_history_events_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1241,7 +1294,7 @@ func (x *WorkflowCompletedEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkflowCompletedEvent.ProtoReflect.Descriptor instead. func (*WorkflowCompletedEvent) Descriptor() ([]byte, []int) { - return file_history_events_proto_rawDescGZIP(), []int{16} + return file_history_events_proto_rawDescGZIP(), []int{17} } type EventSentEvent struct { @@ -1257,7 +1310,7 @@ type EventSentEvent struct { func (x *EventSentEvent) Reset() { *x = EventSentEvent{} if protoimpl.UnsafeEnabled { - mi := &file_history_events_proto_msgTypes[17] + mi := &file_history_events_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1270,7 +1323,7 @@ func (x *EventSentEvent) String() string { func (*EventSentEvent) ProtoMessage() {} func (x *EventSentEvent) ProtoReflect() protoreflect.Message { - mi := &file_history_events_proto_msgTypes[17] + mi := &file_history_events_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1283,7 +1336,7 @@ func (x *EventSentEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use EventSentEvent.ProtoReflect.Descriptor instead. func (*EventSentEvent) Descriptor() ([]byte, []int) { - return file_history_events_proto_rawDescGZIP(), []int{17} + return file_history_events_proto_rawDescGZIP(), []int{18} } func (x *EventSentEvent) GetInstanceId() string { @@ -1319,7 +1372,7 @@ type EventRaisedEvent struct { func (x *EventRaisedEvent) Reset() { *x = EventRaisedEvent{} if protoimpl.UnsafeEnabled { - mi := &file_history_events_proto_msgTypes[18] + mi := &file_history_events_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1332,7 +1385,7 @@ func (x *EventRaisedEvent) String() string { func (*EventRaisedEvent) ProtoMessage() {} func (x *EventRaisedEvent) ProtoReflect() protoreflect.Message { - mi := &file_history_events_proto_msgTypes[18] + mi := &file_history_events_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1345,7 +1398,7 @@ func (x *EventRaisedEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use EventRaisedEvent.ProtoReflect.Descriptor instead. func (*EventRaisedEvent) Descriptor() ([]byte, []int) { - return file_history_events_proto_rawDescGZIP(), []int{18} + return file_history_events_proto_rawDescGZIP(), []int{19} } func (x *EventRaisedEvent) GetName() string { @@ -1373,7 +1426,7 @@ type ContinueAsNewEvent struct { func (x *ContinueAsNewEvent) Reset() { *x = ContinueAsNewEvent{} if protoimpl.UnsafeEnabled { - mi := &file_history_events_proto_msgTypes[19] + mi := &file_history_events_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1386,7 +1439,7 @@ func (x *ContinueAsNewEvent) String() string { func (*ContinueAsNewEvent) ProtoMessage() {} func (x *ContinueAsNewEvent) ProtoReflect() protoreflect.Message { - mi := &file_history_events_proto_msgTypes[19] + mi := &file_history_events_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1399,7 +1452,7 @@ func (x *ContinueAsNewEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use ContinueAsNewEvent.ProtoReflect.Descriptor instead. func (*ContinueAsNewEvent) Descriptor() ([]byte, []int) { - return file_history_events_proto_rawDescGZIP(), []int{19} + return file_history_events_proto_rawDescGZIP(), []int{20} } func (x *ContinueAsNewEvent) GetInput() *wrapperspb.StringValue { @@ -1420,7 +1473,7 @@ type ExecutionSuspendedEvent struct { func (x *ExecutionSuspendedEvent) Reset() { *x = ExecutionSuspendedEvent{} if protoimpl.UnsafeEnabled { - mi := &file_history_events_proto_msgTypes[20] + mi := &file_history_events_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1433,7 +1486,7 @@ func (x *ExecutionSuspendedEvent) String() string { func (*ExecutionSuspendedEvent) ProtoMessage() {} func (x *ExecutionSuspendedEvent) ProtoReflect() protoreflect.Message { - mi := &file_history_events_proto_msgTypes[20] + mi := &file_history_events_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1446,7 +1499,7 @@ func (x *ExecutionSuspendedEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionSuspendedEvent.ProtoReflect.Descriptor instead. func (*ExecutionSuspendedEvent) Descriptor() ([]byte, []int) { - return file_history_events_proto_rawDescGZIP(), []int{20} + return file_history_events_proto_rawDescGZIP(), []int{21} } func (x *ExecutionSuspendedEvent) GetInput() *wrapperspb.StringValue { @@ -1467,7 +1520,7 @@ type ExecutionResumedEvent struct { func (x *ExecutionResumedEvent) Reset() { *x = ExecutionResumedEvent{} if protoimpl.UnsafeEnabled { - mi := &file_history_events_proto_msgTypes[21] + mi := &file_history_events_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1480,7 +1533,7 @@ func (x *ExecutionResumedEvent) String() string { func (*ExecutionResumedEvent) ProtoMessage() {} func (x *ExecutionResumedEvent) ProtoReflect() protoreflect.Message { - mi := &file_history_events_proto_msgTypes[21] + mi := &file_history_events_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1493,7 +1546,7 @@ func (x *ExecutionResumedEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionResumedEvent.ProtoReflect.Descriptor instead. func (*ExecutionResumedEvent) Descriptor() ([]byte, []int) { - return file_history_events_proto_rawDescGZIP(), []int{21} + return file_history_events_proto_rawDescGZIP(), []int{22} } func (x *ExecutionResumedEvent) GetInput() *wrapperspb.StringValue { @@ -1515,7 +1568,7 @@ type ExecutionStalledEvent struct { func (x *ExecutionStalledEvent) Reset() { *x = ExecutionStalledEvent{} if protoimpl.UnsafeEnabled { - mi := &file_history_events_proto_msgTypes[22] + mi := &file_history_events_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1528,7 +1581,7 @@ func (x *ExecutionStalledEvent) String() string { func (*ExecutionStalledEvent) ProtoMessage() {} func (x *ExecutionStalledEvent) ProtoReflect() protoreflect.Message { - mi := &file_history_events_proto_msgTypes[22] + mi := &file_history_events_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1541,7 +1594,7 @@ func (x *ExecutionStalledEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionStalledEvent.ProtoReflect.Descriptor instead. func (*ExecutionStalledEvent) Descriptor() ([]byte, []int) { - return file_history_events_proto_rawDescGZIP(), []int{22} + return file_history_events_proto_rawDescGZIP(), []int{23} } func (x *ExecutionStalledEvent) GetReason() StalledReason { @@ -1586,6 +1639,7 @@ type HistoryEvent struct { // *HistoryEvent_ExecutionSuspended // *HistoryEvent_ExecutionResumed // *HistoryEvent_ExecutionStalled + // *HistoryEvent_DetachedWorkflowInstanceCreated EventType isHistoryEvent_EventType `protobuf_oneof:"eventType"` Router *TaskRouter `protobuf:"bytes,30,opt,name=router,proto3,oneof" json:"router,omitempty"` } @@ -1593,7 +1647,7 @@ type HistoryEvent struct { func (x *HistoryEvent) Reset() { *x = HistoryEvent{} if protoimpl.UnsafeEnabled { - mi := &file_history_events_proto_msgTypes[23] + mi := &file_history_events_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1606,7 +1660,7 @@ func (x *HistoryEvent) String() string { func (*HistoryEvent) ProtoMessage() {} func (x *HistoryEvent) ProtoReflect() protoreflect.Message { - mi := &file_history_events_proto_msgTypes[23] + mi := &file_history_events_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1619,7 +1673,7 @@ func (x *HistoryEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use HistoryEvent.ProtoReflect.Descriptor instead. func (*HistoryEvent) Descriptor() ([]byte, []int) { - return file_history_events_proto_rawDescGZIP(), []int{23} + return file_history_events_proto_rawDescGZIP(), []int{24} } func (x *HistoryEvent) GetEventId() int32 { @@ -1776,6 +1830,13 @@ func (x *HistoryEvent) GetExecutionStalled() *ExecutionStalledEvent { return nil } +func (x *HistoryEvent) GetDetachedWorkflowInstanceCreated() *DetachedWorkflowInstanceCreatedEvent { + if x, ok := x.GetEventType().(*HistoryEvent_DetachedWorkflowInstanceCreated); ok { + return x.DetachedWorkflowInstanceCreated + } + return nil +} + func (x *HistoryEvent) GetRouter() *TaskRouter { if x != nil { return x.Router @@ -1863,6 +1924,10 @@ type HistoryEvent_ExecutionStalled struct { ExecutionStalled *ExecutionStalledEvent `protobuf:"bytes,31,opt,name=executionStalled,proto3,oneof"` } +type HistoryEvent_DetachedWorkflowInstanceCreated struct { + DetachedWorkflowInstanceCreated *DetachedWorkflowInstanceCreatedEvent `protobuf:"bytes,32,opt,name=detachedWorkflowInstanceCreated,proto3,oneof"` +} + func (*HistoryEvent_ExecutionStarted) isHistoryEvent_EventType() {} func (*HistoryEvent_ExecutionCompleted) isHistoryEvent_EventType() {} @@ -1901,6 +1966,8 @@ func (*HistoryEvent_ExecutionResumed) isHistoryEvent_EventType() {} func (*HistoryEvent_ExecutionStalled) isHistoryEvent_EventType() {} +func (*HistoryEvent_DetachedWorkflowInstanceCreated) isHistoryEvent_EventType() {} + // A self-contained range of events produced by a single app, used when // history from multiple workflows is propagated to a downstream workflow // or activity. Each chunk owns the raw event bytes its producer signed; @@ -1911,40 +1978,38 @@ type PropagatedHistoryChunk struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Raw deterministic bytes of each HistoryEvent in this chunk, in - // execution order. The producer marshals each event once and signs - // over these exact bytes; receivers digest them directly and never - // re-marshal, so chunk verification is independent of protobuf - // marshaler-version stability across producer and receiver. This - // mirrors the approach attestations use for ioDigest: signed bytes - // travel verbatim end-to-end. The chunk's length is len(rawEvents). + // Raw deterministic bytes of each HistoryEvent in this chunk, in execution + // order. The producer marshals each event once and signs over these exact + // bytes; receivers digest them directly and never re-marshal, so chunk + // verification is independent of protobuf marshaler-version stability + // across producer and receiver. This mirrors the approach attestations use + // for ioDigest: signed bytes travel verbatim end-to-end. The chunk's + // length is len(rawEvents). RawEvents [][]byte `protobuf:"bytes,1,rep,name=rawEvents,proto3" json:"rawEvents,omitempty"` AppId string `protobuf:"bytes,2,opt,name=appId,proto3" json:"appId,omitempty"` // The workflow instance ID/name that produced the events in this chunk. InstanceId string `protobuf:"bytes,3,opt,name=instanceId,proto3" json:"instanceId,omitempty"` WorkflowName string `protobuf:"bytes,4,opt,name=workflowName,proto3" json:"workflowName,omitempty"` - // Raw deterministic bytes of each HistorySignature message produced - // by the chunk's app at dispatch time, covering rawEvents in order. - // Receivers unmarshal these on demand to verify the chain. Raw bytes - // are required because HistorySignature.previousSignatureDigest - // commits to the exact persisted serialization; re-marshaling on the - // wire would break chain linkage. See backend_service.proto: - // HistorySignature. + // Raw deterministic bytes of each HistorySignature message produced by the + // chunk's app at dispatch time, covering rawEvents in order. Receivers + // unmarshal these on demand to verify the chain. Raw bytes are required + // because HistorySignature.previousSignatureDigest commits to the exact + // persisted serialization; re-marshaling on the wire would break chain + // linkage. See backend_service.proto: HistorySignature. RawSignatures [][]byte `protobuf:"bytes,5,rep,name=rawSignatures,proto3" json:"rawSignatures,omitempty"` // X.509 certificate chains of the chunk app's signing identities, // DER-concatenated leaf-first then intermediates (same encoding as // backend_service.proto: SigningCertificate.certificate). Each - // HistorySignature in rawSignatures has a certificateIndex that - // indexes into this list, scoped to the chunk's producer app. Raw - // bytes here avoid a circular import on backend_service.proto's - // SigningCertificate type. + // HistorySignature in rawSignatures has a certificateIndex that indexes + // into this list, scoped to the chunk's producer app. Raw bytes here avoid + // a circular import on backend_service.proto's SigningCertificate type. SigningCertChains [][]byte `protobuf:"bytes,6,rep,name=signingCertChains,proto3" json:"signingCertChains,omitempty"` } func (x *PropagatedHistoryChunk) Reset() { *x = PropagatedHistoryChunk{} if protoimpl.UnsafeEnabled { - mi := &file_history_events_proto_msgTypes[24] + mi := &file_history_events_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1957,7 +2022,7 @@ func (x *PropagatedHistoryChunk) String() string { func (*PropagatedHistoryChunk) ProtoMessage() {} func (x *PropagatedHistoryChunk) ProtoReflect() protoreflect.Message { - mi := &file_history_events_proto_msgTypes[24] + mi := &file_history_events_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1970,7 +2035,7 @@ func (x *PropagatedHistoryChunk) ProtoReflect() protoreflect.Message { // Deprecated: Use PropagatedHistoryChunk.ProtoReflect.Descriptor instead. func (*PropagatedHistoryChunk) Descriptor() ([]byte, []int) { - return file_history_events_proto_rawDescGZIP(), []int{24} + return file_history_events_proto_rawDescGZIP(), []int{25} } func (x *PropagatedHistoryChunk) GetRawEvents() [][]byte { @@ -2022,18 +2087,18 @@ type PropagatedHistory struct { // The propagation scope that was used to produce this history. Scope HistoryPropagationScope `protobuf:"varint,1,opt,name=scope,proto3,enum=HistoryPropagationScope" json:"scope,omitempty"` - // Per-app history chunks. Each chunk owns the raw event bytes its - // producer signed (PropagatedHistoryChunk.rawEvents); receivers - // digest those bytes directly and decode them into typed - // HistoryEvents on demand. Chunks are ordered, non-overlapping, and - // together describe the full propagated event sequence. + // Per-app history chunks. Each chunk owns the raw event bytes its producer + // signed (PropagatedHistoryChunk.rawEvents); receivers digest those bytes + // directly and decode them into typed HistoryEvents on demand. Chunks are + // ordered, non-overlapping, and together describe the full propagated + // event sequence. Chunks []*PropagatedHistoryChunk `protobuf:"bytes,2,rep,name=chunks,proto3" json:"chunks,omitempty"` } func (x *PropagatedHistory) Reset() { *x = PropagatedHistory{} if protoimpl.UnsafeEnabled { - mi := &file_history_events_proto_msgTypes[25] + mi := &file_history_events_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2046,7 +2111,7 @@ func (x *PropagatedHistory) String() string { func (*PropagatedHistory) ProtoMessage() {} func (x *PropagatedHistory) ProtoReflect() protoreflect.Message { - mi := &file_history_events_proto_msgTypes[25] + mi := &file_history_events_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2059,7 +2124,7 @@ func (x *PropagatedHistory) ProtoReflect() protoreflect.Message { // Deprecated: Use PropagatedHistory.ProtoReflect.Descriptor instead. func (*PropagatedHistory) Descriptor() ([]byte, []int) { - return file_history_events_proto_rawDescGZIP(), []int{25} + return file_history_events_proto_rawDescGZIP(), []int{26} } func (x *PropagatedHistory) GetScope() HistoryPropagationScope { @@ -2283,226 +2348,238 @@ var file_history_events_proto_rawDesc = []byte{ 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x22, 0x18, 0x0a, 0x16, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, 0x67, - 0x69, 0x6e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x22, 0x2e, 0x0a, - 0x18, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x45, 0x78, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x44, 0x0a, - 0x18, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x41, 0x63, 0x74, 0x69, - 0x76, 0x69, 0x74, 0x79, 0x52, 0x65, 0x74, 0x72, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x74, 0x61, 0x73, - 0x6b, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0f, 0x74, 0x61, 0x73, 0x6b, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x22, 0x3f, 0x0a, 0x1d, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, 0x67, - 0x69, 0x6e, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, - 0x65, 0x74, 0x72, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x49, 0x64, 0x22, 0xfd, 0x03, 0x0a, 0x11, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x06, 0x66, 0x69, - 0x72, 0x65, 0x41, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x06, 0x66, 0x69, 0x72, 0x65, 0x41, 0x74, 0x12, 0x17, - 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x57, 0x0a, 0x17, 0x72, 0x65, 0x72, 0x75, 0x6e, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x6e, - 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x52, 0x65, 0x72, 0x75, 0x6e, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x6e, - 0x66, 0x6f, 0x48, 0x02, 0x52, 0x17, 0x72, 0x65, 0x72, 0x75, 0x6e, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x88, 0x01, 0x01, - 0x12, 0x3b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, - 0x67, 0x69, 0x6e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x48, 0x00, - 0x52, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x41, 0x0a, - 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, 0x67, - 0x69, 0x6e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, - 0x00, 0x52, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x12, 0x41, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x52, 0x65, 0x74, 0x72, - 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, - 0x72, 0x69, 0x67, 0x69, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x52, 0x65, 0x74, - 0x72, 0x79, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x52, 0x65, - 0x74, 0x72, 0x79, 0x12, 0x50, 0x0a, 0x12, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, - 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x74, 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1e, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x43, 0x68, 0x69, - 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x74, 0x72, 0x79, 0x48, - 0x00, 0x52, 0x12, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, - 0x52, 0x65, 0x74, 0x72, 0x79, 0x42, 0x08, 0x0a, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x42, - 0x07, 0x0a, 0x05, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x72, 0x65, 0x72, - 0x75, 0x6e, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x5f, 0x0a, 0x0f, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x46, 0x69, 0x72, - 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x06, 0x66, 0x69, 0x72, 0x65, 0x41, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x52, 0x06, 0x66, 0x69, 0x72, 0x65, 0x41, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x74, - 0x69, 0x6d, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x74, 0x69, - 0x6d, 0x65, 0x72, 0x49, 0x64, 0x22, 0x53, 0x0a, 0x14, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, - 0x77, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2f, 0x0a, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, - 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x48, 0x00, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x0a, - 0x0a, 0x08, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x18, 0x0a, 0x16, 0x57, 0x6f, - 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x22, 0x78, 0x0a, 0x0e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6e, - 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x69, 0x6e, - 0x70, 0x75, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, - 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x22, 0x5a, - 0x0a, 0x10, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x61, 0x69, 0x73, 0x65, 0x64, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x22, 0x48, 0x0a, 0x12, 0x43, 0x6f, - 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x41, 0x73, 0x4e, 0x65, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x12, 0x32, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x69, - 0x6e, 0x70, 0x75, 0x74, 0x22, 0x4d, 0x0a, 0x17, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x75, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, - 0x32, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, + 0x61, 0x74, 0x65, 0x22, 0x46, 0x0a, 0x24, 0x44, 0x65, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x57, + 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x22, 0x18, 0x0a, 0x16, 0x54, + 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x72, 0x22, 0x2e, 0x0a, 0x18, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, + 0x69, 0x67, 0x69, 0x6e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x44, 0x0a, 0x18, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, + 0x69, 0x67, 0x69, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x52, 0x65, 0x74, 0x72, + 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x74, 0x61, 0x73, 0x6b, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x61, 0x73, 0x6b, + 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x3f, 0x0a, 0x1d, 0x54, + 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x57, + 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x74, 0x72, 0x79, 0x12, 0x1e, 0x0a, 0x0a, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x22, 0xfd, 0x03, 0x0a, + 0x11, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x06, 0x66, 0x69, 0x72, 0x65, 0x41, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x06, + 0x66, 0x69, 0x72, 0x65, 0x41, 0x74, 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, + 0x57, 0x0a, 0x17, 0x72, 0x65, 0x72, 0x75, 0x6e, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x18, 0x2e, 0x52, 0x65, 0x72, 0x75, 0x6e, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x02, 0x52, 0x17, 0x72, 0x65, + 0x72, 0x75, 0x6e, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x88, 0x01, 0x01, 0x12, 0x3b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x41, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x69, + 0x76, 0x69, 0x74, 0x79, 0x52, 0x65, 0x74, 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x19, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x41, 0x63, 0x74, + 0x69, 0x76, 0x69, 0x74, 0x79, 0x52, 0x65, 0x74, 0x72, 0x79, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x52, 0x65, 0x74, 0x72, 0x79, 0x12, 0x50, 0x0a, 0x12, 0x63, + 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x74, 0x72, + 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, + 0x72, 0x69, 0x67, 0x69, 0x6e, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, + 0x6f, 0x77, 0x52, 0x65, 0x74, 0x72, 0x79, 0x48, 0x00, 0x52, 0x12, 0x63, 0x68, 0x69, 0x6c, 0x64, + 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x74, 0x72, 0x79, 0x42, 0x08, 0x0a, + 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x72, 0x65, 0x72, 0x75, 0x6e, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x5f, 0x0a, 0x0f, + 0x54, 0x69, 0x6d, 0x65, 0x72, 0x46, 0x69, 0x72, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, + 0x32, 0x0a, 0x06, 0x66, 0x69, 0x72, 0x65, 0x41, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x06, 0x66, 0x69, 0x72, + 0x65, 0x41, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x49, 0x64, 0x22, 0x53, 0x0a, + 0x14, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2f, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, + 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x22, 0x18, 0x0a, 0x16, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, + 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x78, 0x0a, 0x0e, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1e, + 0x0a, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, + 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x22, 0x5a, 0x0a, 0x10, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, + 0x61, 0x69, 0x73, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x32, + 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x70, + 0x75, 0x74, 0x22, 0x48, 0x0a, 0x12, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x41, 0x73, + 0x4e, 0x65, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x22, 0x4d, 0x0a, 0x17, + 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x75, 0x73, 0x70, 0x65, 0x6e, 0x64, + 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x22, 0x4b, 0x0a, 0x15, 0x45, + 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x22, 0x76, 0x0a, 0x15, 0x45, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x12, 0x26, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x0e, 0x2e, 0x53, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, + 0x6e, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0b, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, + 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0x94, 0x0d, 0x0a, 0x0c, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x69, 0x6e, - 0x70, 0x75, 0x74, 0x22, 0x4b, 0x0a, 0x15, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x05, - 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, - 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, - 0x22, 0x76, 0x0a, 0x15, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, - 0x6c, 0x6c, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x06, 0x72, 0x65, 0x61, - 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x53, 0x74, 0x61, 0x6c, - 0x6c, 0x65, 0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, - 0x6e, 0x12, 0x25, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xa1, 0x0c, 0x0a, 0x0c, 0x48, 0x69, 0x73, - 0x74, 0x6f, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x44, 0x0a, - 0x10, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, - 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, - 0x00, 0x52, 0x10, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x72, - 0x74, 0x65, 0x64, 0x12, 0x4a, 0x0a, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, - 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x18, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, - 0x65, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x12, 0x65, 0x78, 0x65, - 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, - 0x4d, 0x0a, 0x13, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x72, 0x6d, - 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x45, - 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, - 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x13, 0x65, 0x78, 0x65, 0x63, 0x75, - 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x12, 0x3b, - 0x0a, 0x0d, 0x74, 0x61, 0x73, 0x6b, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x63, 0x68, 0x65, - 0x64, 0x75, 0x6c, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x74, 0x61, - 0x73, 0x6b, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x12, 0x3b, 0x0a, 0x0d, 0x74, - 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, - 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x74, 0x61, 0x73, 0x6b, 0x43, - 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x32, 0x0a, 0x0a, 0x74, 0x61, 0x73, 0x6b, - 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x54, - 0x61, 0x73, 0x6b, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, - 0x52, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x12, 0x68, 0x0a, 0x1c, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x44, 0x0a, 0x10, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x10, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x12, 0x4a, 0x0a, 0x12, 0x65, + 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, + 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x48, 0x00, 0x52, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, + 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x4d, 0x0a, 0x13, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, + 0x00, 0x52, 0x13, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x72, 0x6d, + 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x12, 0x3b, 0x0a, 0x0d, 0x74, 0x61, 0x73, 0x6b, 0x53, 0x63, + 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x54, 0x61, 0x73, 0x6b, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x74, 0x61, 0x73, 0x6b, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, + 0x6c, 0x65, 0x64, 0x12, 0x3b, 0x0a, 0x0d, 0x74, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x74, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x54, 0x61, 0x73, + 0x6b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, + 0x00, 0x52, 0x0d, 0x74, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, + 0x12, 0x32, 0x0a, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x46, 0x61, 0x69, 0x6c, 0x65, + 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x46, 0x61, + 0x69, 0x6c, 0x65, 0x64, 0x12, 0x68, 0x0a, 0x1c, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, + 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x43, 0x68, 0x69, + 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, + 0x52, 0x1c, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x6e, + 0x0a, 0x1e, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, + 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, + 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1e, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, - 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1c, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x57, - 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x6e, 0x0a, 0x1e, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x57, - 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, - 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, - 0x2e, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1e, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, - 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6d, - 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x65, 0x0a, 0x1b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x57, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x65, + 0x0a, 0x1b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x18, 0x0b, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, + 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x46, 0x61, 0x69, 0x6c, 0x65, + 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x46, - 0x61, 0x69, 0x6c, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x43, 0x68, - 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x74, 0x61, - 0x6e, 0x63, 0x65, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, - 0x52, 0x1b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x12, 0x38, 0x0a, - 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0c, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x72, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x32, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x72, - 0x46, 0x69, 0x72, 0x65, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x72, 0x46, 0x69, 0x72, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, - 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x46, 0x69, 0x72, 0x65, 0x64, 0x12, 0x41, 0x0a, 0x0f, 0x77, - 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x18, 0x0e, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, - 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0f, 0x77, - 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x12, 0x47, - 0x0a, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, - 0x74, 0x65, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x57, 0x6f, 0x72, 0x6b, - 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x48, 0x00, 0x52, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, - 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x2f, 0x0a, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x53, 0x65, 0x6e, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x09, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x0b, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x52, 0x61, 0x69, 0x73, 0x65, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x61, 0x69, 0x73, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x48, 0x00, 0x52, 0x0b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x61, 0x69, 0x73, 0x65, 0x64, 0x12, - 0x3b, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x41, 0x73, 0x4e, 0x65, 0x77, - 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, - 0x65, 0x41, 0x73, 0x4e, 0x65, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x63, - 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x41, 0x73, 0x4e, 0x65, 0x77, 0x12, 0x4a, 0x0a, 0x12, - 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x75, 0x73, 0x70, 0x65, 0x6e, 0x64, - 0x65, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, - 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x75, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x48, 0x00, 0x52, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x53, - 0x75, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x12, 0x44, 0x0a, 0x10, 0x65, 0x78, 0x65, 0x63, - 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x18, 0x16, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x75, 0x6d, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x10, 0x65, 0x78, - 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x12, 0x44, - 0x0a, 0x10, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x6c, 0x6c, - 0x65, 0x64, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, - 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x48, 0x00, 0x52, 0x10, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, - 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x28, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x18, 0x1e, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x6f, 0x75, 0x74, 0x65, - 0x72, 0x48, 0x01, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x88, 0x01, 0x01, 0x42, 0x0b, - 0x0a, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x5f, - 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x4a, 0x04, 0x08, 0x12, 0x10, 0x13, 0x4a, 0x04, 0x08, 0x13, - 0x10, 0x14, 0x4a, 0x04, 0x08, 0x17, 0x10, 0x18, 0x4a, 0x04, 0x08, 0x18, 0x10, 0x19, 0x4a, 0x04, - 0x08, 0x19, 0x10, 0x1a, 0x4a, 0x04, 0x08, 0x1a, 0x10, 0x1b, 0x4a, 0x04, 0x08, 0x1b, 0x10, 0x1c, - 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, 0x1d, 0x10, 0x1e, 0x22, 0xe4, 0x01, 0x0a, - 0x16, 0x50, 0x72, 0x6f, 0x70, 0x61, 0x67, 0x61, 0x74, 0x65, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, - 0x72, 0x79, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x61, 0x77, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x72, 0x61, 0x77, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x77, - 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x24, 0x0a, 0x0d, 0x72, 0x61, 0x77, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, - 0x18, 0x05, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0d, 0x72, 0x61, 0x77, 0x53, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, - 0x43, 0x65, 0x72, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0c, - 0x52, 0x11, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x43, 0x68, 0x61, - 0x69, 0x6e, 0x73, 0x22, 0x74, 0x0a, 0x11, 0x50, 0x72, 0x6f, 0x70, 0x61, 0x67, 0x61, 0x74, 0x65, - 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x2e, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, - 0x79, 0x50, 0x72, 0x6f, 0x70, 0x61, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x6f, 0x70, - 0x65, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x68, 0x75, 0x6e, - 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x61, - 0x67, 0x61, 0x74, 0x65, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x43, 0x68, 0x75, 0x6e, - 0x6b, 0x52, 0x06, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x42, 0x56, 0x0a, 0x2b, 0x69, 0x6f, 0x2e, - 0x64, 0x61, 0x70, 0x72, 0x2e, 0x64, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x61, 0x73, 0x6b, - 0x2e, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x5a, 0x0b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x73, 0xaa, 0x02, 0x19, 0x44, 0x61, 0x70, 0x72, 0x2e, 0x44, 0x75, 0x72, - 0x61, 0x62, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x69, 0x6c, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, + 0x00, 0x52, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, + 0x32, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x46, 0x69, 0x72, 0x65, 0x64, 0x18, 0x0d, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x46, 0x69, 0x72, 0x65, 0x64, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x46, 0x69, + 0x72, 0x65, 0x64, 0x12, 0x41, 0x0a, 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, + 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x57, + 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, + 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x12, 0x47, 0x0a, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, + 0x6f, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x11, 0x77, 0x6f, + 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, + 0x2f, 0x0a, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x18, 0x10, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x6e, 0x74, + 0x12, 0x35, 0x0a, 0x0b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x61, 0x69, 0x73, 0x65, 0x64, 0x18, + 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x61, 0x69, + 0x73, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x52, 0x61, 0x69, 0x73, 0x65, 0x64, 0x12, 0x3b, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x69, + 0x6e, 0x75, 0x65, 0x41, 0x73, 0x4e, 0x65, 0x77, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, + 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x41, 0x73, 0x4e, 0x65, 0x77, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x41, + 0x73, 0x4e, 0x65, 0x77, 0x12, 0x4a, 0x0a, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x53, 0x75, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x18, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x75, 0x73, 0x70, + 0x65, 0x6e, 0x64, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x12, 0x65, 0x78, + 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x75, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, + 0x12, 0x44, 0x0a, 0x10, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, + 0x75, 0x6d, 0x65, 0x64, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x45, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x48, 0x00, 0x52, 0x10, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x12, 0x44, 0x0a, 0x10, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x6c, + 0x6c, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x10, 0x65, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x71, 0x0a, 0x1f, + 0x64, 0x65, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, + 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, + 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x44, 0x65, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, + 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1f, + 0x64, 0x65, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, + 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, + 0x28, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0b, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x48, 0x01, 0x52, 0x06, + 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, + 0x72, 0x4a, 0x04, 0x08, 0x12, 0x10, 0x13, 0x4a, 0x04, 0x08, 0x13, 0x10, 0x14, 0x4a, 0x04, 0x08, + 0x17, 0x10, 0x18, 0x4a, 0x04, 0x08, 0x18, 0x10, 0x19, 0x4a, 0x04, 0x08, 0x19, 0x10, 0x1a, 0x4a, + 0x04, 0x08, 0x1a, 0x10, 0x1b, 0x4a, 0x04, 0x08, 0x1b, 0x10, 0x1c, 0x4a, 0x04, 0x08, 0x1c, 0x10, + 0x1d, 0x4a, 0x04, 0x08, 0x1d, 0x10, 0x1e, 0x22, 0xe4, 0x01, 0x0a, 0x16, 0x50, 0x72, 0x6f, 0x70, + 0x61, 0x67, 0x61, 0x74, 0x65, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x43, 0x68, 0x75, + 0x6e, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x61, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x72, 0x61, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0x12, 0x14, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, + 0x6f, 0x77, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x6f, + 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x61, + 0x77, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, + 0x0c, 0x52, 0x0d, 0x72, 0x61, 0x77, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, + 0x12, 0x2c, 0x0a, 0x11, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x43, + 0x68, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x11, 0x73, 0x69, 0x67, + 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x22, 0x74, + 0x0a, 0x11, 0x50, 0x72, 0x6f, 0x70, 0x61, 0x67, 0x61, 0x74, 0x65, 0x64, 0x48, 0x69, 0x73, 0x74, + 0x6f, 0x72, 0x79, 0x12, 0x2e, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x70, + 0x61, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x05, 0x73, 0x63, + 0x6f, 0x70, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x61, 0x67, 0x61, 0x74, 0x65, 0x64, + 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x06, 0x63, 0x68, + 0x75, 0x6e, 0x6b, 0x73, 0x42, 0x56, 0x0a, 0x2b, 0x69, 0x6f, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, + 0x64, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x69, 0x6d, 0x70, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x5a, 0x0b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, + 0xaa, 0x02, 0x19, 0x44, 0x61, 0x70, 0x72, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x54, + 0x61, 0x73, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2517,96 +2594,97 @@ func file_history_events_proto_rawDescGZIP() []byte { return file_history_events_proto_rawDescData } -var file_history_events_proto_msgTypes = make([]protoimpl.MessageInfo, 27) +var file_history_events_proto_msgTypes = make([]protoimpl.MessageInfo, 28) var file_history_events_proto_goTypes = []interface{}{ - (*ExecutionStartedEvent)(nil), // 0: ExecutionStartedEvent - (*ExecutionCompletedEvent)(nil), // 1: ExecutionCompletedEvent - (*ExecutionTerminatedEvent)(nil), // 2: ExecutionTerminatedEvent - (*TaskScheduledEvent)(nil), // 3: TaskScheduledEvent - (*TaskCompletedEvent)(nil), // 4: TaskCompletedEvent - (*TaskFailedEvent)(nil), // 5: TaskFailedEvent - (*ChildWorkflowInstanceCreatedEvent)(nil), // 6: ChildWorkflowInstanceCreatedEvent - (*ChildWorkflowInstanceCompletedEvent)(nil), // 7: ChildWorkflowInstanceCompletedEvent - (*ChildWorkflowInstanceFailedEvent)(nil), // 8: ChildWorkflowInstanceFailedEvent - (*TimerOriginCreateTimer)(nil), // 9: TimerOriginCreateTimer - (*TimerOriginExternalEvent)(nil), // 10: TimerOriginExternalEvent - (*TimerOriginActivityRetry)(nil), // 11: TimerOriginActivityRetry - (*TimerOriginChildWorkflowRetry)(nil), // 12: TimerOriginChildWorkflowRetry - (*TimerCreatedEvent)(nil), // 13: TimerCreatedEvent - (*TimerFiredEvent)(nil), // 14: TimerFiredEvent - (*WorkflowStartedEvent)(nil), // 15: WorkflowStartedEvent - (*WorkflowCompletedEvent)(nil), // 16: WorkflowCompletedEvent - (*EventSentEvent)(nil), // 17: EventSentEvent - (*EventRaisedEvent)(nil), // 18: EventRaisedEvent - (*ContinueAsNewEvent)(nil), // 19: ContinueAsNewEvent - (*ExecutionSuspendedEvent)(nil), // 20: ExecutionSuspendedEvent - (*ExecutionResumedEvent)(nil), // 21: ExecutionResumedEvent - (*ExecutionStalledEvent)(nil), // 22: ExecutionStalledEvent - (*HistoryEvent)(nil), // 23: HistoryEvent - (*PropagatedHistoryChunk)(nil), // 24: PropagatedHistoryChunk - (*PropagatedHistory)(nil), // 25: PropagatedHistory - nil, // 26: ExecutionStartedEvent.TagsEntry - (*wrapperspb.StringValue)(nil), // 27: google.protobuf.StringValue - (*WorkflowInstance)(nil), // 28: WorkflowInstance - (*ParentInstanceInfo)(nil), // 29: ParentInstanceInfo - (*timestamppb.Timestamp)(nil), // 30: google.protobuf.Timestamp - (*TraceContext)(nil), // 31: TraceContext - (OrchestrationStatus)(0), // 32: OrchestrationStatus - (*TaskFailureDetails)(nil), // 33: TaskFailureDetails - (*RerunParentInstanceInfo)(nil), // 34: RerunParentInstanceInfo - (HistoryPropagationScope)(0), // 35: HistoryPropagationScope - (*ActivityCompletionAttestation)(nil), // 36: ActivityCompletionAttestation - (*ChildCompletionAttestation)(nil), // 37: ChildCompletionAttestation - (*WorkflowVersion)(nil), // 38: WorkflowVersion - (StalledReason)(0), // 39: StalledReason - (*TaskRouter)(nil), // 40: TaskRouter + (*ExecutionStartedEvent)(nil), // 0: ExecutionStartedEvent + (*ExecutionCompletedEvent)(nil), // 1: ExecutionCompletedEvent + (*ExecutionTerminatedEvent)(nil), // 2: ExecutionTerminatedEvent + (*TaskScheduledEvent)(nil), // 3: TaskScheduledEvent + (*TaskCompletedEvent)(nil), // 4: TaskCompletedEvent + (*TaskFailedEvent)(nil), // 5: TaskFailedEvent + (*ChildWorkflowInstanceCreatedEvent)(nil), // 6: ChildWorkflowInstanceCreatedEvent + (*ChildWorkflowInstanceCompletedEvent)(nil), // 7: ChildWorkflowInstanceCompletedEvent + (*ChildWorkflowInstanceFailedEvent)(nil), // 8: ChildWorkflowInstanceFailedEvent + (*DetachedWorkflowInstanceCreatedEvent)(nil), // 9: DetachedWorkflowInstanceCreatedEvent + (*TimerOriginCreateTimer)(nil), // 10: TimerOriginCreateTimer + (*TimerOriginExternalEvent)(nil), // 11: TimerOriginExternalEvent + (*TimerOriginActivityRetry)(nil), // 12: TimerOriginActivityRetry + (*TimerOriginChildWorkflowRetry)(nil), // 13: TimerOriginChildWorkflowRetry + (*TimerCreatedEvent)(nil), // 14: TimerCreatedEvent + (*TimerFiredEvent)(nil), // 15: TimerFiredEvent + (*WorkflowStartedEvent)(nil), // 16: WorkflowStartedEvent + (*WorkflowCompletedEvent)(nil), // 17: WorkflowCompletedEvent + (*EventSentEvent)(nil), // 18: EventSentEvent + (*EventRaisedEvent)(nil), // 19: EventRaisedEvent + (*ContinueAsNewEvent)(nil), // 20: ContinueAsNewEvent + (*ExecutionSuspendedEvent)(nil), // 21: ExecutionSuspendedEvent + (*ExecutionResumedEvent)(nil), // 22: ExecutionResumedEvent + (*ExecutionStalledEvent)(nil), // 23: ExecutionStalledEvent + (*HistoryEvent)(nil), // 24: HistoryEvent + (*PropagatedHistoryChunk)(nil), // 25: PropagatedHistoryChunk + (*PropagatedHistory)(nil), // 26: PropagatedHistory + nil, // 27: ExecutionStartedEvent.TagsEntry + (*wrapperspb.StringValue)(nil), // 28: google.protobuf.StringValue + (*WorkflowInstance)(nil), // 29: WorkflowInstance + (*ParentInstanceInfo)(nil), // 30: ParentInstanceInfo + (*timestamppb.Timestamp)(nil), // 31: google.protobuf.Timestamp + (*TraceContext)(nil), // 32: TraceContext + (OrchestrationStatus)(0), // 33: OrchestrationStatus + (*TaskFailureDetails)(nil), // 34: TaskFailureDetails + (*RerunParentInstanceInfo)(nil), // 35: RerunParentInstanceInfo + (HistoryPropagationScope)(0), // 36: HistoryPropagationScope + (*ActivityCompletionAttestation)(nil), // 37: ActivityCompletionAttestation + (*ChildCompletionAttestation)(nil), // 38: ChildCompletionAttestation + (*WorkflowVersion)(nil), // 39: WorkflowVersion + (StalledReason)(0), // 40: StalledReason + (*TaskRouter)(nil), // 41: TaskRouter } var file_history_events_proto_depIdxs = []int32{ - 27, // 0: ExecutionStartedEvent.version:type_name -> google.protobuf.StringValue - 27, // 1: ExecutionStartedEvent.input:type_name -> google.protobuf.StringValue - 28, // 2: ExecutionStartedEvent.workflowInstance:type_name -> WorkflowInstance - 29, // 3: ExecutionStartedEvent.parentInstance:type_name -> ParentInstanceInfo - 30, // 4: ExecutionStartedEvent.scheduledStartTimestamp:type_name -> google.protobuf.Timestamp - 31, // 5: ExecutionStartedEvent.parentTraceContext:type_name -> TraceContext - 27, // 6: ExecutionStartedEvent.workflowSpanID:type_name -> google.protobuf.StringValue - 26, // 7: ExecutionStartedEvent.tags:type_name -> ExecutionStartedEvent.TagsEntry - 32, // 8: ExecutionCompletedEvent.workflowStatus:type_name -> OrchestrationStatus - 27, // 9: ExecutionCompletedEvent.result:type_name -> google.protobuf.StringValue - 33, // 10: ExecutionCompletedEvent.failureDetails:type_name -> TaskFailureDetails - 27, // 11: ExecutionTerminatedEvent.input:type_name -> google.protobuf.StringValue - 27, // 12: TaskScheduledEvent.version:type_name -> google.protobuf.StringValue - 27, // 13: TaskScheduledEvent.input:type_name -> google.protobuf.StringValue - 31, // 14: TaskScheduledEvent.parentTraceContext:type_name -> TraceContext - 34, // 15: TaskScheduledEvent.rerunParentInstanceInfo:type_name -> RerunParentInstanceInfo - 35, // 16: TaskScheduledEvent.historyPropagationScope:type_name -> HistoryPropagationScope - 27, // 17: TaskCompletedEvent.result:type_name -> google.protobuf.StringValue - 36, // 18: TaskCompletedEvent.attestation:type_name -> ActivityCompletionAttestation - 33, // 19: TaskFailedEvent.failureDetails:type_name -> TaskFailureDetails - 36, // 20: TaskFailedEvent.attestation:type_name -> ActivityCompletionAttestation - 27, // 21: ChildWorkflowInstanceCreatedEvent.version:type_name -> google.protobuf.StringValue - 27, // 22: ChildWorkflowInstanceCreatedEvent.input:type_name -> google.protobuf.StringValue - 31, // 23: ChildWorkflowInstanceCreatedEvent.parentTraceContext:type_name -> TraceContext - 34, // 24: ChildWorkflowInstanceCreatedEvent.rerunParentInstanceInfo:type_name -> RerunParentInstanceInfo - 35, // 25: ChildWorkflowInstanceCreatedEvent.historyPropagationScope:type_name -> HistoryPropagationScope - 27, // 26: ChildWorkflowInstanceCompletedEvent.result:type_name -> google.protobuf.StringValue - 37, // 27: ChildWorkflowInstanceCompletedEvent.attestation:type_name -> ChildCompletionAttestation - 33, // 28: ChildWorkflowInstanceFailedEvent.failureDetails:type_name -> TaskFailureDetails - 37, // 29: ChildWorkflowInstanceFailedEvent.attestation:type_name -> ChildCompletionAttestation - 30, // 30: TimerCreatedEvent.fireAt:type_name -> google.protobuf.Timestamp - 34, // 31: TimerCreatedEvent.rerunParentInstanceInfo:type_name -> RerunParentInstanceInfo - 9, // 32: TimerCreatedEvent.createTimer:type_name -> TimerOriginCreateTimer - 10, // 33: TimerCreatedEvent.externalEvent:type_name -> TimerOriginExternalEvent - 11, // 34: TimerCreatedEvent.activityRetry:type_name -> TimerOriginActivityRetry - 12, // 35: TimerCreatedEvent.childWorkflowRetry:type_name -> TimerOriginChildWorkflowRetry - 30, // 36: TimerFiredEvent.fireAt:type_name -> google.protobuf.Timestamp - 38, // 37: WorkflowStartedEvent.version:type_name -> WorkflowVersion - 27, // 38: EventSentEvent.input:type_name -> google.protobuf.StringValue - 27, // 39: EventRaisedEvent.input:type_name -> google.protobuf.StringValue - 27, // 40: ContinueAsNewEvent.input:type_name -> google.protobuf.StringValue - 27, // 41: ExecutionSuspendedEvent.input:type_name -> google.protobuf.StringValue - 27, // 42: ExecutionResumedEvent.input:type_name -> google.protobuf.StringValue - 39, // 43: ExecutionStalledEvent.reason:type_name -> StalledReason - 30, // 44: HistoryEvent.timestamp:type_name -> google.protobuf.Timestamp + 28, // 0: ExecutionStartedEvent.version:type_name -> google.protobuf.StringValue + 28, // 1: ExecutionStartedEvent.input:type_name -> google.protobuf.StringValue + 29, // 2: ExecutionStartedEvent.workflowInstance:type_name -> WorkflowInstance + 30, // 3: ExecutionStartedEvent.parentInstance:type_name -> ParentInstanceInfo + 31, // 4: ExecutionStartedEvent.scheduledStartTimestamp:type_name -> google.protobuf.Timestamp + 32, // 5: ExecutionStartedEvent.parentTraceContext:type_name -> TraceContext + 28, // 6: ExecutionStartedEvent.workflowSpanID:type_name -> google.protobuf.StringValue + 27, // 7: ExecutionStartedEvent.tags:type_name -> ExecutionStartedEvent.TagsEntry + 33, // 8: ExecutionCompletedEvent.workflowStatus:type_name -> OrchestrationStatus + 28, // 9: ExecutionCompletedEvent.result:type_name -> google.protobuf.StringValue + 34, // 10: ExecutionCompletedEvent.failureDetails:type_name -> TaskFailureDetails + 28, // 11: ExecutionTerminatedEvent.input:type_name -> google.protobuf.StringValue + 28, // 12: TaskScheduledEvent.version:type_name -> google.protobuf.StringValue + 28, // 13: TaskScheduledEvent.input:type_name -> google.protobuf.StringValue + 32, // 14: TaskScheduledEvent.parentTraceContext:type_name -> TraceContext + 35, // 15: TaskScheduledEvent.rerunParentInstanceInfo:type_name -> RerunParentInstanceInfo + 36, // 16: TaskScheduledEvent.historyPropagationScope:type_name -> HistoryPropagationScope + 28, // 17: TaskCompletedEvent.result:type_name -> google.protobuf.StringValue + 37, // 18: TaskCompletedEvent.attestation:type_name -> ActivityCompletionAttestation + 34, // 19: TaskFailedEvent.failureDetails:type_name -> TaskFailureDetails + 37, // 20: TaskFailedEvent.attestation:type_name -> ActivityCompletionAttestation + 28, // 21: ChildWorkflowInstanceCreatedEvent.version:type_name -> google.protobuf.StringValue + 28, // 22: ChildWorkflowInstanceCreatedEvent.input:type_name -> google.protobuf.StringValue + 32, // 23: ChildWorkflowInstanceCreatedEvent.parentTraceContext:type_name -> TraceContext + 35, // 24: ChildWorkflowInstanceCreatedEvent.rerunParentInstanceInfo:type_name -> RerunParentInstanceInfo + 36, // 25: ChildWorkflowInstanceCreatedEvent.historyPropagationScope:type_name -> HistoryPropagationScope + 28, // 26: ChildWorkflowInstanceCompletedEvent.result:type_name -> google.protobuf.StringValue + 38, // 27: ChildWorkflowInstanceCompletedEvent.attestation:type_name -> ChildCompletionAttestation + 34, // 28: ChildWorkflowInstanceFailedEvent.failureDetails:type_name -> TaskFailureDetails + 38, // 29: ChildWorkflowInstanceFailedEvent.attestation:type_name -> ChildCompletionAttestation + 31, // 30: TimerCreatedEvent.fireAt:type_name -> google.protobuf.Timestamp + 35, // 31: TimerCreatedEvent.rerunParentInstanceInfo:type_name -> RerunParentInstanceInfo + 10, // 32: TimerCreatedEvent.createTimer:type_name -> TimerOriginCreateTimer + 11, // 33: TimerCreatedEvent.externalEvent:type_name -> TimerOriginExternalEvent + 12, // 34: TimerCreatedEvent.activityRetry:type_name -> TimerOriginActivityRetry + 13, // 35: TimerCreatedEvent.childWorkflowRetry:type_name -> TimerOriginChildWorkflowRetry + 31, // 36: TimerFiredEvent.fireAt:type_name -> google.protobuf.Timestamp + 39, // 37: WorkflowStartedEvent.version:type_name -> WorkflowVersion + 28, // 38: EventSentEvent.input:type_name -> google.protobuf.StringValue + 28, // 39: EventRaisedEvent.input:type_name -> google.protobuf.StringValue + 28, // 40: ContinueAsNewEvent.input:type_name -> google.protobuf.StringValue + 28, // 41: ExecutionSuspendedEvent.input:type_name -> google.protobuf.StringValue + 28, // 42: ExecutionResumedEvent.input:type_name -> google.protobuf.StringValue + 40, // 43: ExecutionStalledEvent.reason:type_name -> StalledReason + 31, // 44: HistoryEvent.timestamp:type_name -> google.protobuf.Timestamp 0, // 45: HistoryEvent.executionStarted:type_name -> ExecutionStartedEvent 1, // 46: HistoryEvent.executionCompleted:type_name -> ExecutionCompletedEvent 2, // 47: HistoryEvent.executionTerminated:type_name -> ExecutionTerminatedEvent @@ -2616,24 +2694,25 @@ var file_history_events_proto_depIdxs = []int32{ 6, // 51: HistoryEvent.childWorkflowInstanceCreated:type_name -> ChildWorkflowInstanceCreatedEvent 7, // 52: HistoryEvent.childWorkflowInstanceCompleted:type_name -> ChildWorkflowInstanceCompletedEvent 8, // 53: HistoryEvent.childWorkflowInstanceFailed:type_name -> ChildWorkflowInstanceFailedEvent - 13, // 54: HistoryEvent.timerCreated:type_name -> TimerCreatedEvent - 14, // 55: HistoryEvent.timerFired:type_name -> TimerFiredEvent - 15, // 56: HistoryEvent.workflowStarted:type_name -> WorkflowStartedEvent - 16, // 57: HistoryEvent.workflowCompleted:type_name -> WorkflowCompletedEvent - 17, // 58: HistoryEvent.eventSent:type_name -> EventSentEvent - 18, // 59: HistoryEvent.eventRaised:type_name -> EventRaisedEvent - 19, // 60: HistoryEvent.continueAsNew:type_name -> ContinueAsNewEvent - 20, // 61: HistoryEvent.executionSuspended:type_name -> ExecutionSuspendedEvent - 21, // 62: HistoryEvent.executionResumed:type_name -> ExecutionResumedEvent - 22, // 63: HistoryEvent.executionStalled:type_name -> ExecutionStalledEvent - 40, // 64: HistoryEvent.router:type_name -> TaskRouter - 35, // 65: PropagatedHistory.scope:type_name -> HistoryPropagationScope - 24, // 66: PropagatedHistory.chunks:type_name -> PropagatedHistoryChunk - 67, // [67:67] is the sub-list for method output_type - 67, // [67:67] is the sub-list for method input_type - 67, // [67:67] is the sub-list for extension type_name - 67, // [67:67] is the sub-list for extension extendee - 0, // [0:67] is the sub-list for field type_name + 14, // 54: HistoryEvent.timerCreated:type_name -> TimerCreatedEvent + 15, // 55: HistoryEvent.timerFired:type_name -> TimerFiredEvent + 16, // 56: HistoryEvent.workflowStarted:type_name -> WorkflowStartedEvent + 17, // 57: HistoryEvent.workflowCompleted:type_name -> WorkflowCompletedEvent + 18, // 58: HistoryEvent.eventSent:type_name -> EventSentEvent + 19, // 59: HistoryEvent.eventRaised:type_name -> EventRaisedEvent + 20, // 60: HistoryEvent.continueAsNew:type_name -> ContinueAsNewEvent + 21, // 61: HistoryEvent.executionSuspended:type_name -> ExecutionSuspendedEvent + 22, // 62: HistoryEvent.executionResumed:type_name -> ExecutionResumedEvent + 23, // 63: HistoryEvent.executionStalled:type_name -> ExecutionStalledEvent + 9, // 64: HistoryEvent.detachedWorkflowInstanceCreated:type_name -> DetachedWorkflowInstanceCreatedEvent + 41, // 65: HistoryEvent.router:type_name -> TaskRouter + 36, // 66: PropagatedHistory.scope:type_name -> HistoryPropagationScope + 25, // 67: PropagatedHistory.chunks:type_name -> PropagatedHistoryChunk + 68, // [68:68] is the sub-list for method output_type + 68, // [68:68] is the sub-list for method input_type + 68, // [68:68] is the sub-list for extension type_name + 68, // [68:68] is the sub-list for extension extendee + 0, // [0:68] is the sub-list for field type_name } func init() { file_history_events_proto_init() } @@ -2753,7 +2832,7 @@ func file_history_events_proto_init() { } } file_history_events_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TimerOriginCreateTimer); i { + switch v := v.(*DetachedWorkflowInstanceCreatedEvent); i { case 0: return &v.state case 1: @@ -2765,7 +2844,7 @@ func file_history_events_proto_init() { } } file_history_events_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TimerOriginExternalEvent); i { + switch v := v.(*TimerOriginCreateTimer); i { case 0: return &v.state case 1: @@ -2777,7 +2856,7 @@ func file_history_events_proto_init() { } } file_history_events_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TimerOriginActivityRetry); i { + switch v := v.(*TimerOriginExternalEvent); i { case 0: return &v.state case 1: @@ -2789,7 +2868,7 @@ func file_history_events_proto_init() { } } file_history_events_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TimerOriginChildWorkflowRetry); i { + switch v := v.(*TimerOriginActivityRetry); i { case 0: return &v.state case 1: @@ -2801,7 +2880,7 @@ func file_history_events_proto_init() { } } file_history_events_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TimerCreatedEvent); i { + switch v := v.(*TimerOriginChildWorkflowRetry); i { case 0: return &v.state case 1: @@ -2813,7 +2892,7 @@ func file_history_events_proto_init() { } } file_history_events_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TimerFiredEvent); i { + switch v := v.(*TimerCreatedEvent); i { case 0: return &v.state case 1: @@ -2825,7 +2904,7 @@ func file_history_events_proto_init() { } } file_history_events_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WorkflowStartedEvent); i { + switch v := v.(*TimerFiredEvent); i { case 0: return &v.state case 1: @@ -2837,7 +2916,7 @@ func file_history_events_proto_init() { } } file_history_events_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WorkflowCompletedEvent); i { + switch v := v.(*WorkflowStartedEvent); i { case 0: return &v.state case 1: @@ -2849,7 +2928,7 @@ func file_history_events_proto_init() { } } file_history_events_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EventSentEvent); i { + switch v := v.(*WorkflowCompletedEvent); i { case 0: return &v.state case 1: @@ -2861,7 +2940,7 @@ func file_history_events_proto_init() { } } file_history_events_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EventRaisedEvent); i { + switch v := v.(*EventSentEvent); i { case 0: return &v.state case 1: @@ -2873,7 +2952,7 @@ func file_history_events_proto_init() { } } file_history_events_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ContinueAsNewEvent); i { + switch v := v.(*EventRaisedEvent); i { case 0: return &v.state case 1: @@ -2885,7 +2964,7 @@ func file_history_events_proto_init() { } } file_history_events_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecutionSuspendedEvent); i { + switch v := v.(*ContinueAsNewEvent); i { case 0: return &v.state case 1: @@ -2897,7 +2976,7 @@ func file_history_events_proto_init() { } } file_history_events_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecutionResumedEvent); i { + switch v := v.(*ExecutionSuspendedEvent); i { case 0: return &v.state case 1: @@ -2909,7 +2988,7 @@ func file_history_events_proto_init() { } } file_history_events_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecutionStalledEvent); i { + switch v := v.(*ExecutionResumedEvent); i { case 0: return &v.state case 1: @@ -2921,7 +3000,7 @@ func file_history_events_proto_init() { } } file_history_events_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HistoryEvent); i { + switch v := v.(*ExecutionStalledEvent); i { case 0: return &v.state case 1: @@ -2933,7 +3012,7 @@ func file_history_events_proto_init() { } } file_history_events_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PropagatedHistoryChunk); i { + switch v := v.(*HistoryEvent); i { case 0: return &v.state case 1: @@ -2945,6 +3024,18 @@ func file_history_events_proto_init() { } } file_history_events_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PropagatedHistoryChunk); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_history_events_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PropagatedHistory); i { case 0: return &v.state @@ -2963,15 +3054,15 @@ func file_history_events_proto_init() { file_history_events_proto_msgTypes[6].OneofWrappers = []interface{}{} file_history_events_proto_msgTypes[7].OneofWrappers = []interface{}{} file_history_events_proto_msgTypes[8].OneofWrappers = []interface{}{} - file_history_events_proto_msgTypes[13].OneofWrappers = []interface{}{ + file_history_events_proto_msgTypes[14].OneofWrappers = []interface{}{ (*TimerCreatedEvent_CreateTimer)(nil), (*TimerCreatedEvent_ExternalEvent)(nil), (*TimerCreatedEvent_ActivityRetry)(nil), (*TimerCreatedEvent_ChildWorkflowRetry)(nil), } - file_history_events_proto_msgTypes[15].OneofWrappers = []interface{}{} - file_history_events_proto_msgTypes[22].OneofWrappers = []interface{}{} - file_history_events_proto_msgTypes[23].OneofWrappers = []interface{}{ + file_history_events_proto_msgTypes[16].OneofWrappers = []interface{}{} + file_history_events_proto_msgTypes[23].OneofWrappers = []interface{}{} + file_history_events_proto_msgTypes[24].OneofWrappers = []interface{}{ (*HistoryEvent_ExecutionStarted)(nil), (*HistoryEvent_ExecutionCompleted)(nil), (*HistoryEvent_ExecutionTerminated)(nil), @@ -2991,6 +3082,7 @@ func file_history_events_proto_init() { (*HistoryEvent_ExecutionSuspended)(nil), (*HistoryEvent_ExecutionResumed)(nil), (*HistoryEvent_ExecutionStalled)(nil), + (*HistoryEvent_DetachedWorkflowInstanceCreated)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -2998,7 +3090,7 @@ func file_history_events_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_history_events_proto_rawDesc, NumEnums: 0, - NumMessages: 27, + NumMessages: 28, NumExtensions: 0, NumServices: 0, }, diff --git a/api/protos/orchestrator_actions.pb.go b/api/protos/orchestrator_actions.pb.go index 6d084b2..9d0cc8d 100644 --- a/api/protos/orchestrator_actions.pb.go +++ b/api/protos/orchestrator_actions.pb.go @@ -201,6 +201,133 @@ func (x *CreateChildWorkflowAction) GetHistoryPropagationScope() HistoryPropagat return HistoryPropagationScope_HISTORY_PROPAGATION_SCOPE_NONE } +// CreateDetachedWorkflowAction creates a new, detached workflow instance from +// a running workflow. Mirrors the fields of CreateInstanceRequest (the client +// scheduling API) so the runtime has all the information needed to schedule +// the new instance directly from this action. The spawned workflow is fully +// decoupled from the caller: no parent pointer is recorded on the new +// workflow, no completion is awaited, and no failure propagation flows back. +// The creation is recorded once in the caller's history as a +// DetachedWorkflowInstanceCreatedEvent referencing the new instance ID. +type CreateDetachedWorkflowAction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // instanceId is the ID assigned to the new workflow. It is mandatory: + // implementors must set a stable, deterministic ID so that on replay the + // call resolves to the same DetachedWorkflowInstanceCreatedEvent in + // history. + InstanceId string `protobuf:"bytes,1,opt,name=instanceId,proto3" json:"instanceId,omitempty"` + // name of the workflow to schedule. Mandatory. + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // The remaining fields mirror the optional inputs of + // CreateInstanceRequest. Wrapper types (StringValue) carry presence via + // the wrapper; bare message fields are explicitly marked optional. + Version *wrapperspb.StringValue `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` + Input *wrapperspb.StringValue `protobuf:"bytes,4,opt,name=input,proto3" json:"input,omitempty"` + ScheduledStartTimestamp *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=scheduledStartTimestamp,proto3,oneof" json:"scheduledStartTimestamp,omitempty"` + ExecutionId *wrapperspb.StringValue `protobuf:"bytes,6,opt,name=executionId,proto3" json:"executionId,omitempty"` + Tags map[string]string `protobuf:"bytes,7,rep,name=tags,proto3" json:"tags,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + ParentTraceContext *TraceContext `protobuf:"bytes,8,opt,name=parentTraceContext,proto3,oneof" json:"parentTraceContext,omitempty"` + Router *TaskRouter `protobuf:"bytes,9,opt,name=router,proto3,oneof" json:"router,omitempty"` +} + +func (x *CreateDetachedWorkflowAction) Reset() { + *x = CreateDetachedWorkflowAction{} + if protoimpl.UnsafeEnabled { + mi := &file_orchestrator_actions_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateDetachedWorkflowAction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateDetachedWorkflowAction) ProtoMessage() {} + +func (x *CreateDetachedWorkflowAction) ProtoReflect() protoreflect.Message { + mi := &file_orchestrator_actions_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateDetachedWorkflowAction.ProtoReflect.Descriptor instead. +func (*CreateDetachedWorkflowAction) Descriptor() ([]byte, []int) { + return file_orchestrator_actions_proto_rawDescGZIP(), []int{2} +} + +func (x *CreateDetachedWorkflowAction) GetInstanceId() string { + if x != nil { + return x.InstanceId + } + return "" +} + +func (x *CreateDetachedWorkflowAction) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CreateDetachedWorkflowAction) GetVersion() *wrapperspb.StringValue { + if x != nil { + return x.Version + } + return nil +} + +func (x *CreateDetachedWorkflowAction) GetInput() *wrapperspb.StringValue { + if x != nil { + return x.Input + } + return nil +} + +func (x *CreateDetachedWorkflowAction) GetScheduledStartTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.ScheduledStartTimestamp + } + return nil +} + +func (x *CreateDetachedWorkflowAction) GetExecutionId() *wrapperspb.StringValue { + if x != nil { + return x.ExecutionId + } + return nil +} + +func (x *CreateDetachedWorkflowAction) GetTags() map[string]string { + if x != nil { + return x.Tags + } + return nil +} + +func (x *CreateDetachedWorkflowAction) GetParentTraceContext() *TraceContext { + if x != nil { + return x.ParentTraceContext + } + return nil +} + +func (x *CreateDetachedWorkflowAction) GetRouter() *TaskRouter { + if x != nil { + return x.Router + } + return nil +} + type CreateTimerAction struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -222,7 +349,7 @@ type CreateTimerAction struct { func (x *CreateTimerAction) Reset() { *x = CreateTimerAction{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_actions_proto_msgTypes[2] + mi := &file_orchestrator_actions_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -235,7 +362,7 @@ func (x *CreateTimerAction) String() string { func (*CreateTimerAction) ProtoMessage() {} func (x *CreateTimerAction) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_actions_proto_msgTypes[2] + mi := &file_orchestrator_actions_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -248,7 +375,7 @@ func (x *CreateTimerAction) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateTimerAction.ProtoReflect.Descriptor instead. func (*CreateTimerAction) Descriptor() ([]byte, []int) { - return file_orchestrator_actions_proto_rawDescGZIP(), []int{2} + return file_orchestrator_actions_proto_rawDescGZIP(), []int{3} } func (x *CreateTimerAction) GetFireAt() *timestamppb.Timestamp { @@ -341,7 +468,7 @@ type SendEventAction struct { func (x *SendEventAction) Reset() { *x = SendEventAction{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_actions_proto_msgTypes[3] + mi := &file_orchestrator_actions_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -354,7 +481,7 @@ func (x *SendEventAction) String() string { func (*SendEventAction) ProtoMessage() {} func (x *SendEventAction) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_actions_proto_msgTypes[3] + mi := &file_orchestrator_actions_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -367,7 +494,7 @@ func (x *SendEventAction) ProtoReflect() protoreflect.Message { // Deprecated: Use SendEventAction.ProtoReflect.Descriptor instead. func (*SendEventAction) Descriptor() ([]byte, []int) { - return file_orchestrator_actions_proto_rawDescGZIP(), []int{3} + return file_orchestrator_actions_proto_rawDescGZIP(), []int{4} } func (x *SendEventAction) GetInstance() *WorkflowInstance { @@ -407,7 +534,7 @@ type CompleteWorkflowAction struct { func (x *CompleteWorkflowAction) Reset() { *x = CompleteWorkflowAction{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_actions_proto_msgTypes[4] + mi := &file_orchestrator_actions_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -420,7 +547,7 @@ func (x *CompleteWorkflowAction) String() string { func (*CompleteWorkflowAction) ProtoMessage() {} func (x *CompleteWorkflowAction) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_actions_proto_msgTypes[4] + mi := &file_orchestrator_actions_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -433,7 +560,7 @@ func (x *CompleteWorkflowAction) ProtoReflect() protoreflect.Message { // Deprecated: Use CompleteWorkflowAction.ProtoReflect.Descriptor instead. func (*CompleteWorkflowAction) Descriptor() ([]byte, []int) { - return file_orchestrator_actions_proto_rawDescGZIP(), []int{4} + return file_orchestrator_actions_proto_rawDescGZIP(), []int{5} } func (x *CompleteWorkflowAction) GetWorkflowStatus() OrchestrationStatus { @@ -491,7 +618,7 @@ type TerminateWorkflowAction struct { func (x *TerminateWorkflowAction) Reset() { *x = TerminateWorkflowAction{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_actions_proto_msgTypes[5] + mi := &file_orchestrator_actions_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -504,7 +631,7 @@ func (x *TerminateWorkflowAction) String() string { func (*TerminateWorkflowAction) ProtoMessage() {} func (x *TerminateWorkflowAction) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_actions_proto_msgTypes[5] + mi := &file_orchestrator_actions_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -517,7 +644,7 @@ func (x *TerminateWorkflowAction) ProtoReflect() protoreflect.Message { // Deprecated: Use TerminateWorkflowAction.ProtoReflect.Descriptor instead. func (*TerminateWorkflowAction) Descriptor() ([]byte, []int) { - return file_orchestrator_actions_proto_rawDescGZIP(), []int{5} + return file_orchestrator_actions_proto_rawDescGZIP(), []int{6} } func (x *TerminateWorkflowAction) GetInstanceId() string { @@ -550,7 +677,7 @@ type WorkflowVersionNotAvailableAction struct { func (x *WorkflowVersionNotAvailableAction) Reset() { *x = WorkflowVersionNotAvailableAction{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_actions_proto_msgTypes[6] + mi := &file_orchestrator_actions_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -563,7 +690,7 @@ func (x *WorkflowVersionNotAvailableAction) String() string { func (*WorkflowVersionNotAvailableAction) ProtoMessage() {} func (x *WorkflowVersionNotAvailableAction) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_actions_proto_msgTypes[6] + mi := &file_orchestrator_actions_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -576,7 +703,7 @@ func (x *WorkflowVersionNotAvailableAction) ProtoReflect() protoreflect.Message // Deprecated: Use WorkflowVersionNotAvailableAction.ProtoReflect.Descriptor instead. func (*WorkflowVersionNotAvailableAction) Descriptor() ([]byte, []int) { - return file_orchestrator_actions_proto_rawDescGZIP(), []int{6} + return file_orchestrator_actions_proto_rawDescGZIP(), []int{7} } type WorkflowAction struct { @@ -594,6 +721,7 @@ type WorkflowAction struct { // *WorkflowAction_CompleteWorkflow // *WorkflowAction_TerminateWorkflow // *WorkflowAction_WorkflowVersionNotAvailable + // *WorkflowAction_CreateDetachedWorkflow WorkflowActionType isWorkflowAction_WorkflowActionType `protobuf_oneof:"workflowActionType"` Router *TaskRouter `protobuf:"bytes,9,opt,name=router,proto3,oneof" json:"router,omitempty"` } @@ -601,7 +729,7 @@ type WorkflowAction struct { func (x *WorkflowAction) Reset() { *x = WorkflowAction{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_actions_proto_msgTypes[7] + mi := &file_orchestrator_actions_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -614,7 +742,7 @@ func (x *WorkflowAction) String() string { func (*WorkflowAction) ProtoMessage() {} func (x *WorkflowAction) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_actions_proto_msgTypes[7] + mi := &file_orchestrator_actions_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -627,7 +755,7 @@ func (x *WorkflowAction) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkflowAction.ProtoReflect.Descriptor instead. func (*WorkflowAction) Descriptor() ([]byte, []int) { - return file_orchestrator_actions_proto_rawDescGZIP(), []int{7} + return file_orchestrator_actions_proto_rawDescGZIP(), []int{8} } func (x *WorkflowAction) GetId() int32 { @@ -693,6 +821,13 @@ func (x *WorkflowAction) GetWorkflowVersionNotAvailable() *WorkflowVersionNotAva return nil } +func (x *WorkflowAction) GetCreateDetachedWorkflow() *CreateDetachedWorkflowAction { + if x, ok := x.GetWorkflowActionType().(*WorkflowAction_CreateDetachedWorkflow); ok { + return x.CreateDetachedWorkflow + } + return nil +} + func (x *WorkflowAction) GetRouter() *TaskRouter { if x != nil { return x.Router @@ -732,6 +867,10 @@ type WorkflowAction_WorkflowVersionNotAvailable struct { WorkflowVersionNotAvailable *WorkflowVersionNotAvailableAction `protobuf:"bytes,10,opt,name=workflowVersionNotAvailable,proto3,oneof"` } +type WorkflowAction_CreateDetachedWorkflow struct { + CreateDetachedWorkflow *CreateDetachedWorkflowAction `protobuf:"bytes,11,opt,name=createDetachedWorkflow,proto3,oneof"` +} + func (*WorkflowAction_ScheduleTask) isWorkflowAction_WorkflowActionType() {} func (*WorkflowAction_CreateChildWorkflow) isWorkflowAction_WorkflowActionType() {} @@ -746,6 +885,8 @@ func (*WorkflowAction_TerminateWorkflow) isWorkflowAction_WorkflowActionType() { func (*WorkflowAction_WorkflowVersionNotAvailable) isWorkflowAction_WorkflowActionType() {} +func (*WorkflowAction_CreateDetachedWorkflow) isWorkflowAction_WorkflowActionType() {} + var File_orchestrator_actions_proto protoreflect.FileDescriptor var file_orchestrator_actions_proto_rawDesc = []byte{ @@ -802,119 +943,165 @@ var file_orchestrator_actions_proto_rawDesc = []byte{ 0x79, 0x50, 0x72, 0x6f, 0x70, 0x61, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x70, 0x61, - 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x22, 0x88, 0x03, 0x0a, 0x11, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x32, 0x0a, 0x06, 0x66, 0x69, 0x72, 0x65, 0x41, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x06, 0x66, - 0x69, 0x72, 0x65, 0x41, 0x74, 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x3b, - 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, 0x67, 0x69, - 0x6e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0b, - 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0d, 0x65, - 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, - 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, - 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x41, - 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x52, 0x65, 0x74, 0x72, 0x79, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, - 0x67, 0x69, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x52, 0x65, 0x74, 0x72, 0x79, - 0x48, 0x00, 0x52, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x52, 0x65, 0x74, 0x72, - 0x79, 0x12, 0x50, 0x0a, 0x12, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, - 0x6f, 0x77, 0x52, 0x65, 0x74, 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x43, 0x68, 0x69, 0x6c, 0x64, - 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x74, 0x72, 0x79, 0x48, 0x00, 0x52, - 0x12, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, - 0x74, 0x72, 0x79, 0x42, 0x08, 0x0a, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x42, 0x07, 0x0a, - 0x05, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x86, 0x01, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x08, 0x69, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x57, - 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, - 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x30, 0x0a, - 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, - 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, - 0xf8, 0x02, 0x0a, 0x16, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, - 0x66, 0x6c, 0x6f, 0x77, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x0e, 0x77, 0x6f, - 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x4f, 0x72, 0x63, 0x68, 0x65, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, - 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, - 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x36, - 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x64, - 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x3c, 0x0a, 0x0a, 0x6e, 0x65, 0x77, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, - 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x6e, 0x65, 0x77, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x37, 0x0a, 0x0f, 0x63, 0x61, 0x72, 0x72, 0x79, 0x6f, 0x76, 0x65, - 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, - 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x0f, 0x63, 0x61, - 0x72, 0x72, 0x79, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x3b, 0x0a, - 0x0e, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x46, 0x61, 0x69, 0x6c, - 0x75, 0x72, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x0e, 0x66, 0x61, 0x69, 0x6c, - 0x75, 0x72, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x89, 0x01, 0x0a, 0x17, 0x54, - 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, + 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x22, 0xfb, 0x04, 0x0a, 0x1c, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x57, 0x6f, + 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x36, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x59, 0x0a, 0x17, + 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x48, 0x00, 0x52, 0x17, 0x73, 0x63, 0x68, + 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x88, 0x01, 0x01, 0x12, 0x3e, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0b, 0x65, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, + 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, + 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x41, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, + 0x74, 0x61, 0x67, 0x73, 0x12, 0x42, 0x0a, 0x12, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x54, 0x72, + 0x61, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0d, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x48, + 0x01, 0x52, 0x12, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x54, 0x72, 0x61, 0x63, 0x65, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x88, 0x01, 0x01, 0x12, 0x28, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, + 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, + 0x6f, 0x75, 0x74, 0x65, 0x72, 0x48, 0x02, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x88, + 0x01, 0x01, 0x1a, 0x37, 0x0a, 0x09, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x1a, 0x0a, 0x18, 0x5f, + 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x70, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x54, 0x72, 0x61, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x42, 0x09, + 0x0a, 0x07, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x22, 0x88, 0x03, 0x0a, 0x11, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x32, 0x0a, 0x06, 0x66, 0x69, 0x72, 0x65, 0x41, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x06, 0x66, 0x69, 0x72, + 0x65, 0x41, 0x74, 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x01, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x3b, 0x0a, 0x0b, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0d, 0x65, 0x78, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x19, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x45, 0x78, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x65, + 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x41, 0x0a, 0x0d, + 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x52, 0x65, 0x74, 0x72, 0x79, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, 0x67, 0x69, + 0x6e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x52, 0x65, 0x74, 0x72, 0x79, 0x48, 0x00, + 0x52, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x52, 0x65, 0x74, 0x72, 0x79, 0x12, + 0x50, 0x0a, 0x12, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, + 0x52, 0x65, 0x74, 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x72, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, + 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x74, 0x72, 0x79, 0x48, 0x00, 0x52, 0x12, 0x63, + 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x74, 0x72, + 0x79, 0x42, 0x08, 0x0a, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x42, 0x07, 0x0a, 0x05, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x86, 0x01, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x57, 0x6f, 0x72, + 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x04, 0x64, + 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xf8, 0x02, + 0x0a, 0x16, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, + 0x6f, 0x77, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, + 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x14, 0x2e, 0x4f, 0x72, 0x63, 0x68, 0x65, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, - 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, - 0x65, 0x63, 0x75, 0x72, 0x73, 0x65, 0x22, 0x23, 0x0a, 0x21, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, - 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x41, 0x76, 0x61, 0x69, - 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xdf, 0x04, 0x0a, 0x0e, - 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x39, - 0x0a, 0x0c, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x54, - 0x61, 0x73, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x63, 0x68, - 0x65, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x4e, 0x0a, 0x13, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, - 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x41, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x68, 0x69, 0x6c, - 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x36, 0x0a, 0x0b, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, - 0x72, 0x12, 0x30, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x12, 0x45, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x57, - 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, - 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x10, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, - 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x48, 0x0a, 0x11, 0x74, 0x65, - 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, - 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, - 0x00, 0x52, 0x11, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, - 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x66, 0x0a, 0x1b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x36, 0x0a, 0x07, + 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x64, 0x65, 0x74, + 0x61, 0x69, 0x6c, 0x73, 0x12, 0x3c, 0x0a, 0x0a, 0x6e, 0x65, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x6e, 0x65, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x37, 0x0a, 0x0f, 0x63, 0x61, 0x72, 0x72, 0x79, 0x6f, 0x76, 0x65, 0x72, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x48, 0x69, + 0x73, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x0f, 0x63, 0x61, 0x72, 0x72, + 0x79, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x3b, 0x0a, 0x0e, 0x66, + 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, + 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x0e, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, + 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x89, 0x01, 0x0a, 0x17, 0x54, 0x65, 0x72, + 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x41, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, + 0x63, 0x75, 0x72, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x63, + 0x75, 0x72, 0x73, 0x65, 0x22, 0x23, 0x0a, 0x21, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, - 0x62, 0x6c, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x57, 0x6f, 0x72, 0x6b, - 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x41, 0x76, - 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, - 0x1b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x4e, 0x6f, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x28, 0x0a, 0x06, - 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x54, - 0x61, 0x73, 0x6b, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x48, 0x01, 0x52, 0x06, 0x72, 0x6f, 0x75, - 0x74, 0x65, 0x72, 0x88, 0x01, 0x01, 0x42, 0x14, 0x0a, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, - 0x6f, 0x77, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x42, 0x09, 0x0a, 0x07, - 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x42, 0x56, 0x0a, - 0x2b, 0x69, 0x6f, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, 0x64, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, - 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x5a, 0x0b, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0xaa, 0x02, 0x19, 0x44, 0x61, 0x70, 0x72, - 0x2e, 0x44, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x2e, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x62, 0x6c, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xb8, 0x05, 0x0a, 0x0e, 0x57, 0x6f, + 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x0c, + 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x61, 0x73, + 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x63, 0x68, 0x65, 0x64, + 0x75, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x4e, 0x0a, 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x68, 0x69, + 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x48, 0x00, 0x52, 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x57, + 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x36, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x48, 0x00, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, + 0x30, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x12, 0x45, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f, 0x72, + 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x43, 0x6f, + 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x41, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x10, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, + 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x48, 0x0a, 0x11, 0x74, 0x65, 0x72, 0x6d, + 0x69, 0x6e, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x57, + 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, + 0x11, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, + 0x6f, 0x77, 0x12, 0x66, 0x0a, 0x1b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, + 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, + 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x41, 0x76, 0x61, 0x69, + 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x1b, 0x77, + 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, + 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x57, 0x0a, 0x16, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, + 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x44, 0x65, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, + 0x6c, 0x6f, 0x77, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x16, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x44, 0x65, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x66, + 0x6c, 0x6f, 0x77, 0x12, 0x28, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, + 0x48, 0x01, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x88, 0x01, 0x01, 0x42, 0x14, 0x0a, + 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, + 0x79, 0x70, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x4a, 0x04, + 0x08, 0x08, 0x10, 0x09, 0x42, 0x56, 0x0a, 0x2b, 0x69, 0x6f, 0x2e, 0x64, 0x61, 0x70, 0x72, 0x2e, + 0x64, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x69, 0x6d, 0x70, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x5a, 0x0b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, + 0xaa, 0x02, 0x19, 0x44, 0x61, 0x70, 0x72, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x54, + 0x61, 0x73, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -929,65 +1116,76 @@ func file_orchestrator_actions_proto_rawDescGZIP() []byte { return file_orchestrator_actions_proto_rawDescData } -var file_orchestrator_actions_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_orchestrator_actions_proto_msgTypes = make([]protoimpl.MessageInfo, 10) var file_orchestrator_actions_proto_goTypes = []interface{}{ (*ScheduleTaskAction)(nil), // 0: ScheduleTaskAction (*CreateChildWorkflowAction)(nil), // 1: CreateChildWorkflowAction - (*CreateTimerAction)(nil), // 2: CreateTimerAction - (*SendEventAction)(nil), // 3: SendEventAction - (*CompleteWorkflowAction)(nil), // 4: CompleteWorkflowAction - (*TerminateWorkflowAction)(nil), // 5: TerminateWorkflowAction - (*WorkflowVersionNotAvailableAction)(nil), // 6: WorkflowVersionNotAvailableAction - (*WorkflowAction)(nil), // 7: WorkflowAction - (*wrapperspb.StringValue)(nil), // 8: google.protobuf.StringValue - (*TaskRouter)(nil), // 9: TaskRouter - (HistoryPropagationScope)(0), // 10: HistoryPropagationScope - (*timestamppb.Timestamp)(nil), // 11: google.protobuf.Timestamp - (*TimerOriginCreateTimer)(nil), // 12: TimerOriginCreateTimer - (*TimerOriginExternalEvent)(nil), // 13: TimerOriginExternalEvent - (*TimerOriginActivityRetry)(nil), // 14: TimerOriginActivityRetry - (*TimerOriginChildWorkflowRetry)(nil), // 15: TimerOriginChildWorkflowRetry - (*WorkflowInstance)(nil), // 16: WorkflowInstance - (OrchestrationStatus)(0), // 17: OrchestrationStatus - (*HistoryEvent)(nil), // 18: HistoryEvent - (*TaskFailureDetails)(nil), // 19: TaskFailureDetails + (*CreateDetachedWorkflowAction)(nil), // 2: CreateDetachedWorkflowAction + (*CreateTimerAction)(nil), // 3: CreateTimerAction + (*SendEventAction)(nil), // 4: SendEventAction + (*CompleteWorkflowAction)(nil), // 5: CompleteWorkflowAction + (*TerminateWorkflowAction)(nil), // 6: TerminateWorkflowAction + (*WorkflowVersionNotAvailableAction)(nil), // 7: WorkflowVersionNotAvailableAction + (*WorkflowAction)(nil), // 8: WorkflowAction + nil, // 9: CreateDetachedWorkflowAction.TagsEntry + (*wrapperspb.StringValue)(nil), // 10: google.protobuf.StringValue + (*TaskRouter)(nil), // 11: TaskRouter + (HistoryPropagationScope)(0), // 12: HistoryPropagationScope + (*timestamppb.Timestamp)(nil), // 13: google.protobuf.Timestamp + (*TraceContext)(nil), // 14: TraceContext + (*TimerOriginCreateTimer)(nil), // 15: TimerOriginCreateTimer + (*TimerOriginExternalEvent)(nil), // 16: TimerOriginExternalEvent + (*TimerOriginActivityRetry)(nil), // 17: TimerOriginActivityRetry + (*TimerOriginChildWorkflowRetry)(nil), // 18: TimerOriginChildWorkflowRetry + (*WorkflowInstance)(nil), // 19: WorkflowInstance + (OrchestrationStatus)(0), // 20: OrchestrationStatus + (*HistoryEvent)(nil), // 21: HistoryEvent + (*TaskFailureDetails)(nil), // 22: TaskFailureDetails } var file_orchestrator_actions_proto_depIdxs = []int32{ - 8, // 0: ScheduleTaskAction.version:type_name -> google.protobuf.StringValue - 8, // 1: ScheduleTaskAction.input:type_name -> google.protobuf.StringValue - 9, // 2: ScheduleTaskAction.router:type_name -> TaskRouter - 10, // 3: ScheduleTaskAction.historyPropagationScope:type_name -> HistoryPropagationScope - 8, // 4: CreateChildWorkflowAction.version:type_name -> google.protobuf.StringValue - 8, // 5: CreateChildWorkflowAction.input:type_name -> google.protobuf.StringValue - 9, // 6: CreateChildWorkflowAction.router:type_name -> TaskRouter - 10, // 7: CreateChildWorkflowAction.historyPropagationScope:type_name -> HistoryPropagationScope - 11, // 8: CreateTimerAction.fireAt:type_name -> google.protobuf.Timestamp - 12, // 9: CreateTimerAction.createTimer:type_name -> TimerOriginCreateTimer - 13, // 10: CreateTimerAction.externalEvent:type_name -> TimerOriginExternalEvent - 14, // 11: CreateTimerAction.activityRetry:type_name -> TimerOriginActivityRetry - 15, // 12: CreateTimerAction.childWorkflowRetry:type_name -> TimerOriginChildWorkflowRetry - 16, // 13: SendEventAction.instance:type_name -> WorkflowInstance - 8, // 14: SendEventAction.data:type_name -> google.protobuf.StringValue - 17, // 15: CompleteWorkflowAction.workflowStatus:type_name -> OrchestrationStatus - 8, // 16: CompleteWorkflowAction.result:type_name -> google.protobuf.StringValue - 8, // 17: CompleteWorkflowAction.details:type_name -> google.protobuf.StringValue - 8, // 18: CompleteWorkflowAction.newVersion:type_name -> google.protobuf.StringValue - 18, // 19: CompleteWorkflowAction.carryoverEvents:type_name -> HistoryEvent - 19, // 20: CompleteWorkflowAction.failureDetails:type_name -> TaskFailureDetails - 8, // 21: TerminateWorkflowAction.reason:type_name -> google.protobuf.StringValue - 0, // 22: WorkflowAction.scheduleTask:type_name -> ScheduleTaskAction - 1, // 23: WorkflowAction.createChildWorkflow:type_name -> CreateChildWorkflowAction - 2, // 24: WorkflowAction.createTimer:type_name -> CreateTimerAction - 3, // 25: WorkflowAction.sendEvent:type_name -> SendEventAction - 4, // 26: WorkflowAction.completeWorkflow:type_name -> CompleteWorkflowAction - 5, // 27: WorkflowAction.terminateWorkflow:type_name -> TerminateWorkflowAction - 6, // 28: WorkflowAction.workflowVersionNotAvailable:type_name -> WorkflowVersionNotAvailableAction - 9, // 29: WorkflowAction.router:type_name -> TaskRouter - 30, // [30:30] is the sub-list for method output_type - 30, // [30:30] is the sub-list for method input_type - 30, // [30:30] is the sub-list for extension type_name - 30, // [30:30] is the sub-list for extension extendee - 0, // [0:30] is the sub-list for field type_name + 10, // 0: ScheduleTaskAction.version:type_name -> google.protobuf.StringValue + 10, // 1: ScheduleTaskAction.input:type_name -> google.protobuf.StringValue + 11, // 2: ScheduleTaskAction.router:type_name -> TaskRouter + 12, // 3: ScheduleTaskAction.historyPropagationScope:type_name -> HistoryPropagationScope + 10, // 4: CreateChildWorkflowAction.version:type_name -> google.protobuf.StringValue + 10, // 5: CreateChildWorkflowAction.input:type_name -> google.protobuf.StringValue + 11, // 6: CreateChildWorkflowAction.router:type_name -> TaskRouter + 12, // 7: CreateChildWorkflowAction.historyPropagationScope:type_name -> HistoryPropagationScope + 10, // 8: CreateDetachedWorkflowAction.version:type_name -> google.protobuf.StringValue + 10, // 9: CreateDetachedWorkflowAction.input:type_name -> google.protobuf.StringValue + 13, // 10: CreateDetachedWorkflowAction.scheduledStartTimestamp:type_name -> google.protobuf.Timestamp + 10, // 11: CreateDetachedWorkflowAction.executionId:type_name -> google.protobuf.StringValue + 9, // 12: CreateDetachedWorkflowAction.tags:type_name -> CreateDetachedWorkflowAction.TagsEntry + 14, // 13: CreateDetachedWorkflowAction.parentTraceContext:type_name -> TraceContext + 11, // 14: CreateDetachedWorkflowAction.router:type_name -> TaskRouter + 13, // 15: CreateTimerAction.fireAt:type_name -> google.protobuf.Timestamp + 15, // 16: CreateTimerAction.createTimer:type_name -> TimerOriginCreateTimer + 16, // 17: CreateTimerAction.externalEvent:type_name -> TimerOriginExternalEvent + 17, // 18: CreateTimerAction.activityRetry:type_name -> TimerOriginActivityRetry + 18, // 19: CreateTimerAction.childWorkflowRetry:type_name -> TimerOriginChildWorkflowRetry + 19, // 20: SendEventAction.instance:type_name -> WorkflowInstance + 10, // 21: SendEventAction.data:type_name -> google.protobuf.StringValue + 20, // 22: CompleteWorkflowAction.workflowStatus:type_name -> OrchestrationStatus + 10, // 23: CompleteWorkflowAction.result:type_name -> google.protobuf.StringValue + 10, // 24: CompleteWorkflowAction.details:type_name -> google.protobuf.StringValue + 10, // 25: CompleteWorkflowAction.newVersion:type_name -> google.protobuf.StringValue + 21, // 26: CompleteWorkflowAction.carryoverEvents:type_name -> HistoryEvent + 22, // 27: CompleteWorkflowAction.failureDetails:type_name -> TaskFailureDetails + 10, // 28: TerminateWorkflowAction.reason:type_name -> google.protobuf.StringValue + 0, // 29: WorkflowAction.scheduleTask:type_name -> ScheduleTaskAction + 1, // 30: WorkflowAction.createChildWorkflow:type_name -> CreateChildWorkflowAction + 3, // 31: WorkflowAction.createTimer:type_name -> CreateTimerAction + 4, // 32: WorkflowAction.sendEvent:type_name -> SendEventAction + 5, // 33: WorkflowAction.completeWorkflow:type_name -> CompleteWorkflowAction + 6, // 34: WorkflowAction.terminateWorkflow:type_name -> TerminateWorkflowAction + 7, // 35: WorkflowAction.workflowVersionNotAvailable:type_name -> WorkflowVersionNotAvailableAction + 2, // 36: WorkflowAction.createDetachedWorkflow:type_name -> CreateDetachedWorkflowAction + 11, // 37: WorkflowAction.router:type_name -> TaskRouter + 38, // [38:38] is the sub-list for method output_type + 38, // [38:38] is the sub-list for method input_type + 38, // [38:38] is the sub-list for extension type_name + 38, // [38:38] is the sub-list for extension extendee + 0, // [0:38] is the sub-list for field type_name } func init() { file_orchestrator_actions_proto_init() } @@ -1023,7 +1221,7 @@ func file_orchestrator_actions_proto_init() { } } file_orchestrator_actions_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateTimerAction); i { + switch v := v.(*CreateDetachedWorkflowAction); i { case 0: return &v.state case 1: @@ -1035,7 +1233,7 @@ func file_orchestrator_actions_proto_init() { } } file_orchestrator_actions_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SendEventAction); i { + switch v := v.(*CreateTimerAction); i { case 0: return &v.state case 1: @@ -1047,7 +1245,7 @@ func file_orchestrator_actions_proto_init() { } } file_orchestrator_actions_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CompleteWorkflowAction); i { + switch v := v.(*SendEventAction); i { case 0: return &v.state case 1: @@ -1059,7 +1257,7 @@ func file_orchestrator_actions_proto_init() { } } file_orchestrator_actions_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TerminateWorkflowAction); i { + switch v := v.(*CompleteWorkflowAction); i { case 0: return &v.state case 1: @@ -1071,7 +1269,7 @@ func file_orchestrator_actions_proto_init() { } } file_orchestrator_actions_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WorkflowVersionNotAvailableAction); i { + switch v := v.(*TerminateWorkflowAction); i { case 0: return &v.state case 1: @@ -1083,6 +1281,18 @@ func file_orchestrator_actions_proto_init() { } } file_orchestrator_actions_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WorkflowVersionNotAvailableAction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_orchestrator_actions_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*WorkflowAction); i { case 0: return &v.state @@ -1097,13 +1307,14 @@ func file_orchestrator_actions_proto_init() { } file_orchestrator_actions_proto_msgTypes[0].OneofWrappers = []interface{}{} file_orchestrator_actions_proto_msgTypes[1].OneofWrappers = []interface{}{} - file_orchestrator_actions_proto_msgTypes[2].OneofWrappers = []interface{}{ + file_orchestrator_actions_proto_msgTypes[2].OneofWrappers = []interface{}{} + file_orchestrator_actions_proto_msgTypes[3].OneofWrappers = []interface{}{ (*CreateTimerAction_CreateTimer)(nil), (*CreateTimerAction_ExternalEvent)(nil), (*CreateTimerAction_ActivityRetry)(nil), (*CreateTimerAction_ChildWorkflowRetry)(nil), } - file_orchestrator_actions_proto_msgTypes[7].OneofWrappers = []interface{}{ + file_orchestrator_actions_proto_msgTypes[8].OneofWrappers = []interface{}{ (*WorkflowAction_ScheduleTask)(nil), (*WorkflowAction_CreateChildWorkflow)(nil), (*WorkflowAction_CreateTimer)(nil), @@ -1111,6 +1322,7 @@ func file_orchestrator_actions_proto_init() { (*WorkflowAction_CompleteWorkflow)(nil), (*WorkflowAction_TerminateWorkflow)(nil), (*WorkflowAction_WorkflowVersionNotAvailable)(nil), + (*WorkflowAction_CreateDetachedWorkflow)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -1118,7 +1330,7 @@ func file_orchestrator_actions_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_orchestrator_actions_proto_rawDesc, NumEnums: 0, - NumMessages: 8, + NumMessages: 10, NumExtensions: 0, NumServices: 0, }, diff --git a/backend/runtimestate/applier.go b/backend/runtimestate/applier.go index c22599a..3525c17 100644 --- a/backend/runtimestate/applier.go +++ b/backend/runtimestate/applier.go @@ -315,6 +315,87 @@ func (a *Applier) Actions(s *protos.WorkflowRuntimeState, customStatus *wrappers msg.PropagatedHistory = ph } s.PendingMessages = append(s.PendingMessages, msg) + } else if createDetached := action.GetCreateDetachedWorkflow(); createDetached != nil { + // Detached workflows are fully decoupled from the caller: the + // spawned ExecutionStartedEvent carries no ParentInstanceInfo, + // so completion and failure do not flow back to the caller's + // history. Recursive purge / terminate enumerate only + // ChildWorkflowInstanceCreated events, so detached spawns are + // correctly excluded from those traversals. + if createDetached.InstanceId == "" { + return result, fmt.Errorf("CreateDetachedWorkflowAction requires an instance ID") + } + + _ = AddEvent(s, &protos.HistoryEvent{ + EventId: action.Id, + Timestamp: timestamppb.New(time.Now()), + EventType: &protos.HistoryEvent_DetachedWorkflowInstanceCreated{ + DetachedWorkflowInstanceCreated: &protos.DetachedWorkflowInstanceCreatedEvent{ + InstanceId: createDetached.InstanceId, + }, + }, + Router: action.Router, + }) + + // Mint an execution ID if the action did not supply one, + // matching the client ScheduleNewWorkflow behavior so the new + // instance always has a stable executionId on its start event. + executionID := createDetached.GetExecutionId() + if executionID == nil { + executionID = wrapperspb.String(uuid.New().String()) + } + + // Prefer the trace context the workflow author attached to + // the action; fall back to the caller's current trace context + // so a detached workflow scheduled without explicit tracing + // still inherits a parent span. + traceContext := createDetached.GetParentTraceContext() + if traceContext == nil { + traceContext = currentTraceContext + } + + // Build a target-only router for the spawned StartEvent so the + // new instance carries no back-reference to the caller. The + // applier loop stamps action.Router.SourceAppID = a.appID, which + // is what CallChildWorkflow propagates to its child so completion + // can flow back. Detached workflows do not flow completion back, + // so dropping SourceAppID gives the spawned instance the same + // router shape a client-scheduled top-level workflow would have. + var spawnedRouter *protos.TaskRouter + if r := action.Router; r != nil && r.GetTargetAppID() != "" { + spawnedRouter = &protos.TaskRouter{ + TargetAppID: ptr.Of(r.GetTargetAppID()), + } + if ns := r.GetTargetAppNamespace(); ns != "" { + spawnedRouter.TargetAppNamespace = ptr.Of(ns) + } + } + + startEvent := &protos.HistoryEvent{ + EventId: -1, + Timestamp: timestamppb.New(time.Now()), + EventType: &protos.HistoryEvent_ExecutionStarted{ + ExecutionStarted: &protos.ExecutionStartedEvent{ + Name: createDetached.Name, + Input: createDetached.Input, + ScheduledStartTimestamp: createDetached.ScheduledStartTimestamp, + Tags: createDetached.Tags, + WorkflowInstance: &protos.WorkflowInstance{ + InstanceId: createDetached.InstanceId, + ExecutionId: executionID, + }, + ParentTraceContext: traceContext, + // ParentInstance is intentionally left nil: the + // detached workflow has no parent linkage. + }, + }, + Router: spawnedRouter, + } + + s.PendingMessages = append(s.PendingMessages, &protos.WorkflowRuntimeStateMessage{ + HistoryEvent: startEvent, + TargetInstanceId: createDetached.InstanceId, + }) } else if sendEvent := action.GetSendEvent(); sendEvent != nil { e := &protos.HistoryEvent{ EventId: action.Id, diff --git a/submodules/durabletask-protobuf b/submodules/durabletask-protobuf index 7d7391e..3f10731 160000 --- a/submodules/durabletask-protobuf +++ b/submodules/durabletask-protobuf @@ -1 +1 @@ -Subproject commit 7d7391e4044252f4abcf55b17634a65de744f4ee +Subproject commit 3f1073180d713b3c4dbf4d9522a41ab46a851a9d diff --git a/task/detached_workflow_test.go b/task/detached_workflow_test.go new file mode 100644 index 0000000..22c63c4 --- /dev/null +++ b/task/detached_workflow_test.go @@ -0,0 +1,234 @@ +/* +Copyright 2026 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package task + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/timestamppb" + "google.golang.org/protobuf/types/known/wrapperspb" + + "github.com/dapr/durabletask-go/api" + "github.com/dapr/durabletask-go/api/protos" +) + +func TestScheduleNewWorkflow_EmitsAction(t *testing.T) { + ctx := newTestContext(t) + startTime := time.Date(2030, 1, 2, 3, 4, 5, 0, time.UTC) + + id, err := ctx.ScheduleNewWorkflow(dummyWorkflow, + WithDetachedWorkflowInstanceID("spawned-1"), + WithDetachedWorkflowInput(map[string]string{"hello": "world"}), + WithDetachedWorkflowVersion("v1.2.3"), + WithDetachedWorkflowExecutionID("exec-42"), + WithDetachedWorkflowStartTime(startTime), + WithDetachedWorkflowTags(map[string]string{"team": "growth"}), + ) + require.NoError(t, err) + assert.Equal(t, api.InstanceID("spawned-1"), id) + + require.Len(t, ctx.pendingActions, 1) + assert.Empty(t, ctx.pendingTasks, "ScheduleNewWorkflow is fire-and-forget; no Task should be registered") + + for _, a := range ctx.pendingActions { + dw := a.GetCreateDetachedWorkflow() + require.NotNil(t, dw) + assert.Equal(t, "spawned-1", dw.InstanceId) + assert.Equal(t, "dummyWorkflow", dw.Name) + assert.Equal(t, `{"hello":"world"}`, dw.GetInput().GetValue()) + assert.Equal(t, "v1.2.3", dw.GetVersion().GetValue()) + assert.Equal(t, "exec-42", dw.GetExecutionId().GetValue()) + assert.Equal(t, startTime, dw.GetScheduledStartTimestamp().AsTime()) + assert.Equal(t, map[string]string{"team": "growth"}, dw.GetTags()) + assert.Nil(t, a.Router, "no router envelope should be emitted when no app/namespace target is set") + } +} + +func TestScheduleNewWorkflow_RawInput(t *testing.T) { + ctx := newTestContext(t) + raw := wrapperspb.String("raw-bytes") + + _, err := ctx.ScheduleNewWorkflow(dummyWorkflow, + WithDetachedWorkflowInstanceID("spawned-raw"), + WithRawDetachedWorkflowInput(raw), + ) + require.NoError(t, err) + + require.Len(t, ctx.pendingActions, 1) + for _, a := range ctx.pendingActions { + dw := a.GetCreateDetachedWorkflow() + require.NotNil(t, dw) + assert.Equal(t, "raw-bytes", dw.GetInput().GetValue()) + } +} + +func TestScheduleNewWorkflow_ExplicitEmptyExecutionID_Errors(t *testing.T) { + ctx := newTestContext(t) + + id, err := ctx.ScheduleNewWorkflow(dummyWorkflow, + WithDetachedWorkflowInstanceID("spawned"), + WithDetachedWorkflowExecutionID(""), + ) + require.Error(t, err) + assert.Equal(t, api.EmptyInstanceID, id) + assert.Contains(t, err.Error(), "empty string") + assert.Empty(t, ctx.pendingActions, + "no action should be scheduled when an empty execution ID is provided — the spawned StartEvent would otherwise carry an empty ExecutionId because the applier's nil-check passes through wrapperspb.String(\"\")") +} + +func TestScheduleNewWorkflow_ExplicitEmptyInstanceID_Errors(t *testing.T) { + ctx := newTestContext(t) + + id, err := ctx.ScheduleNewWorkflow(dummyWorkflow, + WithDetachedWorkflowInstanceID(""), + ) + require.Error(t, err) + assert.Equal(t, api.EmptyInstanceID, id) + assert.Contains(t, err.Error(), "empty string") + assert.Empty(t, ctx.pendingActions, "no action should be scheduled when instanceID is set to an empty string") + assert.Equal(t, int32(0), ctx.defaultDetachedWorkflowCounter, + "a rejected call must not advance the default-ID counter") +} + +func TestScheduleNewWorkflow_DefaultsInstanceID(t *testing.T) { + ctx := newTestContext(t) + + // First default-ID spawn → "-0". + id0, err := ctx.ScheduleNewWorkflow(dummyWorkflow) + require.NoError(t, err) + assert.Equal(t, api.InstanceID("test-id-0"), id0) + + // An intervening action with a different shape (e.g., a timer) must + // NOT advance the default-ID counter — the counter only tracks + // default-ID spawns so the suffix is stable across replays even if + // the user reorders unrelated calls. + ctx.CreateTimer(time.Second) + + id1, err := ctx.ScheduleNewWorkflow(dummyWorkflow) + require.NoError(t, err) + assert.Equal(t, api.InstanceID("test-id-1"), id1) + + // An explicit ID must not be overridden, and must not bump the + // default counter. + idExplicit, err := ctx.ScheduleNewWorkflow(dummyWorkflow, + WithDetachedWorkflowInstanceID("custom-id"), + ) + require.NoError(t, err) + assert.Equal(t, api.InstanceID("custom-id"), idExplicit) + + id2, err := ctx.ScheduleNewWorkflow(dummyWorkflow) + require.NoError(t, err) + assert.Equal(t, api.InstanceID("test-id-2"), id2, + "explicit-ID spawns must not advance the default-ID counter") +} + +func TestScheduleNewWorkflow_NamespaceWithoutAppIDFails(t *testing.T) { + ctx := newTestContext(t) + + id, err := ctx.ScheduleNewWorkflow(dummyWorkflow, + WithDetachedWorkflowInstanceID("spawned-ns"), + WithDetachedWorkflowAppNamespace("target-ns"), + ) + require.Error(t, err) + assert.Equal(t, api.EmptyInstanceID, id) + assert.Contains(t, err.Error(), "WithDetachedWorkflowAppID") + assert.Empty(t, ctx.pendingActions) +} + +func TestScheduleNewWorkflow_RouterAppIDOnly(t *testing.T) { + ctx := newTestContext(t) + + _, err := ctx.ScheduleNewWorkflow(dummyWorkflow, + WithDetachedWorkflowInstanceID("spawned-app"), + WithDetachedWorkflowAppID("target-app"), + ) + require.NoError(t, err) + + require.Len(t, ctx.pendingActions, 1) + for _, a := range ctx.pendingActions { + require.NotNil(t, a.Router) + assert.Equal(t, "target-app", a.Router.GetTargetAppID()) + assert.Equal(t, "", a.Router.GetTargetAppNamespace()) + } +} + +func TestScheduleNewWorkflow_RouterAppIDAndNamespace(t *testing.T) { + ctx := newTestContext(t) + + _, err := ctx.ScheduleNewWorkflow(dummyWorkflow, + WithDetachedWorkflowInstanceID("spawned-cross"), + WithDetachedWorkflowAppID("target-app"), + WithDetachedWorkflowAppNamespace("target-ns"), + ) + require.NoError(t, err) + + require.Len(t, ctx.pendingActions, 1) + for _, a := range ctx.pendingActions { + require.NotNil(t, a.Router) + assert.Equal(t, "target-app", a.Router.GetTargetAppID()) + assert.Equal(t, "target-ns", a.Router.GetTargetAppNamespace()) + } +} + +func TestOnDetachedWorkflowCreated_RetiresPendingAction(t *testing.T) { + ctx := newTestContext(t) + + _, err := ctx.ScheduleNewWorkflow(dummyWorkflow, + WithDetachedWorkflowInstanceID("spawned-replay"), + ) + require.NoError(t, err) + require.Len(t, ctx.pendingActions, 1) + + // Find the emitted action's id so we can simulate the matching history event. + var actionID int32 + for id := range ctx.pendingActions { + actionID = id + } + + err = ctx.processEvent(&protos.HistoryEvent{ + EventId: actionID, + Timestamp: timestamppb.Now(), + EventType: &protos.HistoryEvent_DetachedWorkflowInstanceCreated{ + DetachedWorkflowInstanceCreated: &protos.DetachedWorkflowInstanceCreatedEvent{ + InstanceId: "spawned-replay", + }, + }, + }) + require.NoError(t, err) + assert.Empty(t, ctx.pendingActions, "matching event should retire the pending action") +} + +func TestOnDetachedWorkflowCreated_NondeterministicReplay_Errors(t *testing.T) { + ctx := newTestContext(t) + + // No pending action staged for this id — simulating a history event + // produced by a workflow version whose code path no longer schedules a + // detached workflow at that sequence position. + err := ctx.processEvent(&protos.HistoryEvent{ + EventId: 42, + Timestamp: timestamppb.Now(), + EventType: &protos.HistoryEvent_DetachedWorkflowInstanceCreated{ + DetachedWorkflowInstanceCreated: &protos.DetachedWorkflowInstanceCreatedEvent{ + InstanceId: "spawned-mismatch", + }, + }, + }) + require.Error(t, err) + assert.Contains(t, err.Error(), "ScheduleNewWorkflow") + assert.Contains(t, err.Error(), "spawned-mismatch") + assert.Contains(t, err.Error(), "42") +} diff --git a/task/orchestrator.go b/task/orchestrator.go index a35a307..a2635a1 100644 --- a/task/orchestrator.go +++ b/task/orchestrator.go @@ -6,6 +6,7 @@ import ( "math" "reflect" "sort" + "strconv" "strings" "time" @@ -60,6 +61,15 @@ type WorkflowContext struct { appliedPatches map[string]bool encounteredPatches []string propagatedHistory *api.PropagatedHistory + + // defaultDetachedWorkflowCounter tracks how many ScheduleNewWorkflow + // calls have used the default-generated instance ID this execution. + // It is incremented only when the caller does not pass + // WithDetachedWorkflowInstanceID, so the suffix on generated IDs + // reflects the order of default-ID spawns rather than the global + // action sequence. Reset by start() each replay so the same workflow + // code path always produces the same IDs. + defaultDetachedWorkflowCounter int32 } // callChildWorkflowOptions is a struct that holds the options for the CallChildWorkflow workflow method. @@ -164,6 +174,137 @@ func WithChildWorkflowRetryPolicy(policy *RetryPolicy) ChildWorkflowOptionFunc { } } +// scheduleNewWorkflowOptions is a struct that holds the options for the +// ScheduleNewWorkflow workflow method. It mirrors the fields of +// CreateInstanceRequest so that a workflow author can spawn a fully +// decoupled instance with the same surface area as the client API. +type scheduleNewWorkflowOptions struct { + instanceID *string + rawInput *wrapperspb.StringValue + version *wrapperspb.StringValue + executionID *wrapperspb.StringValue + scheduledStartTimestamp *timestamppb.Timestamp + tags map[string]string + parentTraceContext *protos.TraceContext + targetAppID *string + targetAppNamespace *string +} + +// DetachedWorkflowOptions is the interface for options passed to +// ScheduleNewWorkflow. Unlike CallChildWorkflow, the spawned instance is +// fire-and-forget: the caller receives the instance ID synchronously but +// does not wait on (and is not notified of) the spawned workflow's +// completion. +type DetachedWorkflowOptions interface { + applyDetachedWorkflowOption(*scheduleNewWorkflowOptions) error +} + +// DetachedWorkflowOptionsFunc adapts a function to the +// DetachedWorkflowOptions interface. +type DetachedWorkflowOptionsFunc func(*scheduleNewWorkflowOptions) error + +func (f DetachedWorkflowOptionsFunc) applyDetachedWorkflowOption(opts *scheduleNewWorkflowOptions) error { + return f(opts) +} + +// WithDetachedWorkflowInstanceID sets the instance ID of the detached +// workflow. When omitted, ScheduleNewWorkflow generates a deterministic +// ID of the form "-" where n increments per +// default-ID spawn within the execution. The '-' separator keeps the +// generated ID safe for consumers (e.g. dapr) that propagate the +// instance id into RFC 1123 subdomain identifiers. Passing an empty +// string is rejected as an error: callers either set a non-empty ID or +// omit the option entirely to opt into the default. +func WithDetachedWorkflowInstanceID(instanceID string) DetachedWorkflowOptionsFunc { + return func(opts *scheduleNewWorkflowOptions) error { + opts.instanceID = &instanceID + return nil + } +} + +// WithDetachedWorkflowInput sets the input for the detached workflow, +// marshalling it to JSON. +func WithDetachedWorkflowInput(input any) DetachedWorkflowOptionsFunc { + return func(opts *scheduleNewWorkflowOptions) error { + bytes, err := marshalData(input) + if err != nil { + return fmt.Errorf("failed to marshal input to JSON: %w", err) + } + opts.rawInput = wrapperspb.String(string(bytes)) + return nil + } +} + +// WithRawDetachedWorkflowInput sets a pre-marshalled raw input on the +// detached workflow. +func WithRawDetachedWorkflowInput(input *wrapperspb.StringValue) DetachedWorkflowOptionsFunc { + return func(opts *scheduleNewWorkflowOptions) error { + opts.rawInput = input + return nil + } +} + +// WithDetachedWorkflowVersion sets a version label on the detached +// workflow. The semantics mirror CreateInstanceRequest.version. +func WithDetachedWorkflowVersion(version string) DetachedWorkflowOptionsFunc { + return func(opts *scheduleNewWorkflowOptions) error { + opts.version = wrapperspb.String(version) + return nil + } +} + +// WithDetachedWorkflowExecutionID sets an explicit execution ID on the +// detached workflow's first execution. When unset, the runtime mints a +// fresh UUID, matching the client ScheduleNewWorkflow behavior. Passing +// an empty string is rejected as an error: callers either set a +// non-empty execution ID or omit the option to opt into UUID minting. +func WithDetachedWorkflowExecutionID(executionID string) DetachedWorkflowOptionsFunc { + return func(opts *scheduleNewWorkflowOptions) error { + if executionID == "" { + return fmt.Errorf("WithDetachedWorkflowExecutionID was passed an empty string; omit the option to let the runtime mint a UUID") + } + opts.executionID = wrapperspb.String(executionID) + return nil + } +} + +// WithDetachedWorkflowStartTime defers the start of the detached workflow +// until the given time. Mirrors api.WithStartTime on the client API. +func WithDetachedWorkflowStartTime(startTime time.Time) DetachedWorkflowOptionsFunc { + return func(opts *scheduleNewWorkflowOptions) error { + opts.scheduledStartTimestamp = timestamppb.New(startTime) + return nil + } +} + +// WithDetachedWorkflowTags sets the tag map on the detached workflow. +func WithDetachedWorkflowTags(tags map[string]string) DetachedWorkflowOptionsFunc { + return func(opts *scheduleNewWorkflowOptions) error { + opts.tags = tags + return nil + } +} + +// WithDetachedWorkflowAppID specifies the app ID hosting the detached +// workflow. When set, the action carries a routing envelope so the +// dispatcher delivers the new instance to the target app. +func WithDetachedWorkflowAppID(appID string) DetachedWorkflowOptionsFunc { + return func(opts *scheduleNewWorkflowOptions) error { + opts.targetAppID = &appID + return nil + } +} + +// WithDetachedWorkflowAppNamespace specifies the Dapr namespace hosting +// the detached workflow. Must be combined with WithDetachedWorkflowAppID; +// see WithChildWorkflowAppNamespace for full semantics. +func WithDetachedWorkflowAppNamespace(namespace string) DetachedWorkflowOptionsFunc { + return func(opts *scheduleNewWorkflowOptions) error { + opts.targetAppNamespace = &namespace + return nil + } +} + // NewWorkflowContext returns a new [WorkflowContext] struct with the specified parameters. func NewWorkflowContext(registry *TaskRegistry, id api.InstanceID, oldEvents []*protos.HistoryEvent, newEvents []*protos.HistoryEvent) *WorkflowContext { return &WorkflowContext{ @@ -182,6 +323,7 @@ func NewWorkflowContext(registry *TaskRegistry, id api.InstanceID, oldEvents []* func (ctx *WorkflowContext) start() (actions []*protos.WorkflowAction) { ctx.historyIndex = 0 ctx.sequenceNumber = 0 + ctx.defaultDetachedWorkflowCounter = 0 ctx.pendingActions = make(map[int32]*protos.WorkflowAction) ctx.pendingTasks = make(map[int32]*completableTask) @@ -278,6 +420,8 @@ func (ctx *WorkflowContext) processEvent(e *backend.HistoryEvent) error { err = ctx.onChildWorkflowCompleted(sc) } else if sf := e.GetChildWorkflowInstanceFailed(); sf != nil { err = ctx.onChildWorkflowFailed(sf) + } else if dw := e.GetDetachedWorkflowInstanceCreated(); dw != nil { + err = ctx.onDetachedWorkflowCreated(e.EventId, dw) } else if tc := e.GetTimerCreated(); tc != nil { err = ctx.onTimerCreated(e) } else if tf := e.GetTimerFired(); tf != nil { @@ -455,6 +599,71 @@ func (ctx *WorkflowContext) internalCallChildWorkflow(workflowName string, optio return task } +// ScheduleNewWorkflow schedules a new, fully decoupled workflow instance +// from the calling workflow. Unlike CallChildWorkflow, the spawned +// workflow has no parent linkage: its history's ExecutionStartedEvent +// carries no ParentInstanceInfo, completion and failure do not flow back +// to the caller, and the caller receives the new instance ID +// synchronously rather than an awaitable Task. +// +// If WithDetachedWorkflowInstanceID is not provided, a deterministic ID +// of the form "-" is generated, where n increments +// only for default-ID spawns within this execution (so the suffix +// reflects the order of those calls and is stable across replays). The +// '-' separator keeps the generated ID safe for consumers that +// propagate the instance id into RFC 1123 subdomain identifiers. +// +// If the workflow author needs the spawned workflow's result, they should +// model the dependency through external events (RaiseEvent / WaitForEvent) +// or shared state — there is no built-in completion channel. +func (ctx *WorkflowContext) ScheduleNewWorkflow(workflow any, opts ...DetachedWorkflowOptions) (api.InstanceID, error) { + options := new(scheduleNewWorkflowOptions) + for _, configure := range opts { + if err := configure.applyDetachedWorkflowOption(options); err != nil { + return api.EmptyInstanceID, err + } + } + + if options.targetAppNamespace != nil && options.targetAppID == nil { + return api.EmptyInstanceID, fmt.Errorf("WithDetachedWorkflowAppNamespace requires WithDetachedWorkflowAppID to also be set") + } + + var instanceID string + if options.instanceID == nil { + instanceID = string(ctx.ID) + "-" + strconv.FormatInt(int64(ctx.defaultDetachedWorkflowCounter), 10) + ctx.defaultDetachedWorkflowCounter++ + } else if *options.instanceID == "" { + return api.EmptyInstanceID, fmt.Errorf("WithDetachedWorkflowInstanceID was passed an empty string; omit the option to opt into the default ID") + } else { + instanceID = *options.instanceID + } + + workflowName := helpers.GetTaskFunctionName(workflow) + + action := &protos.WorkflowAction{ + Id: ctx.getNextSequenceNumber(), + WorkflowActionType: &protos.WorkflowAction_CreateDetachedWorkflow{ + CreateDetachedWorkflow: &protos.CreateDetachedWorkflowAction{ + InstanceId: instanceID, + Name: workflowName, + Version: options.version, + Input: options.rawInput, + ScheduledStartTimestamp: options.scheduledStartTimestamp, + ExecutionId: options.executionID, + Tags: options.tags, + ParentTraceContext: options.parentTraceContext, + }, + }, + } + + if r := taskRouterFromTarget(options.targetAppID, options.targetAppNamespace); r != nil { + action.Router = r + } + + ctx.pendingActions[action.Id] = action + return api.InstanceID(instanceID), nil +} + func (ctx *WorkflowContext) internalScheduleTaskWithRetries(name string, initialAttempt time.Time, schedule func(taskExecutionId string) Task, policy RetryPolicy, retryCount int, taskExecutionId string, setTimerOrigin func(*protos.CreateTimerAction, string)) Task { return &taskWrapper{ delegate: schedule(taskExecutionId), @@ -778,6 +987,28 @@ func (ctx *WorkflowContext) onChildWorkflowScheduled(taskID int32, ts *protos.Ch return nil } +// onDetachedWorkflowCreated retires the pending CreateDetachedWorkflowAction +// at this sequence position. Detached workflows are fire-and-forget, so +// there is no associated pending Task to complete: the call returned the +// instance ID synchronously when the action was emitted. +func (ctx *WorkflowContext) onDetachedWorkflowCreated(taskID int32, dw *protos.DetachedWorkflowInstanceCreatedEvent) error { + a, ok := ctx.pendingActions[taskID] + if !ok || a.GetCreateDetachedWorkflow() == nil { + if ctx.dropOptionalExternalEventTimerAt(taskID) { + a, ok = ctx.pendingActions[taskID] + } + } + if !ok || a.GetCreateDetachedWorkflow() == nil { + return fmt.Errorf( + "a previous execution called ScheduleNewWorkflow for instance ID '%s' and sequence number %d at this point in the workflow logic, but the current execution doesn't have this action with this sequence number", + dw.InstanceId, + taskID, + ) + } + delete(ctx.pendingActions, taskID) + return nil +} + func (ctx *WorkflowContext) onChildWorkflowCompleted(soc *protos.ChildWorkflowInstanceCompletedEvent) error { taskID := soc.TaskScheduledId task, ok := ctx.pendingTasks[taskID] diff --git a/tests/orchestrations_test.go b/tests/orchestrations_test.go index 7139e73..7ddfa25 100644 --- a/tests/orchestrations_test.go +++ b/tests/orchestrations_test.go @@ -583,6 +583,170 @@ func Test_SingleChildWorkflow_Failed_Retries_AutoInstanceID(t *testing.T) { ) } +// Test_DetachedWorkflow_HappyPath verifies that a workflow can spawn a +// fully decoupled child via ScheduleNewWorkflow, the parent completes +// independently of the spawned instance, and the spawned instance runs +// to completion under the requested instance ID. +func Test_DetachedWorkflow_HappyPath(t *testing.T) { + r := task.NewTaskRegistry() + r.AddWorkflowN("Caller", func(ctx *task.WorkflowContext) (any, error) { + spawnedID, err := ctx.ScheduleNewWorkflow("Spawned", + task.WithDetachedWorkflowInstanceID(string(ctx.ID)+"_spawned"), + task.WithDetachedWorkflowInput("payload"), + ) + if err != nil { + return nil, err + } + return string(spawnedID), nil + }) + r.AddWorkflowN("Spawned", func(ctx *task.WorkflowContext) (any, error) { + var input string + if err := ctx.GetInput(&input); err != nil { + return "", err + } + return "spawned-saw:" + input, nil + }) + + ctx := context.Background() + client, worker := initTaskHubWorker(ctx, r) + defer worker.Shutdown(ctx) + + id, err := client.ScheduleNewWorkflow(ctx, "Caller") + require.NoError(t, err) + parentMeta, err := client.WaitForWorkflowCompletion(ctx, id) + require.NoError(t, err) + require.Equal(t, protos.OrchestrationStatus_ORCHESTRATION_STATUS_COMPLETED, parentMeta.RuntimeStatus) + + spawnedID := api.InstanceID(string(id) + "_spawned") + spawnedMeta, err := client.WaitForWorkflowCompletion(ctx, spawnedID) + require.NoError(t, err) + require.Equal(t, protos.OrchestrationStatus_ORCHESTRATION_STATUS_COMPLETED, spawnedMeta.RuntimeStatus) + require.Contains(t, spawnedMeta.Output.GetValue(), "spawned-saw:") +} + +// Test_DetachedWorkflow_DefaultInstanceID verifies that omitting +// WithDetachedWorkflowInstanceID yields a deterministic default ID of +// the form "-" and that the spawned instance is +// reachable under that ID. +func Test_DetachedWorkflow_DefaultInstanceID(t *testing.T) { + r := task.NewTaskRegistry() + r.AddWorkflowN("Caller", func(ctx *task.WorkflowContext) (any, error) { + // First default-ID spawn → "/0". + spawnedID, err := ctx.ScheduleNewWorkflow("Spawned") + if err != nil { + return nil, err + } + return string(spawnedID), nil + }) + r.AddWorkflowN("Spawned", func(ctx *task.WorkflowContext) (any, error) { + return "ok", nil + }) + + ctx := context.Background() + client, worker := initTaskHubWorker(ctx, r) + defer worker.Shutdown(ctx) + + id, err := client.ScheduleNewWorkflow(ctx, "Caller") + require.NoError(t, err) + parentMeta, err := client.WaitForWorkflowCompletion(ctx, id) + require.NoError(t, err) + require.Equal(t, protos.OrchestrationStatus_ORCHESTRATION_STATUS_COMPLETED, parentMeta.RuntimeStatus) + + expectedSpawnedID := api.InstanceID(string(id) + "-0") + require.Contains(t, parentMeta.Output.GetValue(), string(expectedSpawnedID)) + spawnedMeta, err := client.WaitForWorkflowCompletion(ctx, expectedSpawnedID) + require.NoError(t, err) + require.Equal(t, protos.OrchestrationStatus_ORCHESTRATION_STATUS_COMPLETED, spawnedMeta.RuntimeStatus) +} + +// Test_DetachedWorkflow_NoCompletionFlowsBack verifies that when a +// detached child fails, the parent is NOT failed and the parent's +// terminal state does not depend on the child's outcome. +func Test_DetachedWorkflow_NoCompletionFlowsBack(t *testing.T) { + r := task.NewTaskRegistry() + r.AddWorkflowN("Caller", func(ctx *task.WorkflowContext) (any, error) { + _, err := ctx.ScheduleNewWorkflow("FailingSpawned", + task.WithDetachedWorkflowInstanceID(string(ctx.ID)+"_spawned"), + ) + if err != nil { + return nil, err + } + // Caller completes immediately. If completion or failure of the + // detached child were routed back, the parent's terminal state + // would reflect that — it must not. + return "caller-done", nil + }) + r.AddWorkflowN("FailingSpawned", func(ctx *task.WorkflowContext) (any, error) { + return nil, errors.New("spawned failure should NOT propagate") + }) + + ctx := context.Background() + client, worker := initTaskHubWorker(ctx, r) + defer worker.Shutdown(ctx) + + id, err := client.ScheduleNewWorkflow(ctx, "Caller") + require.NoError(t, err) + + parentMeta, err := client.WaitForWorkflowCompletion(ctx, id) + require.NoError(t, err) + require.Equal(t, protos.OrchestrationStatus_ORCHESTRATION_STATUS_COMPLETED, parentMeta.RuntimeStatus, + "parent must complete independently of the detached child's outcome") + require.Nil(t, parentMeta.FailureDetails, + "detached child's failure must not surface as parent failure") + + spawnedID := api.InstanceID(string(id) + "_spawned") + spawnedMeta, err := client.WaitForWorkflowCompletion(ctx, spawnedID) + require.NoError(t, err) + require.Equal(t, protos.OrchestrationStatus_ORCHESTRATION_STATUS_FAILED, spawnedMeta.RuntimeStatus) +} + +// Test_DetachedWorkflow_ReplayDeterminism forces the parent through a +// replay (suspend → resume) and verifies the spawned instance is created +// exactly once with a stable ID, even though the orchestrator function +// re-executes from the start of history each replay. +func Test_DetachedWorkflow_ReplayDeterminism(t *testing.T) { + r := task.NewTaskRegistry() + r.AddWorkflowN("Caller", func(ctx *task.WorkflowContext) (any, error) { + spawnedID, err := ctx.ScheduleNewWorkflow("Spawned", + task.WithDetachedWorkflowInstanceID(string(ctx.ID)+"_spawned"), + ) + if err != nil { + return nil, err + } + // Wait for an external event so the workflow yields and forces a + // replay when it resumes. + if err := ctx.WaitForSingleEvent("Continue", 30*time.Second).Await(nil); err != nil { + return nil, err + } + return string(spawnedID), nil + }) + r.AddWorkflowN("Spawned", func(ctx *task.WorkflowContext) (any, error) { + return "ok", nil + }) + + ctx := context.Background() + client, worker := initTaskHubWorker(ctx, r) + defer worker.Shutdown(ctx) + + id, err := client.ScheduleNewWorkflow(ctx, "Caller") + require.NoError(t, err) + + // Wait for the spawned workflow to complete to confirm it was created + // before we send the resume signal. + spawnedID := api.InstanceID(string(id) + "_spawned") + _, err = client.WaitForWorkflowCompletion(ctx, spawnedID) + require.NoError(t, err) + + // Resume the parent. After replay, ScheduleNewWorkflow should match + // the existing DetachedWorkflowInstanceCreated event in history and + // NOT spawn a second instance. + require.NoError(t, client.RaiseEvent(ctx, id, "Continue")) + + parentMeta, err := client.WaitForWorkflowCompletion(ctx, id) + require.NoError(t, err) + require.Equal(t, protos.OrchestrationStatus_ORCHESTRATION_STATUS_COMPLETED, parentMeta.RuntimeStatus) +} + func Test_ContinueAsNew(t *testing.T) { // Registration r := task.NewTaskRegistry() diff --git a/tests/runtimestate_test.go b/tests/runtimestate_test.go index b7d2e95..ec9cd6a 100644 --- a/tests/runtimestate_test.go +++ b/tests/runtimestate_test.go @@ -934,6 +934,366 @@ func Test_CreateChildWorkflow(t *testing.T) { } } +func Test_CreateDetachedWorkflow(t *testing.T) { + const callerID = "caller" + const expectedTaskID = int32(7) + const expectedInstanceID = "spawned" + const expectedName = "MyDetachedWorkflow" + const expectedExecID = "exec-fixed" + const expectedTraceParent = "trace-detached" + const expectedTraceState = "trace_state_detached" + + expectedInput := wrapperspb.String(`{"hello":"world"}`) + expectedTags := map[string]string{"team": "growth"} + expectedStart := timestamppb.New(time.Date(2030, 1, 2, 3, 4, 5, 0, time.UTC)) + + state := runtimestate.NewWorkflowRuntimeState(callerID, nil, []*protos.HistoryEvent{ + { + EventId: -1, + Timestamp: timestamppb.New(time.Now()), + EventType: &protos.HistoryEvent_ExecutionStarted{ + ExecutionStarted: &protos.ExecutionStartedEvent{ + Name: "Caller", + WorkflowInstance: &protos.WorkflowInstance{ + InstanceId: callerID, + ExecutionId: wrapperspb.String(uuid.New().String()), + }, + }, + }, + }, + }) + + actions := []*protos.WorkflowAction{ + { + Id: expectedTaskID, + WorkflowActionType: &protos.WorkflowAction_CreateDetachedWorkflow{ + CreateDetachedWorkflow: &protos.CreateDetachedWorkflowAction{ + InstanceId: expectedInstanceID, + Name: expectedName, + Input: expectedInput, + Tags: expectedTags, + ScheduledStartTimestamp: expectedStart, + ExecutionId: wrapperspb.String(expectedExecID), + }, + }, + }, + } + + tc := &protos.TraceContext{ + TraceParent: expectedTraceParent, + TraceState: wrapperspb.String(expectedTraceState), + } + applier := runtimestate.NewApplier("caller-app", "") + result, err := applier.Actions(state, nil, actions, tc, nil) + require.NoError(t, err) + assert.False(t, result.ContinuedAsNew) + + // Caller history records exactly one DetachedWorkflowInstanceCreated event + // — and crucially no ChildWorkflowInstanceCreated, so recursive purge / + // terminate cannot accidentally chase the spawned instance. + require.Len(t, state.NewEvents, 1) + created := state.NewEvents[0].GetDetachedWorkflowInstanceCreated() + require.NotNil(t, created) + assert.Equal(t, expectedTaskID, state.NewEvents[0].EventId) + assert.Equal(t, expectedInstanceID, created.InstanceId) + assert.Nil(t, state.NewEvents[0].GetChildWorkflowInstanceCreated()) + + // The spawned instance is delivered as a pending message carrying an + // ExecutionStartedEvent with no ParentInstanceInfo (this is the + // load-bearing distinction from CallChildWorkflow). + require.Len(t, state.PendingMessages, 1) + msg := state.PendingMessages[0] + assert.Equal(t, expectedInstanceID, msg.TargetInstanceId) + startEvent := msg.HistoryEvent.GetExecutionStarted() + require.NotNil(t, startEvent) + assert.Equal(t, expectedName, startEvent.Name) + assert.Equal(t, expectedInput.GetValue(), startEvent.Input.GetValue()) + assert.Equal(t, expectedInstanceID, startEvent.WorkflowInstance.InstanceId) + assert.Equal(t, expectedExecID, startEvent.WorkflowInstance.ExecutionId.GetValue()) + assert.Equal(t, expectedTags, startEvent.Tags) + assert.Equal(t, expectedStart.AsTime(), startEvent.ScheduledStartTimestamp.AsTime()) + assert.Nil(t, startEvent.ParentInstance, "detached workflow must have no parent linkage") + require.NotNil(t, startEvent.ParentTraceContext) + assert.Equal(t, expectedTraceParent, startEvent.ParentTraceContext.TraceParent) + assert.Equal(t, expectedTraceState, startEvent.ParentTraceContext.TraceState.GetValue()) +} + +func Test_CreateDetachedWorkflow_MintsExecutionIDWhenAbsent(t *testing.T) { + state := runtimestate.NewWorkflowRuntimeState("caller", nil, []*protos.HistoryEvent{ + { + EventId: -1, + Timestamp: timestamppb.New(time.Now()), + EventType: &protos.HistoryEvent_ExecutionStarted{ + ExecutionStarted: &protos.ExecutionStartedEvent{ + Name: "Caller", + WorkflowInstance: &protos.WorkflowInstance{ + InstanceId: "caller", + ExecutionId: wrapperspb.String(uuid.New().String()), + }, + }, + }, + }, + }) + + actions := []*protos.WorkflowAction{ + { + Id: 1, + WorkflowActionType: &protos.WorkflowAction_CreateDetachedWorkflow{ + CreateDetachedWorkflow: &protos.CreateDetachedWorkflowAction{ + InstanceId: "spawned-no-exec", + Name: "Spawned", + }, + }, + }, + } + + applier := runtimestate.NewApplier("caller-app", "") + _, err := applier.Actions(state, nil, actions, nil, nil) + require.NoError(t, err) + + require.Len(t, state.PendingMessages, 1) + startEvent := state.PendingMessages[0].HistoryEvent.GetExecutionStarted() + require.NotNil(t, startEvent) + assert.NotEmpty(t, startEvent.WorkflowInstance.ExecutionId.GetValue(), + "applier must mint an execution ID when the action does not supply one") +} + +func Test_CreateDetachedWorkflow_RouterPropagated(t *testing.T) { + state := runtimestate.NewWorkflowRuntimeState("caller", nil, []*protos.HistoryEvent{ + { + EventId: -1, + Timestamp: timestamppb.New(time.Now()), + EventType: &protos.HistoryEvent_ExecutionStarted{ + ExecutionStarted: &protos.ExecutionStartedEvent{ + Name: "Caller", + WorkflowInstance: &protos.WorkflowInstance{ + InstanceId: "caller", + ExecutionId: wrapperspb.String(uuid.New().String()), + }, + }, + }, + }, + }) + + targetAppID := "target-app" + actions := []*protos.WorkflowAction{ + { + Id: 2, + Router: &protos.TaskRouter{TargetAppID: &targetAppID}, + WorkflowActionType: &protos.WorkflowAction_CreateDetachedWorkflow{ + CreateDetachedWorkflow: &protos.CreateDetachedWorkflowAction{ + InstanceId: "spawned-cross-app", + Name: "Spawned", + }, + }, + }, + } + + applier := runtimestate.NewApplier("caller-app", "") + _, err := applier.Actions(state, nil, actions, nil, nil) + require.NoError(t, err) + + require.Len(t, state.PendingMessages, 1) + router := state.PendingMessages[0].HistoryEvent.GetRouter() + require.NotNil(t, router) + assert.Equal(t, targetAppID, router.GetTargetAppID()) + assert.Empty(t, router.GetSourceAppID(), + "detached workflows must not carry a SourceAppID back-reference to the caller") + assert.Empty(t, router.GetTargetAppNamespace(), + "no namespace was requested, so it should not be set") + + // The caller's history event still records the full action.Router as + // audit trail (caller's own record of where it scheduled the workflow). + require.Len(t, state.NewEvents, 1) + historyRouter := state.NewEvents[0].GetRouter() + require.NotNil(t, historyRouter) + assert.Equal(t, targetAppID, historyRouter.GetTargetAppID()) + assert.Equal(t, "caller-app", historyRouter.GetSourceAppID(), + "caller's audit-trail event records the SourceAppID as expected") +} + +// Test_CreateDetachedWorkflow_DispatcherCorrelationInvariant locks in +// the contract dispatchers (e.g. dapr) rely on to correlate a transient +// send failure back to the matching DetachedWorkflowInstanceCreatedEvent +// in NewEvents — so the event can be filtered out before partial-save +// and the action retried on the next reminder fire. +// +// Detached spawns drop ParentInstanceInfo and the dispatched StartEvent +// has EventId = -1, so neither of the existing correlation handles +// (TaskScheduled.EventId == action.Id, ParentInstance.TaskScheduledId) +// is available. The structural invariant the dispatcher must rely on: +// +// For each PendingMessage emitted by a CreateDetachedWorkflowAction, +// there is exactly one DetachedWorkflowInstanceCreatedEvent in the +// same NewEvents batch whose InstanceId equals the message's +// TargetInstanceId, and that event's EventId equals the originating +// action.Id. +// +// Multiple detached spawns in the same batch each get a unique +// InstanceId (auto-generated IDs use a per-execution counter; explicit +// IDs are the workflow author's responsibility), so the mapping is 1:1. +func Test_CreateDetachedWorkflow_DispatcherCorrelationInvariant(t *testing.T) { + state := runtimestate.NewWorkflowRuntimeState("caller", nil, []*protos.HistoryEvent{ + { + EventId: -1, + Timestamp: timestamppb.New(time.Now()), + EventType: &protos.HistoryEvent_ExecutionStarted{ + ExecutionStarted: &protos.ExecutionStartedEvent{ + Name: "Caller", + WorkflowInstance: &protos.WorkflowInstance{ + InstanceId: "caller", + ExecutionId: wrapperspb.String(uuid.New().String()), + }, + }, + }, + }, + }) + + // Three detached spawns in a single applier batch, with distinct + // instance IDs and non-contiguous action IDs (mimics a real batch + // that interleaves other actions). + actions := []*protos.WorkflowAction{ + { + Id: 2, + WorkflowActionType: &protos.WorkflowAction_CreateDetachedWorkflow{ + CreateDetachedWorkflow: &protos.CreateDetachedWorkflowAction{ + InstanceId: "spawned-a", + Name: "A", + }, + }, + }, + { + Id: 5, + WorkflowActionType: &protos.WorkflowAction_CreateDetachedWorkflow{ + CreateDetachedWorkflow: &protos.CreateDetachedWorkflowAction{ + InstanceId: "spawned-b", + Name: "B", + }, + }, + }, + { + Id: 9, + WorkflowActionType: &protos.WorkflowAction_CreateDetachedWorkflow{ + CreateDetachedWorkflow: &protos.CreateDetachedWorkflowAction{ + InstanceId: "spawned-c", + Name: "C", + }, + }, + }, + } + + applier := runtimestate.NewApplier("caller-app", "") + _, err := applier.Actions(state, nil, actions, nil, nil) + require.NoError(t, err) + require.Len(t, state.NewEvents, 3) + require.Len(t, state.PendingMessages, 3) + + // Build the same correlation map a dispatcher would, then assert + // every PendingMessage resolves to exactly one matching event whose + // EventId equals the originating action.Id. + createdByInstanceID := make(map[string]int32, len(state.NewEvents)) + for _, e := range state.NewEvents { + dw := e.GetDetachedWorkflowInstanceCreated() + require.NotNil(t, dw, "every NewEvent in this batch must be a DetachedWorkflowInstanceCreatedEvent") + _, dup := createdByInstanceID[dw.InstanceId] + require.False(t, dup, "InstanceId %q appears twice — invariant requires uniqueness within a batch", dw.InstanceId) + createdByInstanceID[dw.InstanceId] = e.EventId + } + + expected := map[string]int32{ + "spawned-a": 2, + "spawned-b": 5, + "spawned-c": 9, + } + for _, msg := range state.PendingMessages { + require.NotEmpty(t, msg.TargetInstanceId) + eventID, ok := createdByInstanceID[msg.TargetInstanceId] + require.True(t, ok, + "PendingMessage with TargetInstanceId %q has no matching DetachedWorkflowInstanceCreatedEvent in NewEvents — dispatchers cannot correlate this message", + msg.TargetInstanceId) + assert.Equal(t, expected[msg.TargetInstanceId], eventID, + "event id for %q must equal the originating action.Id", msg.TargetInstanceId) + } +} + +func Test_CreateDetachedWorkflow_LocalSpawn_NoRouter(t *testing.T) { + state := runtimestate.NewWorkflowRuntimeState("caller", nil, []*protos.HistoryEvent{ + { + EventId: -1, + Timestamp: timestamppb.New(time.Now()), + EventType: &protos.HistoryEvent_ExecutionStarted{ + ExecutionStarted: &protos.ExecutionStartedEvent{ + Name: "Caller", + WorkflowInstance: &protos.WorkflowInstance{ + InstanceId: "caller", + ExecutionId: wrapperspb.String(uuid.New().String()), + }, + }, + }, + }, + }) + + // No Router on the action — purely in-app spawn. + actions := []*protos.WorkflowAction{ + { + Id: 4, + WorkflowActionType: &protos.WorkflowAction_CreateDetachedWorkflow{ + CreateDetachedWorkflow: &protos.CreateDetachedWorkflowAction{ + InstanceId: "spawned-local", + Name: "Spawned", + }, + }, + }, + } + + applier := runtimestate.NewApplier("caller-app", "") + _, err := applier.Actions(state, nil, actions, nil, nil) + require.NoError(t, err) + + require.Len(t, state.PendingMessages, 1) + assert.Nil(t, state.PendingMessages[0].HistoryEvent.GetRouter(), + "local spawn must produce no router on the spawned StartEvent") +} + +func Test_CreateDetachedWorkflow_MissingInstanceID_Errors(t *testing.T) { + state := runtimestate.NewWorkflowRuntimeState("caller", nil, []*protos.HistoryEvent{ + { + EventId: -1, + Timestamp: timestamppb.New(time.Now()), + EventType: &protos.HistoryEvent_ExecutionStarted{ + ExecutionStarted: &protos.ExecutionStartedEvent{ + Name: "Caller", + WorkflowInstance: &protos.WorkflowInstance{ + InstanceId: "caller", + ExecutionId: wrapperspb.String(uuid.New().String()), + }, + }, + }, + }, + }) + + actions := []*protos.WorkflowAction{ + { + Id: 3, + WorkflowActionType: &protos.WorkflowAction_CreateDetachedWorkflow{ + CreateDetachedWorkflow: &protos.CreateDetachedWorkflowAction{ + Name: "Spawned", + // InstanceId intentionally empty — the orchestrator + // context layer rejects this earlier, but the applier + // also defends against malformed inputs. + }, + }, + }, + } + + applier := runtimestate.NewApplier("caller-app", "") + _, err := applier.Actions(state, nil, actions, nil, nil) + require.Error(t, err) + assert.Contains(t, err.Error(), "instance ID") + assert.Empty(t, state.NewEvents) + assert.Empty(t, state.PendingMessages) +} + func Test_SendEvent(t *testing.T) { expectedInstanceID := "xyz" expectedEventName := "MyEvent" diff --git a/workflow/workflow.go b/workflow/workflow.go index ed752a9..509b5f5 100644 --- a/workflow/workflow.go +++ b/workflow/workflow.go @@ -3,8 +3,9 @@ package workflow import ( "time" - "github.com/dapr/durabletask-go/task" "google.golang.org/protobuf/types/known/wrapperspb" + + "github.com/dapr/durabletask-go/task" ) // Workflow is the functional interface for workflow functions. @@ -14,6 +15,10 @@ type Workflow func(ctx *WorkflowContext) (any, error) // workflow method. type ChildWorkflowOption task.ChildWorkflowOption +// DetachedWorkflowOptions is a functional option type for the +// ScheduleNewWorkflow workflow method. +type DetachedWorkflowOptions task.DetachedWorkflowOptions + // WorkflowContext is the parameter type for workflow functions. type WorkflowContext struct { oc *task.WorkflowContext @@ -64,6 +69,23 @@ func (w *WorkflowContext) CallChildWorkflow(workflow any, opts ...ChildWorkflowO return w.oc.CallChildWorkflow(workflow, oopts...) } +// ScheduleNewWorkflow schedules a new, fully decoupled workflow instance +// from this workflow. Returns the new instance ID synchronously. The +// spawned workflow has no parent linkage: completion and failure do not +// flow back to the caller. If WithDetachedWorkflowInstanceID is not +// provided, a deterministic default ID is generated. +func (w *WorkflowContext) ScheduleNewWorkflow(workflow any, opts ...DetachedWorkflowOptions) (string, error) { + oopts := make([]task.DetachedWorkflowOptions, len(opts)) + for i, o := range opts { + oopts[i] = task.DetachedWorkflowOptions(o) + } + id, err := w.oc.ScheduleNewWorkflow(workflow, oopts...) + if err != nil { + return "", err + } + return string(id), nil +} + // CreateTimer schedules a durable timer that expires after the specified // delay. func (w *WorkflowContext) CreateTimer(delay time.Duration, opts ...CreateTimerOption) Task { @@ -166,3 +188,60 @@ func WithChildWorkflowRetryPolicy(policy *RetryPolicy) ChildWorkflowOption { Handle: policy.Handle, })) } + +// WithDetachedWorkflowInstanceID sets the instance ID of the detached +// workflow. When omitted, ScheduleNewWorkflow generates a deterministic +// ID of the form "-". Passing an empty string is +// rejected as an error: callers either set a non-empty ID or omit the +// option entirely to opt into the default. +func WithDetachedWorkflowInstanceID(instanceID string) DetachedWorkflowOptions { + return DetachedWorkflowOptions(task.WithDetachedWorkflowInstanceID(instanceID)) +} + +// WithDetachedWorkflowInput sets the JSON-marshalled input for the +// detached workflow. +func WithDetachedWorkflowInput(input any) DetachedWorkflowOptions { + return DetachedWorkflowOptions(task.WithDetachedWorkflowInput(input)) +} + +// WithRawDetachedWorkflowInput sets a pre-marshalled raw input on the +// detached workflow. +func WithRawDetachedWorkflowInput(input *wrapperspb.StringValue) DetachedWorkflowOptions { + return DetachedWorkflowOptions(task.WithRawDetachedWorkflowInput(input)) +} + +// WithDetachedWorkflowVersion sets a version label on the detached +// workflow. +func WithDetachedWorkflowVersion(version string) DetachedWorkflowOptions { + return DetachedWorkflowOptions(task.WithDetachedWorkflowVersion(version)) +} + +// WithDetachedWorkflowExecutionID sets an explicit execution ID on the +// detached workflow's first execution. +func WithDetachedWorkflowExecutionID(executionID string) DetachedWorkflowOptions { + return DetachedWorkflowOptions(task.WithDetachedWorkflowExecutionID(executionID)) +} + +// WithDetachedWorkflowStartTime defers the start of the detached workflow +// until the given time. +func WithDetachedWorkflowStartTime(startTime time.Time) DetachedWorkflowOptions { + return DetachedWorkflowOptions(task.WithDetachedWorkflowStartTime(startTime)) +} + +// WithDetachedWorkflowTags sets the tag map on the detached workflow. +func WithDetachedWorkflowTags(tags map[string]string) DetachedWorkflowOptions { + return DetachedWorkflowOptions(task.WithDetachedWorkflowTags(tags)) +} + +// WithDetachedWorkflowAppID specifies the app ID hosting the detached +// workflow. When set, the action carries a routing envelope so the +// dispatcher delivers the new instance to the target app. +func WithDetachedWorkflowAppID(appID string) DetachedWorkflowOptions { + return DetachedWorkflowOptions(task.WithDetachedWorkflowAppID(appID)) +} + +// WithDetachedWorkflowAppNamespace specifies the Dapr namespace hosting +// the detached workflow. Must be combined with WithDetachedWorkflowAppID. +func WithDetachedWorkflowAppNamespace(namespace string) DetachedWorkflowOptions { + return DetachedWorkflowOptions(task.WithDetachedWorkflowAppNamespace(namespace)) +} From a81469d076411c12e7c7f857b64087fc661c27f0 Mon Sep 17 00:00:00 2001 From: Albert Callarisa Date: Fri, 8 May 2026 10:35:07 +0200 Subject: [PATCH 2/3] Addressed PR comments Signed-off-by: Albert Callarisa --- task/detached.go | 232 +++++++++++++++++++++++++++++++++++++++++++ task/orchestrator.go | 219 ---------------------------------------- workflow/detached.go | 87 ++++++++++++++++ workflow/workflow.go | 78 --------------- 4 files changed, 319 insertions(+), 297 deletions(-) create mode 100644 task/detached.go create mode 100644 workflow/detached.go diff --git a/task/detached.go b/task/detached.go new file mode 100644 index 0000000..9770a75 --- /dev/null +++ b/task/detached.go @@ -0,0 +1,232 @@ +package task + +import ( + "fmt" + "strconv" + "time" + + "google.golang.org/protobuf/types/known/timestamppb" + "google.golang.org/protobuf/types/known/wrapperspb" + + "github.com/dapr/durabletask-go/api" + "github.com/dapr/durabletask-go/api/helpers" + "github.com/dapr/durabletask-go/api/protos" +) + +// scheduleNewWorkflowOptions is a struct that holds the options for the +// ScheduleNewWorkflow workflow method. It mirrors the fields of +// CreateInstanceRequest so that a workflow author can spawn a fully +// decoupled instance with the same surface area as the client API. +type scheduleNewWorkflowOptions struct { + instanceID *string + rawInput *wrapperspb.StringValue + version *wrapperspb.StringValue + executionID *wrapperspb.StringValue + scheduledStartTimestamp *timestamppb.Timestamp + tags map[string]string + parentTraceContext *protos.TraceContext + targetAppID *string + targetAppNamespace *string +} + +// DetachedWorkflowOptions is the interface for options passed to +// ScheduleNewWorkflow. Unlike CallChildWorkflow, the spawned instance is +// fire-and-forget: the caller receives the instance ID synchronously but +// does not wait on (and is not notified of) the spawned workflow's +// completion. +type DetachedWorkflowOptions interface { + applyDetachedWorkflowOption(*scheduleNewWorkflowOptions) error +} + +// DetachedWorkflowOptionsFunc adapts a function to the +// DetachedWorkflowOptions interface. +type DetachedWorkflowOptionsFunc func(*scheduleNewWorkflowOptions) error + +func (f DetachedWorkflowOptionsFunc) applyDetachedWorkflowOption(opts *scheduleNewWorkflowOptions) error { + return f(opts) +} + +// WithDetachedWorkflowInstanceID sets the instance ID of the detached +// workflow. When omitted, ScheduleNewWorkflow generates a deterministic +// ID of the form "-" where n increments per +// default-ID spawn within the execution. The '-' separator keeps the +// generated ID safe for consumers (e.g. dapr) that propagate the +// instance id into RFC 1123 subdomain identifiers. Passing an empty +// string is rejected as an error: callers either set a non-empty ID or +// omit the option entirely to opt into the default. +func WithDetachedWorkflowInstanceID(instanceID string) DetachedWorkflowOptionsFunc { + return func(opts *scheduleNewWorkflowOptions) error { + opts.instanceID = &instanceID + return nil + } +} + +// WithDetachedWorkflowInput sets the input for the detached workflow, +// marshalling it to JSON. +func WithDetachedWorkflowInput(input any) DetachedWorkflowOptionsFunc { + return func(opts *scheduleNewWorkflowOptions) error { + bytes, err := marshalData(input) + if err != nil { + return fmt.Errorf("failed to marshal input to JSON: %w", err) + } + opts.rawInput = wrapperspb.String(string(bytes)) + return nil + } +} + +// WithRawDetachedWorkflowInput sets a pre-marshalled raw input on the +// detached workflow. +func WithRawDetachedWorkflowInput(input *wrapperspb.StringValue) DetachedWorkflowOptionsFunc { + return func(opts *scheduleNewWorkflowOptions) error { + opts.rawInput = input + return nil + } +} + +// WithDetachedWorkflowVersion sets a version label on the detached +// workflow. The semantics mirror CreateInstanceRequest.version. +func WithDetachedWorkflowVersion(version string) DetachedWorkflowOptionsFunc { + return func(opts *scheduleNewWorkflowOptions) error { + opts.version = wrapperspb.String(version) + return nil + } +} + +// WithDetachedWorkflowExecutionID sets an explicit execution ID on the +// detached workflow's first execution. When unset, the runtime mints a +// fresh UUID, matching the client ScheduleNewWorkflow behavior. Passing +// an empty string is rejected as an error: callers either set a +// non-empty execution ID or omit the option to opt into UUID minting. +func WithDetachedWorkflowExecutionID(executionID string) DetachedWorkflowOptionsFunc { + return func(opts *scheduleNewWorkflowOptions) error { + if executionID == "" { + return fmt.Errorf("WithDetachedWorkflowExecutionID was passed an empty string; omit the option to let the runtime mint a UUID") + } + opts.executionID = wrapperspb.String(executionID) + return nil + } +} + +// WithDetachedWorkflowStartTime defers the start of the detached workflow +// until the given time. Mirrors api.WithStartTime on the client API. +func WithDetachedWorkflowStartTime(startTime time.Time) DetachedWorkflowOptionsFunc { + return func(opts *scheduleNewWorkflowOptions) error { + opts.scheduledStartTimestamp = timestamppb.New(startTime) + return nil + } +} + +// WithDetachedWorkflowTags sets the tag map on the detached workflow. +func WithDetachedWorkflowTags(tags map[string]string) DetachedWorkflowOptionsFunc { + return func(opts *scheduleNewWorkflowOptions) error { + opts.tags = tags + return nil + } +} + +// WithDetachedWorkflowAppID specifies the app ID hosting the detached +// workflow. When set, the action carries a routing envelope so the +// dispatcher delivers the new instance to the target app. +func WithDetachedWorkflowAppID(appID string) DetachedWorkflowOptionsFunc { + return func(opts *scheduleNewWorkflowOptions) error { + opts.targetAppID = &appID + return nil + } +} + +// WithDetachedWorkflowAppNamespace specifies the Dapr namespace hosting +// the detached workflow. Must be combined with WithDetachedWorkflowAppID; +// see WithChildWorkflowAppNamespace for full semantics. +func WithDetachedWorkflowAppNamespace(namespace string) DetachedWorkflowOptionsFunc { + return func(opts *scheduleNewWorkflowOptions) error { + opts.targetAppNamespace = &namespace + return nil + } +} + +// ScheduleNewWorkflow schedules a new, fully decoupled workflow instance +// from the calling workflow. Unlike CallChildWorkflow, the spawned +// workflow has no parent linkage: its history's ExecutionStartedEvent +// carries no ParentInstanceInfo, completion and failure do not flow back +// to the caller, and the caller receives the new instance ID +// synchronously rather than an awaitable Task. +// +// If WithDetachedWorkflowInstanceID is not provided, a deterministic ID +// of the form "-" is generated, where n increments +// only for default-ID spawns within this execution (so the suffix +// reflects the order of those calls and is stable across replays). The +// '-' separator keeps the generated ID safe for consumers that +// propagate the instance id into RFC 1123 subdomain identifiers. +// +// If the workflow author needs the spawned workflow's result, they should +// model the dependency through external events (RaiseEvent / WaitForEvent) +// or shared state — there is no built-in completion channel. +func (ctx *WorkflowContext) ScheduleNewWorkflow(workflow any, opts ...DetachedWorkflowOptions) (api.InstanceID, error) { + options := new(scheduleNewWorkflowOptions) + for _, configure := range opts { + if err := configure.applyDetachedWorkflowOption(options); err != nil { + return api.EmptyInstanceID, err + } + } + + if options.targetAppNamespace != nil && options.targetAppID == nil { + return api.EmptyInstanceID, fmt.Errorf("WithDetachedWorkflowAppNamespace requires WithDetachedWorkflowAppID to also be set") + } + + var instanceID string + if options.instanceID == nil { + instanceID = string(ctx.ID) + "-" + strconv.FormatInt(int64(ctx.defaultDetachedWorkflowCounter), 10) + ctx.defaultDetachedWorkflowCounter++ + } else if *options.instanceID == "" { + return api.EmptyInstanceID, fmt.Errorf("WithDetachedWorkflowInstanceID was passed an empty string; omit the option to opt into the default ID") + } else { + instanceID = *options.instanceID + } + + workflowName := helpers.GetTaskFunctionName(workflow) + + action := &protos.WorkflowAction{ + Id: ctx.getNextSequenceNumber(), + WorkflowActionType: &protos.WorkflowAction_CreateDetachedWorkflow{ + CreateDetachedWorkflow: &protos.CreateDetachedWorkflowAction{ + InstanceId: instanceID, + Name: workflowName, + Version: options.version, + Input: options.rawInput, + ScheduledStartTimestamp: options.scheduledStartTimestamp, + ExecutionId: options.executionID, + Tags: options.tags, + ParentTraceContext: options.parentTraceContext, + }, + }, + } + + if r := taskRouterFromTarget(options.targetAppID, options.targetAppNamespace); r != nil { + action.Router = r + } + + ctx.pendingActions[action.Id] = action + return api.InstanceID(instanceID), nil +} + +// onDetachedWorkflowCreated retires the pending CreateDetachedWorkflowAction +// at this sequence position. Detached workflows are fire-and-forget, so +// there is no associated pending Task to complete: the call returned the +// instance ID synchronously when the action was emitted. +func (ctx *WorkflowContext) onDetachedWorkflowCreated(taskID int32, dw *protos.DetachedWorkflowInstanceCreatedEvent) error { + a, ok := ctx.pendingActions[taskID] + if !ok || a.GetCreateDetachedWorkflow() == nil { + if ctx.dropOptionalExternalEventTimerAt(taskID) { + a, ok = ctx.pendingActions[taskID] + } + } + if !ok || a.GetCreateDetachedWorkflow() == nil { + return fmt.Errorf( + "a previous execution called ScheduleNewWorkflow for instance ID '%s' and sequence number %d at this point in the workflow logic, but the current execution doesn't have this action with this sequence number", + dw.InstanceId, + taskID, + ) + } + delete(ctx.pendingActions, taskID) + return nil +} diff --git a/task/orchestrator.go b/task/orchestrator.go index a2635a1..43fbbb1 100644 --- a/task/orchestrator.go +++ b/task/orchestrator.go @@ -6,7 +6,6 @@ import ( "math" "reflect" "sort" - "strconv" "strings" "time" @@ -174,137 +173,6 @@ func WithChildWorkflowRetryPolicy(policy *RetryPolicy) ChildWorkflowOptionFunc { } } -// scheduleNewWorkflowOptions is a struct that holds the options for the -// ScheduleNewWorkflow workflow method. It mirrors the fields of -// CreateInstanceRequest so that a workflow author can spawn a fully -// decoupled instance with the same surface area as the client API. -type scheduleNewWorkflowOptions struct { - instanceID *string - rawInput *wrapperspb.StringValue - version *wrapperspb.StringValue - executionID *wrapperspb.StringValue - scheduledStartTimestamp *timestamppb.Timestamp - tags map[string]string - parentTraceContext *protos.TraceContext - targetAppID *string - targetAppNamespace *string -} - -// DetachedWorkflowOptions is the interface for options passed to -// ScheduleNewWorkflow. Unlike CallChildWorkflow, the spawned instance is -// fire-and-forget: the caller receives the instance ID synchronously but -// does not wait on (and is not notified of) the spawned workflow's -// completion. -type DetachedWorkflowOptions interface { - applyDetachedWorkflowOption(*scheduleNewWorkflowOptions) error -} - -// DetachedWorkflowOptionsFunc adapts a function to the -// DetachedWorkflowOptions interface. -type DetachedWorkflowOptionsFunc func(*scheduleNewWorkflowOptions) error - -func (f DetachedWorkflowOptionsFunc) applyDetachedWorkflowOption(opts *scheduleNewWorkflowOptions) error { - return f(opts) -} - -// WithDetachedWorkflowInstanceID sets the instance ID of the detached -// workflow. When omitted, ScheduleNewWorkflow generates a deterministic -// ID of the form "-" where n increments per -// default-ID spawn within the execution. The '-' separator keeps the -// generated ID safe for consumers (e.g. dapr) that propagate the -// instance id into RFC 1123 subdomain identifiers. Passing an empty -// string is rejected as an error: callers either set a non-empty ID or -// omit the option entirely to opt into the default. -func WithDetachedWorkflowInstanceID(instanceID string) DetachedWorkflowOptionsFunc { - return func(opts *scheduleNewWorkflowOptions) error { - opts.instanceID = &instanceID - return nil - } -} - -// WithDetachedWorkflowInput sets the input for the detached workflow, -// marshalling it to JSON. -func WithDetachedWorkflowInput(input any) DetachedWorkflowOptionsFunc { - return func(opts *scheduleNewWorkflowOptions) error { - bytes, err := marshalData(input) - if err != nil { - return fmt.Errorf("failed to marshal input to JSON: %w", err) - } - opts.rawInput = wrapperspb.String(string(bytes)) - return nil - } -} - -// WithRawDetachedWorkflowInput sets a pre-marshalled raw input on the -// detached workflow. -func WithRawDetachedWorkflowInput(input *wrapperspb.StringValue) DetachedWorkflowOptionsFunc { - return func(opts *scheduleNewWorkflowOptions) error { - opts.rawInput = input - return nil - } -} - -// WithDetachedWorkflowVersion sets a version label on the detached -// workflow. The semantics mirror CreateInstanceRequest.version. -func WithDetachedWorkflowVersion(version string) DetachedWorkflowOptionsFunc { - return func(opts *scheduleNewWorkflowOptions) error { - opts.version = wrapperspb.String(version) - return nil - } -} - -// WithDetachedWorkflowExecutionID sets an explicit execution ID on the -// detached workflow's first execution. When unset, the runtime mints a -// fresh UUID, matching the client ScheduleNewWorkflow behavior. Passing -// an empty string is rejected as an error: callers either set a -// non-empty execution ID or omit the option to opt into UUID minting. -func WithDetachedWorkflowExecutionID(executionID string) DetachedWorkflowOptionsFunc { - return func(opts *scheduleNewWorkflowOptions) error { - if executionID == "" { - return fmt.Errorf("WithDetachedWorkflowExecutionID was passed an empty string; omit the option to let the runtime mint a UUID") - } - opts.executionID = wrapperspb.String(executionID) - return nil - } -} - -// WithDetachedWorkflowStartTime defers the start of the detached workflow -// until the given time. Mirrors api.WithStartTime on the client API. -func WithDetachedWorkflowStartTime(startTime time.Time) DetachedWorkflowOptionsFunc { - return func(opts *scheduleNewWorkflowOptions) error { - opts.scheduledStartTimestamp = timestamppb.New(startTime) - return nil - } -} - -// WithDetachedWorkflowTags sets the tag map on the detached workflow. -func WithDetachedWorkflowTags(tags map[string]string) DetachedWorkflowOptionsFunc { - return func(opts *scheduleNewWorkflowOptions) error { - opts.tags = tags - return nil - } -} - -// WithDetachedWorkflowAppID specifies the app ID hosting the detached -// workflow. When set, the action carries a routing envelope so the -// dispatcher delivers the new instance to the target app. -func WithDetachedWorkflowAppID(appID string) DetachedWorkflowOptionsFunc { - return func(opts *scheduleNewWorkflowOptions) error { - opts.targetAppID = &appID - return nil - } -} - -// WithDetachedWorkflowAppNamespace specifies the Dapr namespace hosting -// the detached workflow. Must be combined with WithDetachedWorkflowAppID; -// see WithChildWorkflowAppNamespace for full semantics. -func WithDetachedWorkflowAppNamespace(namespace string) DetachedWorkflowOptionsFunc { - return func(opts *scheduleNewWorkflowOptions) error { - opts.targetAppNamespace = &namespace - return nil - } -} - // NewWorkflowContext returns a new [WorkflowContext] struct with the specified parameters. func NewWorkflowContext(registry *TaskRegistry, id api.InstanceID, oldEvents []*protos.HistoryEvent, newEvents []*protos.HistoryEvent) *WorkflowContext { return &WorkflowContext{ @@ -599,71 +467,6 @@ func (ctx *WorkflowContext) internalCallChildWorkflow(workflowName string, optio return task } -// ScheduleNewWorkflow schedules a new, fully decoupled workflow instance -// from the calling workflow. Unlike CallChildWorkflow, the spawned -// workflow has no parent linkage: its history's ExecutionStartedEvent -// carries no ParentInstanceInfo, completion and failure do not flow back -// to the caller, and the caller receives the new instance ID -// synchronously rather than an awaitable Task. -// -// If WithDetachedWorkflowInstanceID is not provided, a deterministic ID -// of the form "-" is generated, where n increments -// only for default-ID spawns within this execution (so the suffix -// reflects the order of those calls and is stable across replays). The -// '-' separator keeps the generated ID safe for consumers that -// propagate the instance id into RFC 1123 subdomain identifiers. -// -// If the workflow author needs the spawned workflow's result, they should -// model the dependency through external events (RaiseEvent / WaitForEvent) -// or shared state — there is no built-in completion channel. -func (ctx *WorkflowContext) ScheduleNewWorkflow(workflow any, opts ...DetachedWorkflowOptions) (api.InstanceID, error) { - options := new(scheduleNewWorkflowOptions) - for _, configure := range opts { - if err := configure.applyDetachedWorkflowOption(options); err != nil { - return api.EmptyInstanceID, err - } - } - - if options.targetAppNamespace != nil && options.targetAppID == nil { - return api.EmptyInstanceID, fmt.Errorf("WithDetachedWorkflowAppNamespace requires WithDetachedWorkflowAppID to also be set") - } - - var instanceID string - if options.instanceID == nil { - instanceID = string(ctx.ID) + "-" + strconv.FormatInt(int64(ctx.defaultDetachedWorkflowCounter), 10) - ctx.defaultDetachedWorkflowCounter++ - } else if *options.instanceID == "" { - return api.EmptyInstanceID, fmt.Errorf("WithDetachedWorkflowInstanceID was passed an empty string; omit the option to opt into the default ID") - } else { - instanceID = *options.instanceID - } - - workflowName := helpers.GetTaskFunctionName(workflow) - - action := &protos.WorkflowAction{ - Id: ctx.getNextSequenceNumber(), - WorkflowActionType: &protos.WorkflowAction_CreateDetachedWorkflow{ - CreateDetachedWorkflow: &protos.CreateDetachedWorkflowAction{ - InstanceId: instanceID, - Name: workflowName, - Version: options.version, - Input: options.rawInput, - ScheduledStartTimestamp: options.scheduledStartTimestamp, - ExecutionId: options.executionID, - Tags: options.tags, - ParentTraceContext: options.parentTraceContext, - }, - }, - } - - if r := taskRouterFromTarget(options.targetAppID, options.targetAppNamespace); r != nil { - action.Router = r - } - - ctx.pendingActions[action.Id] = action - return api.InstanceID(instanceID), nil -} - func (ctx *WorkflowContext) internalScheduleTaskWithRetries(name string, initialAttempt time.Time, schedule func(taskExecutionId string) Task, policy RetryPolicy, retryCount int, taskExecutionId string, setTimerOrigin func(*protos.CreateTimerAction, string)) Task { return &taskWrapper{ delegate: schedule(taskExecutionId), @@ -987,28 +790,6 @@ func (ctx *WorkflowContext) onChildWorkflowScheduled(taskID int32, ts *protos.Ch return nil } -// onDetachedWorkflowCreated retires the pending CreateDetachedWorkflowAction -// at this sequence position. Detached workflows are fire-and-forget, so -// there is no associated pending Task to complete: the call returned the -// instance ID synchronously when the action was emitted. -func (ctx *WorkflowContext) onDetachedWorkflowCreated(taskID int32, dw *protos.DetachedWorkflowInstanceCreatedEvent) error { - a, ok := ctx.pendingActions[taskID] - if !ok || a.GetCreateDetachedWorkflow() == nil { - if ctx.dropOptionalExternalEventTimerAt(taskID) { - a, ok = ctx.pendingActions[taskID] - } - } - if !ok || a.GetCreateDetachedWorkflow() == nil { - return fmt.Errorf( - "a previous execution called ScheduleNewWorkflow for instance ID '%s' and sequence number %d at this point in the workflow logic, but the current execution doesn't have this action with this sequence number", - dw.InstanceId, - taskID, - ) - } - delete(ctx.pendingActions, taskID) - return nil -} - func (ctx *WorkflowContext) onChildWorkflowCompleted(soc *protos.ChildWorkflowInstanceCompletedEvent) error { taskID := soc.TaskScheduledId task, ok := ctx.pendingTasks[taskID] diff --git a/workflow/detached.go b/workflow/detached.go new file mode 100644 index 0000000..140c46a --- /dev/null +++ b/workflow/detached.go @@ -0,0 +1,87 @@ +package workflow + +import ( + "time" + + "google.golang.org/protobuf/types/known/wrapperspb" + + "github.com/dapr/durabletask-go/task" +) + +// DetachedWorkflowOptions is a functional option type for the +// ScheduleNewWorkflow workflow method. +type DetachedWorkflowOptions task.DetachedWorkflowOptions + +// ScheduleNewWorkflow schedules a new, fully decoupled workflow instance +// from this workflow. Returns the new instance ID synchronously. The +// spawned workflow has no parent linkage: completion and failure do not +// flow back to the caller. If WithDetachedWorkflowInstanceID is not +// provided, a deterministic default ID is generated. +func (w *WorkflowContext) ScheduleNewWorkflow(workflow any, opts ...DetachedWorkflowOptions) (string, error) { + oopts := make([]task.DetachedWorkflowOptions, len(opts)) + for i, o := range opts { + oopts[i] = task.DetachedWorkflowOptions(o) + } + id, err := w.oc.ScheduleNewWorkflow(workflow, oopts...) + if err != nil { + return "", err + } + return string(id), nil +} + +// WithDetachedWorkflowInstanceID sets the instance ID of the detached +// workflow. When omitted, ScheduleNewWorkflow generates a deterministic +// ID of the form "-". Passing an empty string is +// rejected as an error: callers either set a non-empty ID or omit the +// option entirely to opt into the default. +func WithDetachedWorkflowInstanceID(instanceID string) DetachedWorkflowOptions { + return DetachedWorkflowOptions(task.WithDetachedWorkflowInstanceID(instanceID)) +} + +// WithDetachedWorkflowInput sets the JSON-marshalled input for the +// detached workflow. +func WithDetachedWorkflowInput(input any) DetachedWorkflowOptions { + return DetachedWorkflowOptions(task.WithDetachedWorkflowInput(input)) +} + +// WithRawDetachedWorkflowInput sets a pre-marshalled raw input on the +// detached workflow. +func WithRawDetachedWorkflowInput(input *wrapperspb.StringValue) DetachedWorkflowOptions { + return DetachedWorkflowOptions(task.WithRawDetachedWorkflowInput(input)) +} + +// WithDetachedWorkflowVersion sets a version label on the detached +// workflow. +func WithDetachedWorkflowVersion(version string) DetachedWorkflowOptions { + return DetachedWorkflowOptions(task.WithDetachedWorkflowVersion(version)) +} + +// WithDetachedWorkflowExecutionID sets an explicit execution ID on the +// detached workflow's first execution. +func WithDetachedWorkflowExecutionID(executionID string) DetachedWorkflowOptions { + return DetachedWorkflowOptions(task.WithDetachedWorkflowExecutionID(executionID)) +} + +// WithDetachedWorkflowStartTime defers the start of the detached workflow +// until the given time. +func WithDetachedWorkflowStartTime(startTime time.Time) DetachedWorkflowOptions { + return DetachedWorkflowOptions(task.WithDetachedWorkflowStartTime(startTime)) +} + +// WithDetachedWorkflowTags sets the tag map on the detached workflow. +func WithDetachedWorkflowTags(tags map[string]string) DetachedWorkflowOptions { + return DetachedWorkflowOptions(task.WithDetachedWorkflowTags(tags)) +} + +// WithDetachedWorkflowAppID specifies the app ID hosting the detached +// workflow. When set, the action carries a routing envelope so the +// dispatcher delivers the new instance to the target app. +func WithDetachedWorkflowAppID(appID string) DetachedWorkflowOptions { + return DetachedWorkflowOptions(task.WithDetachedWorkflowAppID(appID)) +} + +// WithDetachedWorkflowAppNamespace specifies the Dapr namespace hosting +// the detached workflow. Must be combined with WithDetachedWorkflowAppID. +func WithDetachedWorkflowAppNamespace(namespace string) DetachedWorkflowOptions { + return DetachedWorkflowOptions(task.WithDetachedWorkflowAppNamespace(namespace)) +} diff --git a/workflow/workflow.go b/workflow/workflow.go index 509b5f5..54fb350 100644 --- a/workflow/workflow.go +++ b/workflow/workflow.go @@ -15,10 +15,6 @@ type Workflow func(ctx *WorkflowContext) (any, error) // workflow method. type ChildWorkflowOption task.ChildWorkflowOption -// DetachedWorkflowOptions is a functional option type for the -// ScheduleNewWorkflow workflow method. -type DetachedWorkflowOptions task.DetachedWorkflowOptions - // WorkflowContext is the parameter type for workflow functions. type WorkflowContext struct { oc *task.WorkflowContext @@ -69,23 +65,6 @@ func (w *WorkflowContext) CallChildWorkflow(workflow any, opts ...ChildWorkflowO return w.oc.CallChildWorkflow(workflow, oopts...) } -// ScheduleNewWorkflow schedules a new, fully decoupled workflow instance -// from this workflow. Returns the new instance ID synchronously. The -// spawned workflow has no parent linkage: completion and failure do not -// flow back to the caller. If WithDetachedWorkflowInstanceID is not -// provided, a deterministic default ID is generated. -func (w *WorkflowContext) ScheduleNewWorkflow(workflow any, opts ...DetachedWorkflowOptions) (string, error) { - oopts := make([]task.DetachedWorkflowOptions, len(opts)) - for i, o := range opts { - oopts[i] = task.DetachedWorkflowOptions(o) - } - id, err := w.oc.ScheduleNewWorkflow(workflow, oopts...) - if err != nil { - return "", err - } - return string(id), nil -} - // CreateTimer schedules a durable timer that expires after the specified // delay. func (w *WorkflowContext) CreateTimer(delay time.Duration, opts ...CreateTimerOption) Task { @@ -188,60 +167,3 @@ func WithChildWorkflowRetryPolicy(policy *RetryPolicy) ChildWorkflowOption { Handle: policy.Handle, })) } - -// WithDetachedWorkflowInstanceID sets the instance ID of the detached -// workflow. When omitted, ScheduleNewWorkflow generates a deterministic -// ID of the form "-". Passing an empty string is -// rejected as an error: callers either set a non-empty ID or omit the -// option entirely to opt into the default. -func WithDetachedWorkflowInstanceID(instanceID string) DetachedWorkflowOptions { - return DetachedWorkflowOptions(task.WithDetachedWorkflowInstanceID(instanceID)) -} - -// WithDetachedWorkflowInput sets the JSON-marshalled input for the -// detached workflow. -func WithDetachedWorkflowInput(input any) DetachedWorkflowOptions { - return DetachedWorkflowOptions(task.WithDetachedWorkflowInput(input)) -} - -// WithRawDetachedWorkflowInput sets a pre-marshalled raw input on the -// detached workflow. -func WithRawDetachedWorkflowInput(input *wrapperspb.StringValue) DetachedWorkflowOptions { - return DetachedWorkflowOptions(task.WithRawDetachedWorkflowInput(input)) -} - -// WithDetachedWorkflowVersion sets a version label on the detached -// workflow. -func WithDetachedWorkflowVersion(version string) DetachedWorkflowOptions { - return DetachedWorkflowOptions(task.WithDetachedWorkflowVersion(version)) -} - -// WithDetachedWorkflowExecutionID sets an explicit execution ID on the -// detached workflow's first execution. -func WithDetachedWorkflowExecutionID(executionID string) DetachedWorkflowOptions { - return DetachedWorkflowOptions(task.WithDetachedWorkflowExecutionID(executionID)) -} - -// WithDetachedWorkflowStartTime defers the start of the detached workflow -// until the given time. -func WithDetachedWorkflowStartTime(startTime time.Time) DetachedWorkflowOptions { - return DetachedWorkflowOptions(task.WithDetachedWorkflowStartTime(startTime)) -} - -// WithDetachedWorkflowTags sets the tag map on the detached workflow. -func WithDetachedWorkflowTags(tags map[string]string) DetachedWorkflowOptions { - return DetachedWorkflowOptions(task.WithDetachedWorkflowTags(tags)) -} - -// WithDetachedWorkflowAppID specifies the app ID hosting the detached -// workflow. When set, the action carries a routing envelope so the -// dispatcher delivers the new instance to the target app. -func WithDetachedWorkflowAppID(appID string) DetachedWorkflowOptions { - return DetachedWorkflowOptions(task.WithDetachedWorkflowAppID(appID)) -} - -// WithDetachedWorkflowAppNamespace specifies the Dapr namespace hosting -// the detached workflow. Must be combined with WithDetachedWorkflowAppID. -func WithDetachedWorkflowAppNamespace(namespace string) DetachedWorkflowOptions { - return DetachedWorkflowOptions(task.WithDetachedWorkflowAppNamespace(namespace)) -} From 4ec0334282703f73296d9c99ab60186d2199a98f Mon Sep 17 00:00:00 2001 From: Albert Callarisa Date: Fri, 8 May 2026 16:59:45 +0200 Subject: [PATCH 3/3] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Albert Callarisa --- tests/orchestrations_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/orchestrations_test.go b/tests/orchestrations_test.go index 7ddfa25..3b67598 100644 --- a/tests/orchestrations_test.go +++ b/tests/orchestrations_test.go @@ -631,7 +631,7 @@ func Test_DetachedWorkflow_HappyPath(t *testing.T) { func Test_DetachedWorkflow_DefaultInstanceID(t *testing.T) { r := task.NewTaskRegistry() r.AddWorkflowN("Caller", func(ctx *task.WorkflowContext) (any, error) { - // First default-ID spawn → "/0". + // First default-ID spawn → "-0". spawnedID, err := ctx.ScheduleNewWorkflow("Spawned") if err != nil { return nil, err