mirror of
https://github.com/temporalio/temporal.git
synced 2026-08-30 18:41:49 -07:00
Send raw history events from history to frontend service (#7342)
## What changed? Change to send raw history blobs from history service to frontend service. History service returns a new proto message that has a repeated bytes history field. This response is wire compatible with the original response which has temporal.api.history.v1.History type for this field. This allows history service to not deserialize events from this data blob. This considerably reduces CPU usage. History service still needs event_id and version decoded from history events. For this we use a new proto message StrippedHistoryEvent which has these two fields only. It takes considerably less CPU to decode events to this struct. ## Why? We have seen incidents of high history CPU usage when large number of GetWorkflowExecutionHistory calls are made to workflows which has large history. With this change we can reduce the CPU burden on history service during this API call. ## How did you test it? Existing unit and functional tests. ## Potential risks ## Documentation ## Is hotfix candidate?
This commit is contained in:
@@ -250,3 +250,77 @@ func (this *TaskRange) Equal(that interface{}) bool {
|
||||
|
||||
return proto.Equal(this, that1)
|
||||
}
|
||||
|
||||
// Marshal an object of type StrippedHistoryEvent to the protobuf v3 wire format
|
||||
func (val *StrippedHistoryEvent) Marshal() ([]byte, error) {
|
||||
return proto.Marshal(val)
|
||||
}
|
||||
|
||||
// Unmarshal an object of type StrippedHistoryEvent from the protobuf v3 wire format
|
||||
func (val *StrippedHistoryEvent) Unmarshal(buf []byte) error {
|
||||
return proto.Unmarshal(buf, val)
|
||||
}
|
||||
|
||||
// Size returns the size of the object, in bytes, once serialized
|
||||
func (val *StrippedHistoryEvent) Size() int {
|
||||
return proto.Size(val)
|
||||
}
|
||||
|
||||
// Equal returns whether two StrippedHistoryEvent values are equivalent by recursively
|
||||
// comparing the message's fields.
|
||||
// For more information see the documentation for
|
||||
// https://pkg.go.dev/google.golang.org/protobuf/proto#Equal
|
||||
func (this *StrippedHistoryEvent) Equal(that interface{}) bool {
|
||||
if that == nil {
|
||||
return this == nil
|
||||
}
|
||||
|
||||
var that1 *StrippedHistoryEvent
|
||||
switch t := that.(type) {
|
||||
case *StrippedHistoryEvent:
|
||||
that1 = t
|
||||
case StrippedHistoryEvent:
|
||||
that1 = &t
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
return proto.Equal(this, that1)
|
||||
}
|
||||
|
||||
// Marshal an object of type StrippedHistoryEvents to the protobuf v3 wire format
|
||||
func (val *StrippedHistoryEvents) Marshal() ([]byte, error) {
|
||||
return proto.Marshal(val)
|
||||
}
|
||||
|
||||
// Unmarshal an object of type StrippedHistoryEvents from the protobuf v3 wire format
|
||||
func (val *StrippedHistoryEvents) Unmarshal(buf []byte) error {
|
||||
return proto.Unmarshal(buf, val)
|
||||
}
|
||||
|
||||
// Size returns the size of the object, in bytes, once serialized
|
||||
func (val *StrippedHistoryEvents) Size() int {
|
||||
return proto.Size(val)
|
||||
}
|
||||
|
||||
// Equal returns whether two StrippedHistoryEvents values are equivalent by recursively
|
||||
// comparing the message's fields.
|
||||
// For more information see the documentation for
|
||||
// https://pkg.go.dev/google.golang.org/protobuf/proto#Equal
|
||||
func (this *StrippedHistoryEvents) Equal(that interface{}) bool {
|
||||
if that == nil {
|
||||
return this == nil
|
||||
}
|
||||
|
||||
var that1 *StrippedHistoryEvents
|
||||
switch t := that.(type) {
|
||||
case *StrippedHistoryEvents:
|
||||
that1 = t
|
||||
case StrippedHistoryEvents:
|
||||
that1 = &t
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
return proto.Equal(this, that1)
|
||||
}
|
||||
|
||||
@@ -371,71 +371,185 @@ func (x *TaskRange) GetExclusiveMaxTaskKey() *TaskKey {
|
||||
return nil
|
||||
}
|
||||
|
||||
// StrippedHistoryEvent is a stripped down version of HistoryEvent that only contains the event_id and version.
|
||||
type StrippedHistoryEvent struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
EventId int64 `protobuf:"varint,1,opt,name=event_id,json=eventId,proto3" json:"event_id,omitempty"`
|
||||
Version int64 `protobuf:"varint,4,opt,name=version,proto3" json:"version,omitempty"`
|
||||
}
|
||||
|
||||
func (x *StrippedHistoryEvent) Reset() {
|
||||
*x = StrippedHistoryEvent{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_temporal_server_api_history_v1_message_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *StrippedHistoryEvent) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*StrippedHistoryEvent) ProtoMessage() {}
|
||||
|
||||
func (x *StrippedHistoryEvent) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_temporal_server_api_history_v1_message_proto_msgTypes[6]
|
||||
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 StrippedHistoryEvent.ProtoReflect.Descriptor instead.
|
||||
func (*StrippedHistoryEvent) Descriptor() ([]byte, []int) {
|
||||
return file_temporal_server_api_history_v1_message_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *StrippedHistoryEvent) GetEventId() int64 {
|
||||
if x != nil {
|
||||
return x.EventId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *StrippedHistoryEvent) GetVersion() int64 {
|
||||
if x != nil {
|
||||
return x.Version
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type StrippedHistoryEvents struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Events []*StrippedHistoryEvent `protobuf:"bytes,1,rep,name=events,proto3" json:"events,omitempty"`
|
||||
}
|
||||
|
||||
func (x *StrippedHistoryEvents) Reset() {
|
||||
*x = StrippedHistoryEvents{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_temporal_server_api_history_v1_message_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *StrippedHistoryEvents) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*StrippedHistoryEvents) ProtoMessage() {}
|
||||
|
||||
func (x *StrippedHistoryEvents) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_temporal_server_api_history_v1_message_proto_msgTypes[7]
|
||||
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 StrippedHistoryEvents.ProtoReflect.Descriptor instead.
|
||||
func (*StrippedHistoryEvents) Descriptor() ([]byte, []int) {
|
||||
return file_temporal_server_api_history_v1_message_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *StrippedHistoryEvents) GetEvents() []*StrippedHistoryEvent {
|
||||
if x != nil {
|
||||
return x.Events
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_temporal_server_api_history_v1_message_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_temporal_server_api_history_v1_message_proto_rawDesc = []byte{
|
||||
0x0a, 0x2c, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||
0x2f, 0x61, 0x70, 0x69, 0x2f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x76, 0x31, 0x2f, 0x6d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1e, 0x74, 0x65, 0x6d,
|
||||
0x70, 0x6f, 0x72, 0x61, 0x6c, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69,
|
||||
0x2e, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67,
|
||||
0x70, 0x6f, 0x72, 0x61, 0x6c, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67,
|
||||
0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73,
|
||||
0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x25, 0x74, 0x65, 0x6d, 0x70, 0x6f,
|
||||
0x72, 0x61, 0x6c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x2f,
|
||||
0x76, 0x31, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
|
||||
0x79, 0x0a, 0x19, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x65, 0x6e, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66,
|
||||
0x72, 0x61, 0x6c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x76,
|
||||
0x31, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x79,
|
||||
0x0a, 0x19, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x65, 0x6e, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66,
|
||||
0x6c, 0x6f, 0x77, 0x54, 0x61, 0x73, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x50, 0x0a, 0x0e, 0x68, 0x69,
|
||||
0x73, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x18, 0x03, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x25, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x2e, 0x61, 0x70, 0x69,
|
||||
0x2e, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f,
|
||||
0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x0d, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79,
|
||||
0x53, 0x75, 0x66, 0x66, 0x69, 0x78, 0x42, 0x02, 0x68, 0x00, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a,
|
||||
0x04, 0x08, 0x02, 0x10, 0x03, 0x22, 0x51, 0x0a, 0x12, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48,
|
||||
0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1d, 0x0a, 0x08, 0x65, 0x76, 0x65,
|
||||
0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65, 0x76, 0x65,
|
||||
0x73, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x18, 0x03, 0x20, 0x03, 0x28,
|
||||
0x0b, 0x32, 0x25, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f,
|
||||
0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x0d, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x53,
|
||||
0x75, 0x66, 0x66, 0x69, 0x78, 0x42, 0x02, 0x68, 0x00, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04,
|
||||
0x08, 0x02, 0x10, 0x03, 0x22, 0x51, 0x0a, 0x12, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x69,
|
||||
0x73, 0x74, 0x6f, 0x72, 0x79, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1d, 0x0a, 0x08, 0x65, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x49, 0x64, 0x42, 0x02, 0x68, 0x00, 0x12, 0x1c, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
|
||||
0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42,
|
||||
0x02, 0x68, 0x00, 0x22, 0x85, 0x01, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x69,
|
||||
0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x25, 0x0a, 0x0c, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x5f,
|
||||
0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x62, 0x72, 0x61, 0x6e,
|
||||
0x63, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x02, 0x68, 0x00, 0x12, 0x4c, 0x0a, 0x05, 0x69, 0x74,
|
||||
0x65, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6f,
|
||||
0x72, 0x61, 0x6c, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x68, 0x69,
|
||||
0x73, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d,
|
||||
0x73, 0x42, 0x02, 0x68, 0x00, 0x22, 0xab, 0x01, 0x0a, 0x10, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x12, 0x45, 0x0a, 0x1d, 0x63, 0x75, 0x72, 0x72,
|
||||
0x65, 0x6e, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x69, 0x73, 0x74, 0x6f,
|
||||
0x72, 0x79, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x1a,
|
||||
0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x69, 0x73,
|
||||
0x74, 0x6f, 0x72, 0x79, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x02, 0x68, 0x00, 0x12, 0x50, 0x0a, 0x09,
|
||||
0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e,
|
||||
0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x56,
|
||||
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x09, 0x68, 0x69,
|
||||
0x73, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x42, 0x02, 0x68, 0x00, 0x22, 0x63, 0x0a, 0x07, 0x54, 0x61,
|
||||
0x73, 0x6b, 0x4b, 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x42, 0x02, 0x68,
|
||||
0x00, 0x12, 0x3b, 0x0a, 0x09, 0x66, 0x69, 0x72, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 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, 0x08, 0x66,
|
||||
0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x42, 0x02, 0x68, 0x00, 0x22, 0xcf, 0x01, 0x0a, 0x09,
|
||||
0x54, 0x61, 0x73, 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x60, 0x0a, 0x16, 0x69, 0x6e, 0x63, 0x6c,
|
||||
0x75, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x6b, 0x65,
|
||||
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61,
|
||||
0x6c, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x68, 0x69, 0x73, 0x74,
|
||||
0x6f, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x4b, 0x65, 0x79, 0x52, 0x13,
|
||||
0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x4d, 0x69, 0x6e, 0x54, 0x61, 0x73, 0x6b, 0x4b,
|
||||
0x65, 0x79, 0x42, 0x02, 0x68, 0x00, 0x12, 0x60, 0x0a, 0x16, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69,
|
||||
0x76, 0x65, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x2e,
|
||||
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72,
|
||||
0x79, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x4b, 0x65, 0x79, 0x52, 0x13, 0x65, 0x78, 0x63,
|
||||
0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x78, 0x54, 0x61, 0x73, 0x6b, 0x4b, 0x65, 0x79, 0x42,
|
||||
0x02, 0x68, 0x00, 0x22, 0x53, 0x0a, 0x14, 0x53, 0x74, 0x72, 0x69, 0x70, 0x70, 0x65, 0x64, 0x48, 0x69,
|
||||
0x73, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x08, 0x65, 0x76,
|
||||
0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65, 0x76, 0x65,
|
||||
0x6e, 0x74, 0x49, 0x64, 0x42, 0x02, 0x68, 0x00, 0x12, 0x1c, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x42, 0x02, 0x68, 0x00, 0x22, 0x85, 0x01, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48,
|
||||
0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x25, 0x0a, 0x0c, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68,
|
||||
0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x62, 0x72, 0x61,
|
||||
0x6e, 0x63, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x02, 0x68, 0x00, 0x12, 0x4c, 0x0a, 0x05, 0x69,
|
||||
0x74, 0x65, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x65, 0x6d,
|
||||
0x70, 0x6f, 0x72, 0x61, 0x6c, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
|
||||
0x6e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65,
|
||||
0x6d, 0x73, 0x42, 0x02, 0x68, 0x00, 0x22, 0xab, 0x01, 0x0a, 0x10, 0x56, 0x65, 0x72, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x12, 0x45, 0x0a, 0x1d, 0x63, 0x75,
|
||||
0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x69, 0x73,
|
||||
0x74, 0x6f, 0x72, 0x79, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||
0x1a, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48,
|
||||
0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x02, 0x68, 0x00, 0x12, 0x50,
|
||||
0x0a, 0x09, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x2e, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x2e, 0x73, 0x65, 0x72, 0x76,
|
||||
0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x09,
|
||||
0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x42, 0x02, 0x68, 0x00, 0x22, 0x63, 0x0a, 0x07,
|
||||
0x54, 0x61, 0x73, 0x6b, 0x4b, 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f,
|
||||
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x42,
|
||||
0x02, 0x68, 0x00, 0x12, 0x3b, 0x0a, 0x09, 0x66, 0x69, 0x72, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 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, 0x08, 0x66, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x42, 0x02, 0x68, 0x00, 0x22, 0xcf, 0x01,
|
||||
0x0a, 0x09, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x60, 0x0a, 0x16, 0x69, 0x6e,
|
||||
0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x5f,
|
||||
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6d, 0x70,
|
||||
0x6f, 0x72, 0x61, 0x6c, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x68,
|
||||
0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x4b, 0x65, 0x79,
|
||||
0x52, 0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x4d, 0x69, 0x6e, 0x54, 0x61,
|
||||
0x73, 0x6b, 0x4b, 0x65, 0x79, 0x42, 0x02, 0x68, 0x00, 0x12, 0x60, 0x0a, 0x16, 0x65, 0x78, 0x63, 0x6c,
|
||||
0x75, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x6b, 0x65,
|
||||
0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61,
|
||||
0x6c, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x68, 0x69, 0x73,
|
||||
0x74, 0x6f, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x4b, 0x65, 0x79, 0x52, 0x13,
|
||||
0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x78, 0x54, 0x61, 0x73, 0x6b, 0x4b,
|
||||
0x65, 0x79, 0x42, 0x02, 0x68, 0x00, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x6f, 0x2e, 0x74, 0x65, 0x6d, 0x70,
|
||||
0x6f, 0x72, 0x61, 0x6c, 0x2e, 0x69, 0x6f, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x61,
|
||||
0x70, 0x69, 0x2f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x76, 0x31, 0x3b, 0x68, 0x69, 0x73,
|
||||
0x74, 0x6f, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x42, 0x02, 0x68, 0x00, 0x22, 0x69, 0x0a, 0x15, 0x53, 0x74, 0x72, 0x69, 0x70, 0x70, 0x65, 0x64, 0x48,
|
||||
0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x06,
|
||||
0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x74, 0x65,
|
||||
0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69,
|
||||
0x2e, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x70,
|
||||
0x70, 0x65, 0x64, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52,
|
||||
0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x02, 0x68, 0x00, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x6f,
|
||||
0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x2e, 0x69, 0x6f, 0x2f, 0x73, 0x65, 0x72, 0x76,
|
||||
0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x76, 0x31,
|
||||
0x3b, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -450,7 +564,7 @@ func file_temporal_server_api_history_v1_message_proto_rawDescGZIP() []byte {
|
||||
return file_temporal_server_api_history_v1_message_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_temporal_server_api_history_v1_message_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||
var file_temporal_server_api_history_v1_message_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
|
||||
var file_temporal_server_api_history_v1_message_proto_goTypes = []interface{}{
|
||||
(*TransientWorkflowTaskInfo)(nil), // 0: temporal.server.api.history.v1.TransientWorkflowTaskInfo
|
||||
(*VersionHistoryItem)(nil), // 1: temporal.server.api.history.v1.VersionHistoryItem
|
||||
@@ -458,21 +572,24 @@ var file_temporal_server_api_history_v1_message_proto_goTypes = []interface{}{
|
||||
(*VersionHistories)(nil), // 3: temporal.server.api.history.v1.VersionHistories
|
||||
(*TaskKey)(nil), // 4: temporal.server.api.history.v1.TaskKey
|
||||
(*TaskRange)(nil), // 5: temporal.server.api.history.v1.TaskRange
|
||||
(*v1.HistoryEvent)(nil), // 6: temporal.api.history.v1.HistoryEvent
|
||||
(*timestamppb.Timestamp)(nil), // 7: google.protobuf.Timestamp
|
||||
(*StrippedHistoryEvent)(nil), // 6: temporal.server.api.history.v1.StrippedHistoryEvent
|
||||
(*StrippedHistoryEvents)(nil), // 7: temporal.server.api.history.v1.StrippedHistoryEvents
|
||||
(*v1.HistoryEvent)(nil), // 8: temporal.api.history.v1.HistoryEvent
|
||||
(*timestamppb.Timestamp)(nil), // 9: google.protobuf.Timestamp
|
||||
}
|
||||
var file_temporal_server_api_history_v1_message_proto_depIdxs = []int32{
|
||||
6, // 0: temporal.server.api.history.v1.TransientWorkflowTaskInfo.history_suffix:type_name -> temporal.api.history.v1.HistoryEvent
|
||||
8, // 0: temporal.server.api.history.v1.TransientWorkflowTaskInfo.history_suffix:type_name -> temporal.api.history.v1.HistoryEvent
|
||||
1, // 1: temporal.server.api.history.v1.VersionHistory.items:type_name -> temporal.server.api.history.v1.VersionHistoryItem
|
||||
2, // 2: temporal.server.api.history.v1.VersionHistories.histories:type_name -> temporal.server.api.history.v1.VersionHistory
|
||||
7, // 3: temporal.server.api.history.v1.TaskKey.fire_time:type_name -> google.protobuf.Timestamp
|
||||
9, // 3: temporal.server.api.history.v1.TaskKey.fire_time:type_name -> google.protobuf.Timestamp
|
||||
4, // 4: temporal.server.api.history.v1.TaskRange.inclusive_min_task_key:type_name -> temporal.server.api.history.v1.TaskKey
|
||||
4, // 5: temporal.server.api.history.v1.TaskRange.exclusive_max_task_key:type_name -> temporal.server.api.history.v1.TaskKey
|
||||
6, // [6:6] is the sub-list for method output_type
|
||||
6, // [6:6] is the sub-list for method input_type
|
||||
6, // [6:6] is the sub-list for extension type_name
|
||||
6, // [6:6] is the sub-list for extension extendee
|
||||
0, // [0:6] is the sub-list for field type_name
|
||||
6, // 6: temporal.server.api.history.v1.StrippedHistoryEvents.events:type_name -> temporal.server.api.history.v1.StrippedHistoryEvent
|
||||
7, // [7:7] is the sub-list for method output_type
|
||||
7, // [7:7] is the sub-list for method input_type
|
||||
7, // [7:7] is the sub-list for extension type_name
|
||||
7, // [7:7] is the sub-list for extension extendee
|
||||
0, // [0:7] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_temporal_server_api_history_v1_message_proto_init() }
|
||||
@@ -553,6 +670,30 @@ func file_temporal_server_api_history_v1_message_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_temporal_server_api_history_v1_message_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*StrippedHistoryEvent); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_temporal_server_api_history_v1_message_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*StrippedHistoryEvents); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
@@ -560,7 +701,7 @@ func file_temporal_server_api_history_v1_message_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_temporal_server_api_history_v1_message_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 6,
|
||||
NumMessages: 8,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
@@ -4173,6 +4173,43 @@ func (this *GetWorkflowExecutionHistoryResponse) Equal(that interface{}) bool {
|
||||
return proto.Equal(this, that1)
|
||||
}
|
||||
|
||||
// Marshal an object of type GetWorkflowExecutionHistoryResponseWithRaw to the protobuf v3 wire format
|
||||
func (val *GetWorkflowExecutionHistoryResponseWithRaw) Marshal() ([]byte, error) {
|
||||
return proto.Marshal(val)
|
||||
}
|
||||
|
||||
// Unmarshal an object of type GetWorkflowExecutionHistoryResponseWithRaw from the protobuf v3 wire format
|
||||
func (val *GetWorkflowExecutionHistoryResponseWithRaw) Unmarshal(buf []byte) error {
|
||||
return proto.Unmarshal(buf, val)
|
||||
}
|
||||
|
||||
// Size returns the size of the object, in bytes, once serialized
|
||||
func (val *GetWorkflowExecutionHistoryResponseWithRaw) Size() int {
|
||||
return proto.Size(val)
|
||||
}
|
||||
|
||||
// Equal returns whether two GetWorkflowExecutionHistoryResponseWithRaw values are equivalent by recursively
|
||||
// comparing the message's fields.
|
||||
// For more information see the documentation for
|
||||
// https://pkg.go.dev/google.golang.org/protobuf/proto#Equal
|
||||
func (this *GetWorkflowExecutionHistoryResponseWithRaw) Equal(that interface{}) bool {
|
||||
if that == nil {
|
||||
return this == nil
|
||||
}
|
||||
|
||||
var that1 *GetWorkflowExecutionHistoryResponseWithRaw
|
||||
switch t := that.(type) {
|
||||
case *GetWorkflowExecutionHistoryResponseWithRaw:
|
||||
that1 = t
|
||||
case GetWorkflowExecutionHistoryResponseWithRaw:
|
||||
that1 = &t
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
return proto.Equal(this, that1)
|
||||
}
|
||||
|
||||
// Marshal an object of type GetWorkflowExecutionHistoryReverseRequest to the protobuf v3 wire format
|
||||
func (val *GetWorkflowExecutionHistoryReverseRequest) Marshal() ([]byte, error) {
|
||||
return proto.Marshal(val)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1254,7 +1254,7 @@ type HistoryServiceServer interface {
|
||||
// aip.dev/not-precedent: This service does not follow the update method API --)
|
||||
PollWorkflowExecutionUpdate(context.Context, *PollWorkflowExecutionUpdateRequest) (*PollWorkflowExecutionUpdateResponse, error)
|
||||
StreamWorkflowReplicationMessages(HistoryService_StreamWorkflowReplicationMessagesServer) error
|
||||
GetWorkflowExecutionHistory(context.Context, *GetWorkflowExecutionHistoryRequest) (*GetWorkflowExecutionHistoryResponse, error)
|
||||
GetWorkflowExecutionHistory(context.Context, *GetWorkflowExecutionHistoryRequest) (*GetWorkflowExecutionHistoryResponseWithRaw, error)
|
||||
GetWorkflowExecutionHistoryReverse(context.Context, *GetWorkflowExecutionHistoryReverseRequest) (*GetWorkflowExecutionHistoryReverseResponse, error)
|
||||
GetWorkflowExecutionRawHistoryV2(context.Context, *GetWorkflowExecutionRawHistoryV2Request) (*GetWorkflowExecutionRawHistoryV2Response, error)
|
||||
GetWorkflowExecutionRawHistory(context.Context, *GetWorkflowExecutionRawHistoryRequest) (*GetWorkflowExecutionRawHistoryResponse, error)
|
||||
@@ -1504,7 +1504,7 @@ func (UnimplementedHistoryServiceServer) PollWorkflowExecutionUpdate(context.Con
|
||||
func (UnimplementedHistoryServiceServer) StreamWorkflowReplicationMessages(HistoryService_StreamWorkflowReplicationMessagesServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method StreamWorkflowReplicationMessages not implemented")
|
||||
}
|
||||
func (UnimplementedHistoryServiceServer) GetWorkflowExecutionHistory(context.Context, *GetWorkflowExecutionHistoryRequest) (*GetWorkflowExecutionHistoryResponse, error) {
|
||||
func (UnimplementedHistoryServiceServer) GetWorkflowExecutionHistory(context.Context, *GetWorkflowExecutionHistoryRequest) (*GetWorkflowExecutionHistoryResponseWithRaw, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetWorkflowExecutionHistory not implemented")
|
||||
}
|
||||
func (UnimplementedHistoryServiceServer) GetWorkflowExecutionHistoryReverse(context.Context, *GetWorkflowExecutionHistoryReverseRequest) (*GetWorkflowExecutionHistoryReverseResponse, error) {
|
||||
|
||||
@@ -2382,6 +2382,11 @@ that task will be sent to DLQ.`,
|
||||
0.90,
|
||||
"History service health check on persistence error ratio",
|
||||
)
|
||||
SendRawHistoryBetweenInternalServices = NewGlobalBoolSetting(
|
||||
"history.sendRawHistoryBetweenInternalServices",
|
||||
false,
|
||||
`SendRawHistoryBetweenInternalServices is whether to send raw history events between internal temporal services`,
|
||||
)
|
||||
|
||||
// keys for worker
|
||||
|
||||
|
||||
@@ -824,7 +824,6 @@ func (m *executionManagerImpl) readRawHistoryBranchAndFilter(
|
||||
token.LastNodeID = lastNode.NodeID
|
||||
token.LastTransactionID = lastNode.TransactionID
|
||||
}
|
||||
|
||||
return dataBlobs, transactionIDs, nodeIDs, token, dataSize, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,13 @@ import (
|
||||
"context"
|
||||
"sort"
|
||||
|
||||
commonpb "go.temporal.io/api/common/v1"
|
||||
historypb "go.temporal.io/api/history/v1"
|
||||
"go.temporal.io/api/serviceerror"
|
||||
historyspb "go.temporal.io/server/api/history/v1"
|
||||
persistencespb "go.temporal.io/server/api/persistence/v1"
|
||||
"go.temporal.io/server/common/log"
|
||||
"go.temporal.io/server/common/log/tag"
|
||||
)
|
||||
|
||||
// ReadFullPageEvents reads a full page of history events from ExecutionManager. Due to storage format of V2 History
|
||||
@@ -56,6 +61,30 @@ func ReadFullPageEvents(
|
||||
}
|
||||
}
|
||||
|
||||
// ReadFullPageRawEvents reads a full page of raw history events from ExecutionManager. Due to storage format of V2 History
|
||||
// it is not guaranteed that pageSize amount of data is returned. Function returns the list of history blobs, the size
|
||||
// of data read, the next page token, and an error if present.
|
||||
func ReadFullPageRawEvents(
|
||||
ctx context.Context,
|
||||
executionMgr ExecutionManager,
|
||||
req *ReadHistoryBranchRequest,
|
||||
) ([]*commonpb.DataBlob, int, []byte, error) {
|
||||
var blobs []*commonpb.DataBlob
|
||||
size := 0
|
||||
for {
|
||||
response, err := executionMgr.ReadRawHistoryBranch(ctx, req)
|
||||
if err != nil {
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
blobs = append(blobs, response.HistoryEventBlobs...)
|
||||
size += response.Size
|
||||
if len(blobs) >= req.PageSize || len(response.NextPageToken) == 0 {
|
||||
return blobs, size, response.NextPageToken, nil
|
||||
}
|
||||
req.NextPageToken = response.NextPageToken
|
||||
}
|
||||
}
|
||||
|
||||
// ReadFullPageEventsByBatch reads a full page of history events by batch from ExecutionManager. Due to storage format of V2 History
|
||||
// it is not guaranteed that pageSize amount of data is returned. Function returns the list of history batches, the size
|
||||
// of data read, the next page token, and an error if present.
|
||||
@@ -128,3 +157,41 @@ func sortAncestors(ans []*persistencespb.HistoryBranchRange) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ValidateBatch(
|
||||
batch []*historyspb.StrippedHistoryEvent,
|
||||
branchToken []byte,
|
||||
lastEventID int64,
|
||||
logger log.Logger,
|
||||
) error {
|
||||
var firstEvent, lastEvent *historyspb.StrippedHistoryEvent
|
||||
var eventCount int
|
||||
dataLossTags := func(cause string) []tag.Tag {
|
||||
return []tag.Tag{
|
||||
tag.Cause(cause),
|
||||
tag.WorkflowBranchToken(branchToken),
|
||||
tag.WorkflowFirstEventID(firstEvent.GetEventId()),
|
||||
tag.FirstEventVersion(firstEvent.GetVersion()),
|
||||
tag.WorkflowNextEventID(lastEvent.GetEventId()),
|
||||
tag.LastEventVersion(lastEvent.GetVersion()),
|
||||
tag.Counter(eventCount),
|
||||
tag.TokenLastEventID(lastEventID),
|
||||
}
|
||||
}
|
||||
firstEvent = batch[0]
|
||||
eventCount = len(batch)
|
||||
lastEvent = batch[eventCount-1]
|
||||
|
||||
if firstEvent.GetVersion() != lastEvent.GetVersion() || firstEvent.GetEventId()+int64(eventCount-1) != lastEvent.GetEventId() {
|
||||
// in a single batch, version should be the same, and ID should be contiguous
|
||||
logger.Error(dataLossMsg, dataLossTags(errWrongVersion)...)
|
||||
return serviceerror.NewDataLoss(errWrongVersion)
|
||||
}
|
||||
// If it is the first batch in the response, we cannot check the first event id here. That information is in the historyPagingToken.
|
||||
// TODO: PPV refactor to move this check to ExecutionManager so that we can include that check as well.
|
||||
if lastEventID != 0 && firstEvent.GetEventId() != lastEventID+1 {
|
||||
logger.Error(dataLossMsg, dataLossTags(errNonContiguousEventID)...)
|
||||
return serviceerror.NewDataLoss(errNonContiguousEventID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
enumspb "go.temporal.io/api/enums/v1"
|
||||
historypb "go.temporal.io/api/history/v1"
|
||||
enumsspb "go.temporal.io/server/api/enums/v1"
|
||||
historyspb "go.temporal.io/server/api/history/v1"
|
||||
persistencespb "go.temporal.io/server/api/persistence/v1"
|
||||
replicationspb "go.temporal.io/server/api/replication/v1"
|
||||
"go.temporal.io/server/common/codec"
|
||||
@@ -50,6 +51,7 @@ type (
|
||||
|
||||
SerializeEvent(event *historypb.HistoryEvent, encodingType enumspb.EncodingType) (*commonpb.DataBlob, error)
|
||||
DeserializeEvent(data *commonpb.DataBlob) (*historypb.HistoryEvent, error)
|
||||
DeserializeStrippedEvents(data *commonpb.DataBlob) ([]*historyspb.StrippedHistoryEvent, error)
|
||||
|
||||
SerializeClusterMetadata(icm *persistencespb.ClusterMetadata, encodingType enumspb.EncodingType) (*commonpb.DataBlob, error)
|
||||
DeserializeClusterMetadata(data *commonpb.DataBlob) (*persistencespb.ClusterMetadata, error)
|
||||
@@ -177,6 +179,33 @@ func (t *serializerImpl) DeserializeEvents(data *commonpb.DataBlob) ([]*historyp
|
||||
return events.Events, nil
|
||||
}
|
||||
|
||||
func (t *serializerImpl) DeserializeStrippedEvents(data *commonpb.DataBlob) ([]*historyspb.StrippedHistoryEvent, error) {
|
||||
if data == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if len(data.Data) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
events := &historyspb.StrippedHistoryEvents{}
|
||||
var err error
|
||||
//nolint:exhaustive
|
||||
switch data.EncodingType {
|
||||
case enumspb.ENCODING_TYPE_PROTO3:
|
||||
// Discard unknown fields to improve performance. StrippedHistoryEvents is usually deserialized from HistoryEvent
|
||||
// which has extra fields that are not needed for this message.
|
||||
err = proto.UnmarshalOptions{
|
||||
DiscardUnknown: true,
|
||||
}.Unmarshal(data.Data, events)
|
||||
default:
|
||||
return nil, NewUnknownEncodingTypeError(data.EncodingType.String(), enumspb.ENCODING_TYPE_PROTO3)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, NewDeserializationError(enumspb.ENCODING_TYPE_PROTO3, err)
|
||||
}
|
||||
return events.Events, nil
|
||||
}
|
||||
|
||||
func (t *serializerImpl) SerializeEvent(event *historypb.HistoryEvent, encodingType enumspb.EncodingType) (*commonpb.DataBlob, error) {
|
||||
if event == nil {
|
||||
return nil, nil
|
||||
|
||||
@@ -32,8 +32,10 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
commonpb "go.temporal.io/api/common/v1"
|
||||
enumspb "go.temporal.io/api/enums/v1"
|
||||
historypb "go.temporal.io/api/history/v1"
|
||||
"go.temporal.io/server/api/historyservice/v1"
|
||||
persistencespb "go.temporal.io/server/api/persistence/v1"
|
||||
"go.temporal.io/server/common"
|
||||
"go.temporal.io/server/common/log"
|
||||
@@ -196,6 +198,85 @@ func (s *temporalSerializerSuite) TestSerializeShardInfo_Random() {
|
||||
s.ProtoEqual(&shardInfo, deserializedShardInfo)
|
||||
}
|
||||
|
||||
func (s *temporalSerializerSuite) TestDeserializeStrippedEvents() {
|
||||
// 1. Nil data blob
|
||||
s.Run("NilDataBlob", func() {
|
||||
events, err := s.serializer.DeserializeStrippedEvents(nil)
|
||||
s.NoError(err)
|
||||
s.Nil(events)
|
||||
})
|
||||
|
||||
// 2. Empty data
|
||||
s.Run("EmptyDataBlob", func() {
|
||||
// Data is nil
|
||||
events, err := s.serializer.DeserializeStrippedEvents(&commonpb.DataBlob{
|
||||
EncodingType: enumspb.ENCODING_TYPE_PROTO3,
|
||||
Data: nil,
|
||||
})
|
||||
s.NoError(err)
|
||||
s.Nil(events)
|
||||
|
||||
// Data is empty byte array
|
||||
events, err = s.serializer.DeserializeStrippedEvents(&commonpb.DataBlob{
|
||||
EncodingType: enumspb.ENCODING_TYPE_PROTO3,
|
||||
Data: []byte{},
|
||||
})
|
||||
s.NoError(err)
|
||||
s.Nil(events)
|
||||
})
|
||||
|
||||
// 3. Unknown encoding type
|
||||
s.Run("UnknownEncodingType", func() {
|
||||
_, err := s.serializer.DeserializeStrippedEvents(&commonpb.DataBlob{
|
||||
EncodingType: enumspb.ENCODING_TYPE_JSON, // Not handled by our switch
|
||||
Data: []byte("irrelevant-data"),
|
||||
})
|
||||
s.Error(err)
|
||||
s.Contains(err.Error(), "unknown or unsupported encoding type")
|
||||
})
|
||||
|
||||
// 4. Proper proto decoding, discarding unknown fields
|
||||
s.Run("ProtoDiscardUnknownFields", func() {
|
||||
// Build a HistoryEvent that contains fields *not* present in StrippedHistoryEvent
|
||||
historyEvent := &historypb.HistoryEvent{
|
||||
EventId: 123,
|
||||
Version: 456,
|
||||
EventTime: nil, // or a valid timestamp
|
||||
// This is an extra field not present in StrippedHistoryEvent
|
||||
Attributes: &historypb.HistoryEvent_WorkflowExecutionStartedEventAttributes{
|
||||
WorkflowExecutionStartedEventAttributes: &historypb.WorkflowExecutionStartedEventAttributes{
|
||||
WorkflowType: &commonpb.WorkflowType{Name: "some-workflow-type"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
historyEvents := &historypb.History{
|
||||
Events: []*historypb.HistoryEvent{historyEvent},
|
||||
}
|
||||
|
||||
// Marshal to protobuf
|
||||
data, err := historyEvents.Marshal()
|
||||
s.Require().NoError(err)
|
||||
|
||||
dataBlob := &commonpb.DataBlob{
|
||||
EncodingType: enumspb.ENCODING_TYPE_PROTO3,
|
||||
Data: data,
|
||||
}
|
||||
|
||||
// Deserialize into StrippedHistoryEvents (should drop unknown fields)
|
||||
deserializedEvents, err := s.serializer.DeserializeStrippedEvents(dataBlob)
|
||||
s.NoError(err)
|
||||
s.Require().Len(deserializedEvents, 1)
|
||||
|
||||
// Known fields should be preserved
|
||||
s.EqualValues(123, deserializedEvents[0].EventId)
|
||||
s.EqualValues(456, deserializedEvents[0].Version)
|
||||
|
||||
reflectMsg := deserializedEvents[0].ProtoReflect()
|
||||
s.Empty(reflectMsg.GetUnknown(), "Unknown fields should have been discarded")
|
||||
})
|
||||
}
|
||||
|
||||
func (s *temporalSerializerSuite) TestSerializeWorkflowExecutionState() {
|
||||
state := &persistencespb.WorkflowExecutionState{
|
||||
RequestIds: make(map[string]*persistencespb.RequestIDInfo),
|
||||
@@ -224,3 +305,80 @@ func (s *temporalSerializerSuite) TestSerializeWorkflowExecutionState() {
|
||||
s.NotNil(deserializedState)
|
||||
s.ProtoEqual(state, deserializedState)
|
||||
}
|
||||
|
||||
// HistoryService returns a different GetWorkflowExecutionHistoryResponse GetWorkflowExecutionHistoryResponseWithRaw to
|
||||
// WorkflowHandler. Since HistoryClient is defined with the response type GetWorkflowExecutionHistoryResponse, grpc
|
||||
// will deserialize this message to GetWorkflowExecutionHistoryResponse. This is done to avoid the extra CPU usage in
|
||||
// history service to deserialize event blobs to []*HistoryEvent. This test ensures that
|
||||
// GetWorkflowExecutionHistoryResponseWithRaw is correctly deserialized to GetWorkflowExecutionHistoryResponse.
|
||||
func (s *temporalSerializerSuite) TestGetWorkflowExecutionHistoryResponseWithRawHistoryEvents() {
|
||||
// Create history events and batches
|
||||
fullHistory := &historypb.History{
|
||||
Events: []*historypb.HistoryEvent{
|
||||
{
|
||||
EventId: 1,
|
||||
EventType: enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_STARTED,
|
||||
Version: 100,
|
||||
},
|
||||
{
|
||||
EventId: 2,
|
||||
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED,
|
||||
Version: 101,
|
||||
},
|
||||
{
|
||||
EventId: 3,
|
||||
EventType: enumspb.EVENT_TYPE_ACTIVITY_TASK_COMPLETED,
|
||||
Version: 102,
|
||||
},
|
||||
{
|
||||
EventId: 4,
|
||||
EventType: enumspb.EVENT_TYPE_TIMER_FIRED,
|
||||
Version: 103,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
batch1 := &historypb.History{
|
||||
Events: fullHistory.Events[:2],
|
||||
}
|
||||
|
||||
batch2 := &historypb.History{
|
||||
Events: fullHistory.Events[2:],
|
||||
}
|
||||
|
||||
// Marshal each batch
|
||||
rawHistory1, err := batch1.Marshal()
|
||||
s.Require().NoError(err)
|
||||
|
||||
db1 := &commonpb.DataBlob{
|
||||
EncodingType: enumspb.ENCODING_TYPE_PROTO3,
|
||||
Data: rawHistory1,
|
||||
}
|
||||
|
||||
rawHistory2, err := batch2.Marshal()
|
||||
s.Require().NoError(err)
|
||||
|
||||
db2 := &commonpb.DataBlob{
|
||||
EncodingType: enumspb.ENCODING_TYPE_PROTO3,
|
||||
Data: rawHistory2,
|
||||
}
|
||||
|
||||
rawResp := &historyservice.GetWorkflowExecutionHistoryResponseWithRaw{
|
||||
History: [][]byte{db1.Data, db2.Data},
|
||||
}
|
||||
|
||||
serializedRawResp, err := rawResp.Marshal()
|
||||
s.Require().NoError(err)
|
||||
|
||||
resp := &historyservice.GetWorkflowExecutionHistoryResponse{}
|
||||
err = resp.Unmarshal(serializedRawResp)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Verify resp has same list of history events as fullHistory
|
||||
for i, event := range resp.History.Events {
|
||||
s.Equal(fullHistory.Events[i].EventId, event.EventId)
|
||||
s.Equal(fullHistory.Events[i].Version, event.Version)
|
||||
s.Equal(fullHistory.Events[i].EventType, event.EventType)
|
||||
s.Nil(event.Attributes)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ func (wt *WorkflowTags) extractFromHistoryServiceServerMessage(message any) []ta
|
||||
tag.WorkflowID(r.GetRequest().GetExecution().GetWorkflowId()),
|
||||
tag.WorkflowRunID(r.GetRequest().GetExecution().GetRunId()),
|
||||
}
|
||||
case *historyservice.GetWorkflowExecutionHistoryResponse:
|
||||
case *historyservice.GetWorkflowExecutionHistoryResponseWithRaw:
|
||||
return nil
|
||||
case *historyservice.GetWorkflowExecutionHistoryReverseRequest:
|
||||
return []tag.Tag{
|
||||
|
||||
@@ -37,6 +37,11 @@ done
|
||||
color "Update license headers for proto files..."
|
||||
go run ./cmd/tools/copyright/licensegen.go --scanDir "$new"
|
||||
|
||||
color "Modify history service server interface..."
|
||||
sed -i.bak -e \
|
||||
's/GetWorkflowExecutionHistory(context\.Context, \*GetWorkflowExecutionHistoryRequest) (\*GetWorkflowExecutionHistoryResponse, error)/GetWorkflowExecutionHistory(context.Context, *GetWorkflowExecutionHistoryRequest) (*GetWorkflowExecutionHistoryResponseWithRaw, error)/g' \
|
||||
"$new"/temporal/server/api/historyservice/v1/service_grpc.pb.go && rm "$new"/temporal/server/api/historyservice/v1/service_grpc.pb.go.bak
|
||||
|
||||
color "Moving proto files into place..."
|
||||
old=$api.old
|
||||
[[ -d "$api" ]] && mv -f "$api" "$old"
|
||||
|
||||
@@ -65,3 +65,13 @@ message TaskRange {
|
||||
TaskKey inclusive_min_task_key = 1;
|
||||
TaskKey exclusive_max_task_key = 2;
|
||||
}
|
||||
|
||||
// StrippedHistoryEvent is a stripped down version of HistoryEvent that only contains the event_id and version.
|
||||
message StrippedHistoryEvent {
|
||||
int64 event_id = 1;
|
||||
int64 version = 4;
|
||||
}
|
||||
|
||||
message StrippedHistoryEvents {
|
||||
repeated StrippedHistoryEvent events = 1;
|
||||
}
|
||||
|
||||
@@ -982,6 +982,13 @@ message GetWorkflowExecutionHistoryRequest {
|
||||
|
||||
message GetWorkflowExecutionHistoryResponse {
|
||||
temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryResponse response = 1;
|
||||
temporal.api.history.v1.History history = 2;
|
||||
}
|
||||
|
||||
// This message must be wire compatible with GetWorkflowExecutionHistoryResponse.
|
||||
message GetWorkflowExecutionHistoryResponseWithRaw {
|
||||
temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryResponse response = 1;
|
||||
repeated bytes history = 2;
|
||||
}
|
||||
|
||||
message GetWorkflowExecutionHistoryReverseRequest {
|
||||
|
||||
@@ -88,6 +88,7 @@ import (
|
||||
"go.temporal.io/server/common/tqid"
|
||||
"go.temporal.io/server/common/util"
|
||||
"go.temporal.io/server/common/worker_versioning"
|
||||
"go.temporal.io/server/service/history/api"
|
||||
"go.temporal.io/server/service/worker/batcher"
|
||||
"go.temporal.io/server/service/worker/deployment"
|
||||
"go.temporal.io/server/service/worker/scheduler"
|
||||
@@ -763,6 +764,21 @@ func (wh *WorkflowHandler) GetWorkflowExecutionHistory(ctx context.Context, requ
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
isCloseEventOnly := request.HistoryEventFilterType == enumspb.HISTORY_EVENT_FILTER_TYPE_CLOSE_EVENT
|
||||
err = api.ProcessInternalRawHistory(
|
||||
ctx,
|
||||
wh.saProvider,
|
||||
wh.saMapperProvider,
|
||||
response,
|
||||
wh.visibilityMgr,
|
||||
wh.versionChecker,
|
||||
namespace.Name(request.GetNamespace()),
|
||||
isCloseEventOnly,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response.Response, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ import (
|
||||
batchpb "go.temporal.io/api/batch/v1"
|
||||
commonpb "go.temporal.io/api/common/v1"
|
||||
enumspb "go.temporal.io/api/enums/v1"
|
||||
failurepb "go.temporal.io/api/failure/v1"
|
||||
filterpb "go.temporal.io/api/filter/v1"
|
||||
historypb "go.temporal.io/api/history/v1"
|
||||
namespacepb "go.temporal.io/api/namespace/v1"
|
||||
@@ -48,6 +49,7 @@ import (
|
||||
updatepb "go.temporal.io/api/update/v1"
|
||||
workflowpb "go.temporal.io/api/workflow/v1"
|
||||
"go.temporal.io/api/workflowservice/v1"
|
||||
historyspb "go.temporal.io/server/api/history/v1"
|
||||
"go.temporal.io/server/api/historyservice/v1"
|
||||
"go.temporal.io/server/api/historyservicemock/v1"
|
||||
"go.temporal.io/server/api/matchingservice/v1"
|
||||
@@ -73,7 +75,8 @@ import (
|
||||
"go.temporal.io/server/common/rpc/interceptor"
|
||||
"go.temporal.io/server/common/searchattribute"
|
||||
"go.temporal.io/server/common/tasktoken"
|
||||
e "go.temporal.io/server/service/history/events"
|
||||
"go.temporal.io/server/service/history/api"
|
||||
"go.temporal.io/server/service/history/tests"
|
||||
"go.temporal.io/server/service/worker/batcher"
|
||||
"go.temporal.io/server/service/worker/scheduler"
|
||||
"go.uber.org/mock/gomock"
|
||||
@@ -2036,16 +2039,16 @@ func (s *WorkflowHandlerSuite) TestCountWorkflowExecutions() {
|
||||
}
|
||||
|
||||
func (s *WorkflowHandlerSuite) TestVerifyHistoryIsComplete() {
|
||||
events := make([]*historypb.HistoryEvent, 50)
|
||||
events := make([]*historyspb.StrippedHistoryEvent, 50)
|
||||
for i := 0; i < len(events); i++ {
|
||||
events[i] = &historypb.HistoryEvent{EventId: int64(i + 1)}
|
||||
events[i] = &historyspb.StrippedHistoryEvent{EventId: int64(i + 1)}
|
||||
}
|
||||
var eventsWithHoles []*historypb.HistoryEvent
|
||||
var eventsWithHoles []*historyspb.StrippedHistoryEvent
|
||||
eventsWithHoles = append(eventsWithHoles, events[9:12]...)
|
||||
eventsWithHoles = append(eventsWithHoles, events[20:31]...)
|
||||
|
||||
testCases := []struct {
|
||||
events []*historypb.HistoryEvent
|
||||
events []*historyspb.StrippedHistoryEvent
|
||||
firstEventID int64
|
||||
lastEventID int64
|
||||
isFirstPage bool
|
||||
@@ -2079,7 +2082,16 @@ func (s *WorkflowHandlerSuite) TestVerifyHistoryIsComplete() {
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
err := e.VerifyHistoryIsComplete(tc.events, tc.firstEventID, tc.lastEventID, tc.isFirstPage, tc.isLastPage, tc.pageSize)
|
||||
err := api.VerifyHistoryIsComplete(
|
||||
tc.events[0],
|
||||
tc.events[len(tc.events)-1],
|
||||
len(tc.events),
|
||||
tc.firstEventID,
|
||||
tc.lastEventID,
|
||||
tc.isFirstPage,
|
||||
tc.isLastPage,
|
||||
tc.pageSize,
|
||||
)
|
||||
if tc.isResultErr {
|
||||
s.Error(err, "testcase %v failed", i)
|
||||
} else {
|
||||
@@ -2802,6 +2814,91 @@ func (s *WorkflowHandlerSuite) TestListBatchOperations_InvalidRerquest() {
|
||||
s.ErrorAs(err, &invalidArgumentErr)
|
||||
}
|
||||
|
||||
// This test is to make sure that GetWorkflowExecutionHistory returns the correct history when history service sends
|
||||
// History events in the field response.History. This happens when history.sendRawHistoryBetweenInternalServices is enabled.
|
||||
// This test verifies that HistoryEventFilterType is applied and EVENT_TYPE_WORKFLOW_EXECUTION_FAILED is converted to
|
||||
// EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW for older SDKs.
|
||||
func (s *WorkflowHandlerSuite) TestGetWorkflowExecutionHistory_InternalRawHistoryEnabled() {
|
||||
config := s.newConfig()
|
||||
wh := s.getWorkflowHandler(config)
|
||||
we := commonpb.WorkflowExecution{WorkflowId: "wid1", RunId: uuid.New().String()}
|
||||
newRunID := uuid.New().String()
|
||||
|
||||
s.mockNamespaceCache.EXPECT().GetNamespaceID(tests.Namespace).Return(tests.NamespaceID, nil).Times(2)
|
||||
s.mockSearchAttributesProvider.EXPECT().GetSearchAttributes(gomock.Any(), gomock.Any()).Return(searchattribute.TestNameTypeMap, nil).Times(2)
|
||||
|
||||
req := &workflowservice.GetWorkflowExecutionHistoryRequest{
|
||||
Namespace: tests.Namespace.String(),
|
||||
Execution: &we,
|
||||
MaximumPageSize: 10,
|
||||
HistoryEventFilterType: enumspb.HISTORY_EVENT_FILTER_TYPE_CLOSE_EVENT,
|
||||
SkipArchival: true,
|
||||
}
|
||||
s.mockHistoryClient.EXPECT().GetWorkflowExecutionHistory(gomock.Any(), &historyservice.GetWorkflowExecutionHistoryRequest{
|
||||
NamespaceId: tests.NamespaceID.String(),
|
||||
Request: req,
|
||||
}).Return(&historyservice.GetWorkflowExecutionHistoryResponse{
|
||||
Response: &workflowservice.GetWorkflowExecutionHistoryResponse{
|
||||
History: &historypb.History{},
|
||||
},
|
||||
History: &historypb.History{
|
||||
Events: []*historypb.HistoryEvent{
|
||||
{
|
||||
EventId: int64(5),
|
||||
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_FAILED,
|
||||
Attributes: &historypb.HistoryEvent_WorkflowTaskFailedEventAttributes{
|
||||
WorkflowTaskFailedEventAttributes: &historypb.WorkflowTaskFailedEventAttributes{
|
||||
Failure: &failurepb.Failure{Message: "this workflow task failed"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
EventId: int64(5),
|
||||
EventType: enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_FAILED,
|
||||
Attributes: &historypb.HistoryEvent_WorkflowExecutionFailedEventAttributes{
|
||||
WorkflowExecutionFailedEventAttributes: &historypb.WorkflowExecutionFailedEventAttributes{
|
||||
Failure: &failurepb.Failure{Message: "this workflow failed"},
|
||||
RetryState: enumspb.RETRY_STATE_IN_PROGRESS,
|
||||
WorkflowTaskCompletedEventId: 4,
|
||||
NewExecutionRunId: newRunID,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil).Times(2)
|
||||
|
||||
oldGoSDKVersion := "1.9.1"
|
||||
newGoSDKVersion := "1.10.1"
|
||||
|
||||
// new sdk: should see failed event
|
||||
ctx := headers.SetVersionsForTests(context.Background(), newGoSDKVersion, headers.ClientNameGoSDK, headers.SupportedServerVersions, headers.AllFeatures)
|
||||
resp, err := wh.GetWorkflowExecutionHistory(ctx, req)
|
||||
s.NoError(err)
|
||||
s.False(resp.Archived)
|
||||
event := resp.History.Events[0]
|
||||
s.Equal(int64(5), event.EventId)
|
||||
s.Equal(enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_FAILED, event.EventType)
|
||||
attrs := event.GetWorkflowExecutionFailedEventAttributes()
|
||||
s.Equal("this workflow failed", attrs.Failure.Message)
|
||||
s.Equal(newRunID, attrs.NewExecutionRunId)
|
||||
s.Equal(enumspb.RETRY_STATE_IN_PROGRESS, attrs.RetryState)
|
||||
|
||||
// old sdk: should see continued-as-new event
|
||||
// TODO: We can remove this once we no longer support SDK versions prior to around September 2021.
|
||||
// See comment in workflowHandler.go:GetWorkflowExecutionHistory
|
||||
ctx = headers.SetVersionsForTests(context.Background(), oldGoSDKVersion, headers.ClientNameGoSDK, headers.SupportedServerVersions, "")
|
||||
resp, err = wh.GetWorkflowExecutionHistory(ctx, req)
|
||||
s.NoError(err)
|
||||
s.False(resp.Archived)
|
||||
event = resp.History.Events[0]
|
||||
s.Equal(int64(5), event.EventId)
|
||||
s.Equal(enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW, event.EventType)
|
||||
attrs2 := event.GetWorkflowExecutionContinuedAsNewEventAttributes()
|
||||
s.Equal(newRunID, attrs2.NewExecutionRunId)
|
||||
s.Equal("this workflow failed", attrs2.Failure.Message)
|
||||
}
|
||||
|
||||
func (s *WorkflowHandlerSuite) newConfig() *Config {
|
||||
return NewConfig(dc.NewNoopCollection(), numHistoryShards)
|
||||
}
|
||||
|
||||
@@ -33,7 +33,10 @@ import (
|
||||
historypb "go.temporal.io/api/history/v1"
|
||||
"go.temporal.io/api/serviceerror"
|
||||
historyspb "go.temporal.io/server/api/history/v1"
|
||||
"go.temporal.io/server/api/historyservice/v1"
|
||||
"go.temporal.io/server/common"
|
||||
"go.temporal.io/server/common/failure"
|
||||
"go.temporal.io/server/common/headers"
|
||||
"go.temporal.io/server/common/log/tag"
|
||||
"go.temporal.io/server/common/metrics"
|
||||
"go.temporal.io/server/common/namespace"
|
||||
@@ -43,7 +46,6 @@ import (
|
||||
"go.temporal.io/server/common/rpc/interceptor"
|
||||
"go.temporal.io/server/common/searchattribute"
|
||||
"go.temporal.io/server/service/history/consts"
|
||||
"go.temporal.io/server/service/history/events"
|
||||
"go.temporal.io/server/service/history/shard"
|
||||
)
|
||||
|
||||
@@ -55,28 +57,68 @@ func GetRawHistory(
|
||||
firstEventID int64,
|
||||
nextEventID int64,
|
||||
pageSize int32,
|
||||
nextPageToken []byte,
|
||||
token []byte,
|
||||
transientWorkflowTaskInfo *historyspb.TransientWorkflowTaskInfo,
|
||||
branchToken []byte,
|
||||
) ([]*commonpb.DataBlob, []byte, error) {
|
||||
shardID := common.WorkflowIDToHistoryShard(namespaceID.String(), execution.GetWorkflowId(), shard.GetConfig().NumberOfShards)
|
||||
logger := shard.GetLogger()
|
||||
rawHistory, size, nextToken, err := persistence.ReadFullPageRawEvents(
|
||||
ctx, shard.GetExecutionManager(),
|
||||
&persistence.ReadHistoryBranchRequest{
|
||||
BranchToken: branchToken,
|
||||
MinEventID: firstEventID,
|
||||
MaxEventID: nextEventID,
|
||||
PageSize: int(pageSize),
|
||||
NextPageToken: token,
|
||||
ShardID: shardID,
|
||||
},
|
||||
)
|
||||
|
||||
persistenceExecutionManager := shard.GetExecutionManager()
|
||||
resp, err := persistenceExecutionManager.ReadRawHistoryBranch(ctx, &persistence.ReadHistoryBranchRequest{
|
||||
BranchToken: branchToken,
|
||||
MinEventID: firstEventID,
|
||||
MaxEventID: nextEventID,
|
||||
PageSize: int(pageSize),
|
||||
NextPageToken: nextPageToken,
|
||||
ShardID: shardID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
rawHistory := resp.HistoryEventBlobs
|
||||
allEvents := make([]*historyspb.StrippedHistoryEvent, 0)
|
||||
var lastEventID int64
|
||||
for _, blob := range rawHistory {
|
||||
events, err := shard.GetPayloadSerializer().DeserializeStrippedEvents(blob)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
err = persistence.ValidateBatch(events, branchToken, lastEventID, logger)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
allEvents = append(allEvents, events...)
|
||||
lastEventID = events[len(events)-1].GetEventId()
|
||||
}
|
||||
var firstEvent, lastEvent *historyspb.StrippedHistoryEvent
|
||||
if len(allEvents) > 0 {
|
||||
firstEvent = allEvents[0]
|
||||
lastEvent = allEvents[len(allEvents)-1]
|
||||
}
|
||||
if err = VerifyHistoryIsComplete(
|
||||
firstEvent,
|
||||
lastEvent,
|
||||
len(allEvents),
|
||||
firstEventID,
|
||||
nextEventID-1,
|
||||
len(token) == 0,
|
||||
len(nextToken) == 0,
|
||||
int(pageSize),
|
||||
); err != nil {
|
||||
metricsHandler := interceptor.GetMetricsHandlerFromContext(ctx, logger).WithTags(metrics.OperationTag(metrics.HistoryGetHistoryScope))
|
||||
metrics.ServiceErrIncompleteHistoryCounter.With(metricsHandler).Record(1)
|
||||
logger.Error("getHistory: incomplete history",
|
||||
tag.WorkflowBranchToken(branchToken),
|
||||
tag.Error(err))
|
||||
}
|
||||
|
||||
if len(resp.NextPageToken) == 0 && transientWorkflowTaskInfo != nil {
|
||||
metricsHandler := interceptor.GetMetricsHandlerFromContext(ctx, shard.GetLogger()).WithTags(metrics.OperationTag(metrics.HistoryGetHistoryScope))
|
||||
metrics.HistorySize.With(metricsHandler).Record(int64(size))
|
||||
|
||||
if len(nextToken) == 0 && transientWorkflowTaskInfo != nil {
|
||||
if err := validateTransientWorkflowTaskEvents(nextEventID, transientWorkflowTaskInfo); err != nil {
|
||||
logger := shard.GetLogger()
|
||||
metricsHandler := interceptor.GetMetricsHandlerFromContext(ctx, logger).WithTags(metrics.OperationTag(metrics.HistoryGetRawHistoryScope))
|
||||
@@ -89,16 +131,15 @@ func GetRawHistory(
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
for _, event := range transientWorkflowTaskInfo.HistorySuffix {
|
||||
blob, err := shard.GetPayloadSerializer().SerializeEvent(event, enumspb.ENCODING_TYPE_PROTO3)
|
||||
if len(transientWorkflowTaskInfo.HistorySuffix) > 0 {
|
||||
blob, err := shard.GetPayloadSerializer().SerializeEvents(transientWorkflowTaskInfo.HistorySuffix, enumspb.ENCODING_TYPE_PROTO3)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
rawHistory = append(rawHistory, blob)
|
||||
}
|
||||
}
|
||||
|
||||
return rawHistory, resp.NextPageToken, nil
|
||||
return rawHistory, nextToken, nil
|
||||
}
|
||||
|
||||
func GetHistory(
|
||||
@@ -149,8 +190,19 @@ func GetHistory(
|
||||
metrics.HistorySize.With(metricsHandler).Record(int64(size))
|
||||
|
||||
isLastPage := len(nextPageToken) == 0
|
||||
if err := events.VerifyHistoryIsComplete(
|
||||
historyEvents,
|
||||
var firstEvent, lastEvent *historyspb.StrippedHistoryEvent
|
||||
if len(historyEvents) > 0 {
|
||||
firstEvent = &historyspb.StrippedHistoryEvent{
|
||||
EventId: historyEvents[0].GetEventId(),
|
||||
}
|
||||
lastEvent = &historyspb.StrippedHistoryEvent{
|
||||
EventId: historyEvents[len(historyEvents)-1].GetEventId(),
|
||||
}
|
||||
}
|
||||
if err := VerifyHistoryIsComplete(
|
||||
firstEvent,
|
||||
lastEvent,
|
||||
len(historyEvents),
|
||||
firstEventID,
|
||||
nextEventID-1,
|
||||
isFirstPage,
|
||||
@@ -163,7 +215,6 @@ func GetHistory(
|
||||
tag.WorkflowRunID(execution.GetRunId()),
|
||||
tag.Error(err))
|
||||
}
|
||||
|
||||
if len(nextPageToken) == 0 && transientWorkflowTaskInfo != nil {
|
||||
if err := validateTransientWorkflowTaskEvents(nextEventID, transientWorkflowTaskInfo); err != nil {
|
||||
metrics.ServiceErrIncompleteHistoryCounter.With(metricsHandler).Record(1)
|
||||
@@ -177,7 +228,16 @@ func GetHistory(
|
||||
historyEvents = append(historyEvents, transientWorkflowTaskInfo.HistorySuffix...)
|
||||
}
|
||||
|
||||
if err := ProcessOutgoingSearchAttributes(shard, historyEvents, namespaceID, persistenceVisibilityMgr); err != nil {
|
||||
ns, err := shard.GetNamespaceRegistry().GetNamespaceName(namespaceID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := ProcessOutgoingSearchAttributes(
|
||||
shard.GetSearchAttributesProvider(),
|
||||
shard.GetSearchAttributesMapperProvider(),
|
||||
historyEvents,
|
||||
ns,
|
||||
persistenceVisibilityMgr); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
@@ -228,7 +288,16 @@ func GetHistoryReverse(
|
||||
metricsHandler := interceptor.GetMetricsHandlerFromContext(ctx, logger).WithTags(metrics.OperationTag(metrics.HistoryGetHistoryReverseScope))
|
||||
metrics.HistorySize.With(metricsHandler).Record(int64(size))
|
||||
|
||||
if err := ProcessOutgoingSearchAttributes(shard, historyEvents, namespaceID, persistenceVisibilityMgr); err != nil {
|
||||
ns, err := shard.GetNamespaceRegistry().GetNamespaceName(namespaceID)
|
||||
if err != nil {
|
||||
return nil, nil, 0, err
|
||||
}
|
||||
if err := ProcessOutgoingSearchAttributes(
|
||||
shard.GetSearchAttributesProvider(),
|
||||
shard.GetSearchAttributesMapperProvider(),
|
||||
historyEvents,
|
||||
ns,
|
||||
persistenceVisibilityMgr); err != nil {
|
||||
return nil, nil, 0, err
|
||||
}
|
||||
|
||||
@@ -247,16 +316,13 @@ func GetHistoryReverse(
|
||||
}
|
||||
|
||||
func ProcessOutgoingSearchAttributes(
|
||||
shardCtx shard.Context,
|
||||
saProvider searchattribute.Provider,
|
||||
saMapperProvider searchattribute.MapperProvider,
|
||||
events []*historypb.HistoryEvent,
|
||||
namespaceId namespace.ID,
|
||||
ns namespace.Name,
|
||||
persistenceVisibilityMgr manager.VisibilityManager,
|
||||
) error {
|
||||
ns, err := shardCtx.GetNamespaceRegistry().GetNamespaceName(namespaceId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
saTypeMap, err := shardCtx.GetSearchAttributesProvider().GetSearchAttributes(persistenceVisibilityMgr.GetIndexName(), false)
|
||||
saTypeMap, err := saProvider.GetSearchAttributes(persistenceVisibilityMgr.GetIndexName(), false)
|
||||
if err != nil {
|
||||
return serviceerror.NewUnavailable(fmt.Sprintf(consts.ErrUnableToGetSearchAttributesMessage, err))
|
||||
}
|
||||
@@ -274,7 +340,7 @@ func ProcessOutgoingSearchAttributes(
|
||||
}
|
||||
if searchAttributes != nil {
|
||||
searchattribute.ApplyTypeMap(searchAttributes, saTypeMap)
|
||||
aliasedSas, err := searchattribute.AliasFields(shardCtx.GetSearchAttributesMapperProvider(), searchAttributes, ns.String())
|
||||
aliasedSas, err := searchattribute.AliasFields(saMapperProvider, searchAttributes, ns.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -305,3 +371,181 @@ func validateTransientWorkflowTaskEvents(
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func VerifyHistoryIsComplete(
|
||||
firstEvent *historyspb.StrippedHistoryEvent,
|
||||
lastEvent *historyspb.StrippedHistoryEvent,
|
||||
eventCount int,
|
||||
expectedFirstEventID int64,
|
||||
expectedLastEventID int64,
|
||||
isFirstPage bool,
|
||||
isLastPage bool,
|
||||
pageSize int,
|
||||
) error {
|
||||
|
||||
if eventCount == 0 {
|
||||
if isLastPage {
|
||||
// we seem to be returning a non-nil pageToken on the lastPage which
|
||||
// in turn cases the client to call getHistory again - only to find
|
||||
// there are no more events to consume - bail out if this is the case here
|
||||
return nil
|
||||
}
|
||||
return serviceerror.NewDataLoss("History contains zero events.")
|
||||
}
|
||||
|
||||
if !isFirstPage { // at least one page of history has been read previously
|
||||
if firstEvent.GetEventId() <= expectedFirstEventID {
|
||||
// not first page and no events have been read in the previous pages - not possible
|
||||
return serviceerror.NewDataLoss(fmt.Sprintf("Invalid history: expected first eventID to be > %v but got %v", expectedFirstEventID, firstEvent.GetEventId()))
|
||||
}
|
||||
expectedFirstEventID = firstEvent.GetEventId()
|
||||
}
|
||||
|
||||
if !isLastPage {
|
||||
// estimate lastEventID based on pageSize. This is a lower bound
|
||||
// since the persistence layer counts "batch of events" as a single page
|
||||
expectedLastEventID = expectedFirstEventID + int64(pageSize) - 1
|
||||
}
|
||||
|
||||
nExpectedEvents := expectedLastEventID - expectedFirstEventID + 1
|
||||
|
||||
if firstEvent.GetEventId() == expectedFirstEventID &&
|
||||
((isLastPage && lastEvent.GetEventId() == expectedLastEventID && int64(eventCount) == nExpectedEvents) ||
|
||||
(!isLastPage && lastEvent.GetEventId() >= expectedLastEventID && int64(eventCount) >= nExpectedEvents)) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return serviceerror.NewDataLoss(fmt.Sprintf("Incomplete history: expected events [%v-%v] but got events [%v-%v] of length %v: isFirstPage=%v,isLastPage=%v,pageSize=%v",
|
||||
expectedFirstEventID,
|
||||
expectedLastEventID,
|
||||
firstEvent.GetEventId(),
|
||||
lastEvent.GetEventId(),
|
||||
eventCount,
|
||||
isFirstPage,
|
||||
isLastPage,
|
||||
pageSize))
|
||||
}
|
||||
|
||||
// ProcessInternalRawHistory processes history in the field response.History.
|
||||
// History service can send history events in response.History.Events. In that case, process the events and move them
|
||||
// to response.Response.History. Usually this is done by history service but when history.sendRawHistoryBetweenInternalServices
|
||||
// is enabled, history service sends raw history events to frontend without any processing.
|
||||
func ProcessInternalRawHistory(
|
||||
requestContext context.Context,
|
||||
saProvider searchattribute.Provider,
|
||||
saMapperProvider searchattribute.MapperProvider,
|
||||
response *historyservice.GetWorkflowExecutionHistoryResponse,
|
||||
visibilityManager manager.VisibilityManager,
|
||||
versionChecker headers.VersionChecker,
|
||||
ns namespace.Name,
|
||||
isCloseEventOnly bool,
|
||||
) error {
|
||||
if response == nil || response.History == nil {
|
||||
return nil
|
||||
}
|
||||
response.Response.History = response.History
|
||||
if isCloseEventOnly && len(response.Response.History.Events) > 0 {
|
||||
response.Response.History.Events = response.Response.History.Events[len(response.Response.History.Events)-1:]
|
||||
}
|
||||
err := ProcessOutgoingSearchAttributes(
|
||||
saProvider,
|
||||
saMapperProvider,
|
||||
response.Response.History.Events,
|
||||
ns,
|
||||
visibilityManager,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = FixFollowEvents(requestContext, versionChecker, isCloseEventOnly, response.Response.History)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func FixFollowEvents(
|
||||
ctx context.Context,
|
||||
versionChecker headers.VersionChecker,
|
||||
isCloseEventOnly bool,
|
||||
history *historypb.History,
|
||||
) error {
|
||||
// Backwards-compatibility fix for retry events after #1866: older SDKs don't know how to "follow"
|
||||
// subsequent runs linked in WorkflowExecutionFailed or TimedOut events, so they'll get the wrong result
|
||||
// when trying to "get" the result of a workflow run. (This applies to cron runs also but "get" on a cron
|
||||
// workflow isn't really sensible.)
|
||||
//
|
||||
// To handle this in a backwards-compatible way, we'll pretend the completion event is actually
|
||||
// ContinuedAsNew, if it's Failed or TimedOut. We want to do this only when the client is looking for a
|
||||
// completion event, and not when it's getting the history to display for other purposes. The best signal
|
||||
// for that purpose is `isCloseEventOnly`. (We can't use `isLongPoll` also because in some cases, older
|
||||
// versions of the Java SDK don't set that flag.)
|
||||
//
|
||||
// TODO: We can remove this once we no longer support SDK versions prior to around September 2021.
|
||||
// Revisit this once we have an SDK deprecation policy.
|
||||
followsNextRunId := versionChecker.ClientSupportsFeature(ctx, headers.FeatureFollowsNextRunID)
|
||||
if isCloseEventOnly && !followsNextRunId && len(history.Events) > 0 {
|
||||
lastEvent := history.Events[len(history.Events)-1]
|
||||
fakeEvent, err := makeFakeContinuedAsNewEvent(ctx, lastEvent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fakeEvent != nil {
|
||||
history.Events[len(history.Events)-1] = fakeEvent
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeFakeContinuedAsNewEvent(
|
||||
_ context.Context,
|
||||
lastEvent *historypb.HistoryEvent,
|
||||
) (*historypb.HistoryEvent, error) {
|
||||
switch lastEvent.EventType { // nolint:exhaustive
|
||||
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED:
|
||||
if lastEvent.GetWorkflowExecutionCompletedEventAttributes().GetNewExecutionRunId() == "" {
|
||||
return nil, nil
|
||||
}
|
||||
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_FAILED:
|
||||
if lastEvent.GetWorkflowExecutionFailedEventAttributes().GetNewExecutionRunId() == "" {
|
||||
return nil, nil
|
||||
}
|
||||
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT:
|
||||
if lastEvent.GetWorkflowExecutionTimedOutEventAttributes().GetNewExecutionRunId() == "" {
|
||||
return nil, nil
|
||||
}
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// We need to replace the last event with a continued-as-new event that has at least the
|
||||
// NewExecutionRunId field. We don't actually need any other fields, since that's the only one
|
||||
// the client looks at in this case, but copy the last result or failure from the real completed
|
||||
// event just so it's clear what the result was.
|
||||
newAttrs := &historypb.WorkflowExecutionContinuedAsNewEventAttributes{}
|
||||
switch lastEvent.EventType { // nolint:exhaustive
|
||||
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED:
|
||||
attrs := lastEvent.GetWorkflowExecutionCompletedEventAttributes()
|
||||
newAttrs.NewExecutionRunId = attrs.NewExecutionRunId
|
||||
newAttrs.LastCompletionResult = attrs.Result
|
||||
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_FAILED:
|
||||
attrs := lastEvent.GetWorkflowExecutionFailedEventAttributes()
|
||||
newAttrs.NewExecutionRunId = attrs.NewExecutionRunId
|
||||
newAttrs.Failure = attrs.Failure
|
||||
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT:
|
||||
attrs := lastEvent.GetWorkflowExecutionTimedOutEventAttributes()
|
||||
newAttrs.NewExecutionRunId = attrs.NewExecutionRunId
|
||||
newAttrs.Failure = failure.NewTimeoutFailure("workflow timeout", enumspb.TIMEOUT_TYPE_START_TO_CLOSE)
|
||||
}
|
||||
|
||||
return &historypb.HistoryEvent{
|
||||
EventId: lastEvent.EventId,
|
||||
EventTime: lastEvent.EventTime,
|
||||
EventType: enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW,
|
||||
Version: lastEvent.Version,
|
||||
TaskId: lastEvent.TaskId,
|
||||
Attributes: &historypb.HistoryEvent_WorkflowExecutionContinuedAsNewEventAttributes{
|
||||
WorkflowExecutionContinuedAsNewEventAttributes: newAttrs,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ import (
|
||||
persistencespb "go.temporal.io/server/api/persistence/v1"
|
||||
tokenspb "go.temporal.io/server/api/token/v1"
|
||||
"go.temporal.io/server/common"
|
||||
"go.temporal.io/server/common/failure"
|
||||
"go.temporal.io/server/common/headers"
|
||||
"go.temporal.io/server/common/log/tag"
|
||||
"go.temporal.io/server/common/namespace"
|
||||
@@ -60,7 +59,7 @@ func Invoke(
|
||||
eventNotifier events.Notifier,
|
||||
request *historyservice.GetWorkflowExecutionHistoryRequest,
|
||||
persistenceVisibilityMgr manager.VisibilityManager,
|
||||
) (_ *historyservice.GetWorkflowExecutionHistoryResponse, retError error) {
|
||||
) (_ *historyservice.GetWorkflowExecutionHistoryResponseWithRaw, retError error) {
|
||||
namespaceID := namespace.ID(request.GetNamespaceId())
|
||||
err := api.ValidateNamespaceUUID(namespaceID)
|
||||
if err != nil {
|
||||
@@ -225,9 +224,12 @@ func Invoke(
|
||||
history := &historypb.History{}
|
||||
history.Events = []*historypb.HistoryEvent{}
|
||||
var historyBlob []*commonpb.DataBlob
|
||||
config := shardContext.GetConfig()
|
||||
sendRawHistoryBetweenInternalServices := config.SendRawHistoryBetweenInternalServices()
|
||||
sendRawWorkflowHistoryForNamespace := config.SendRawWorkflowHistory(request.Request.GetNamespace())
|
||||
if isCloseEventOnly {
|
||||
if !isWorkflowRunning {
|
||||
if shardContext.GetConfig().SendRawWorkflowHistory(request.Request.GetNamespace()) {
|
||||
if sendRawWorkflowHistoryForNamespace || sendRawHistoryBetweenInternalServices {
|
||||
historyBlob, _, err = api.GetRawHistory(
|
||||
ctx,
|
||||
shardContext,
|
||||
@@ -243,7 +245,6 @@ func Invoke(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// since getHistory func will not return empty history, so the below is safe
|
||||
historyBlob = historyBlob[len(historyBlob)-1:]
|
||||
} else {
|
||||
@@ -282,7 +283,7 @@ func Invoke(
|
||||
continuationToken = nil
|
||||
}
|
||||
} else {
|
||||
if shardContext.GetConfig().SendRawWorkflowHistory(request.Request.GetNamespace()) {
|
||||
if sendRawWorkflowHistoryForNamespace || sendRawHistoryBetweenInternalServices {
|
||||
historyBlob, continuationToken.PersistenceToken, err = api.GetRawHistory(
|
||||
ctx,
|
||||
shardContext,
|
||||
@@ -329,92 +330,34 @@ func Invoke(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Backwards-compatibility fix for retry events after #1866: older SDKs don't know how to "follow"
|
||||
// subsequent runs linked in WorkflowExecutionFailed or TimedOut events, so they'll get the wrong result
|
||||
// when trying to "get" the result of a workflow run. (This applies to cron runs also but "get" on a cron
|
||||
// workflow isn't really sensible.)
|
||||
//
|
||||
// To handle this in a backwards-compatible way, we'll pretend the completion event is actually
|
||||
// ContinuedAsNew, if it's Failed or TimedOut. We want to do this only when the client is looking for a
|
||||
// completion event, and not when it's getting the history to display for other purposes. The best signal
|
||||
// for that purpose is `isCloseEventOnly`. (We can't use `isLongPoll` also because in some cases, older
|
||||
// versions of the Java SDK don't set that flag.)
|
||||
//
|
||||
// TODO: We can remove this once we no longer support SDK versions prior to around September 2021.
|
||||
// Revisit this once we have an SDK deprecation policy.
|
||||
followsNextRunId := versionChecker.ClientSupportsFeature(ctx, headers.FeatureFollowsNextRunID)
|
||||
if isCloseEventOnly && !followsNextRunId && len(history.Events) > 0 {
|
||||
lastEvent := history.Events[len(history.Events)-1]
|
||||
fakeEvent, err := makeFakeContinuedAsNewEvent(ctx, lastEvent)
|
||||
// if SendRawHistoryBetweenInternalServices is enabled, we do this check in frontend service
|
||||
if len(history.Events) > 0 {
|
||||
err = api.FixFollowEvents(ctx, versionChecker, isCloseEventOnly, history)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if fakeEvent != nil {
|
||||
history.Events[len(history.Events)-1] = fakeEvent
|
||||
}
|
||||
}
|
||||
|
||||
return &historyservice.GetWorkflowExecutionHistoryResponse{
|
||||
var rawHistory [][]byte
|
||||
// if sendRawHistoryBetweenInternalServices is true and SendRawWorkflowHistory is not enabled for this namespace,
|
||||
// send history in raw format in History field of historyservice.GetWorkflowExecutionHistoryResponseWithRaw.
|
||||
// If SendRawWorkflowHistory is enabled for this namespace, raw history will be appended to RawHistory field in
|
||||
// workflowservice.GetWorkflowExecutionHistoryResponse.
|
||||
if sendRawHistoryBetweenInternalServices && !sendRawWorkflowHistoryForNamespace {
|
||||
rawHistory = make([][]byte, 0, len(historyBlob))
|
||||
for _, blob := range historyBlob {
|
||||
rawHistory = append(rawHistory, blob.Data)
|
||||
}
|
||||
historyBlob = nil
|
||||
}
|
||||
|
||||
return &historyservice.GetWorkflowExecutionHistoryResponseWithRaw{
|
||||
Response: &workflowservice.GetWorkflowExecutionHistoryResponse{
|
||||
History: history,
|
||||
RawHistory: historyBlob,
|
||||
NextPageToken: nextToken,
|
||||
Archived: false,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func makeFakeContinuedAsNewEvent(
|
||||
_ context.Context,
|
||||
lastEvent *historypb.HistoryEvent,
|
||||
) (*historypb.HistoryEvent, error) {
|
||||
// nolint:exhaustive
|
||||
switch lastEvent.EventType {
|
||||
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED:
|
||||
if lastEvent.GetWorkflowExecutionCompletedEventAttributes().GetNewExecutionRunId() == "" {
|
||||
return nil, nil
|
||||
}
|
||||
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_FAILED:
|
||||
if lastEvent.GetWorkflowExecutionFailedEventAttributes().GetNewExecutionRunId() == "" {
|
||||
return nil, nil
|
||||
}
|
||||
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT:
|
||||
if lastEvent.GetWorkflowExecutionTimedOutEventAttributes().GetNewExecutionRunId() == "" {
|
||||
return nil, nil
|
||||
}
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// We need to replace the last event with a continued-as-new event that has at least the
|
||||
// NewExecutionRunId field. We don't actually need any other fields, since that's the only one
|
||||
// the client looks at in this case, but copy the last result or failure from the real completed
|
||||
// event just so it's clear what the result was.
|
||||
newAttrs := &historypb.WorkflowExecutionContinuedAsNewEventAttributes{}
|
||||
// nolint:exhaustive
|
||||
switch lastEvent.EventType {
|
||||
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED:
|
||||
attrs := lastEvent.GetWorkflowExecutionCompletedEventAttributes()
|
||||
newAttrs.NewExecutionRunId = attrs.NewExecutionRunId
|
||||
newAttrs.LastCompletionResult = attrs.Result
|
||||
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_FAILED:
|
||||
attrs := lastEvent.GetWorkflowExecutionFailedEventAttributes()
|
||||
newAttrs.NewExecutionRunId = attrs.NewExecutionRunId
|
||||
newAttrs.Failure = attrs.Failure
|
||||
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT:
|
||||
attrs := lastEvent.GetWorkflowExecutionTimedOutEventAttributes()
|
||||
newAttrs.NewExecutionRunId = attrs.NewExecutionRunId
|
||||
newAttrs.Failure = failure.NewTimeoutFailure("workflow timeout", enumspb.TIMEOUT_TYPE_START_TO_CLOSE)
|
||||
}
|
||||
|
||||
return &historypb.HistoryEvent{
|
||||
EventId: lastEvent.EventId,
|
||||
EventTime: lastEvent.EventTime,
|
||||
EventType: enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW,
|
||||
Version: lastEvent.Version,
|
||||
TaskId: lastEvent.TaskId,
|
||||
Attributes: &historypb.HistoryEvent_WorkflowExecutionContinuedAsNewEventAttributes{
|
||||
WorkflowExecutionContinuedAsNewEventAttributes: newAttrs,
|
||||
},
|
||||
History: rawHistory,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -730,7 +730,12 @@ func (s *Starter) generateResponse(
|
||||
}, nil
|
||||
}
|
||||
|
||||
if err := api.ProcessOutgoingSearchAttributes(s.shardContext, historyEvents, s.namespace.ID(), s.visibilityManager); err != nil {
|
||||
if err := api.ProcessOutgoingSearchAttributes(
|
||||
shardCtx.GetSearchAttributesProvider(),
|
||||
shardCtx.GetSearchAttributesMapperProvider(),
|
||||
historyEvents,
|
||||
s.namespace.Name(),
|
||||
s.visibilityManager); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -372,7 +372,8 @@ type Config struct {
|
||||
WorkflowExecutionMaxTotalUpdates dynamicconfig.IntPropertyFnWithNamespaceFilter
|
||||
WorkflowExecutionMaxTotalUpdatesSuggestContinueAsNewThreshold dynamicconfig.FloatPropertyFnWithNamespaceFilter
|
||||
|
||||
SendRawWorkflowHistory dynamicconfig.BoolPropertyFnWithNamespaceFilter
|
||||
SendRawHistoryBetweenInternalServices dynamicconfig.BoolPropertyFn
|
||||
SendRawWorkflowHistory dynamicconfig.BoolPropertyFnWithNamespaceFilter
|
||||
|
||||
WorkflowIdReuseMinimalInterval dynamicconfig.DurationPropertyFnWithNamespaceFilter
|
||||
EnableWorkflowIdReuseStartTimeValidation dynamicconfig.BoolPropertyFnWithNamespaceFilter
|
||||
@@ -689,6 +690,7 @@ func NewConfig(
|
||||
WorkflowExecutionMaxTotalUpdates: dynamicconfig.WorkflowExecutionMaxTotalUpdates.Get(dc),
|
||||
WorkflowExecutionMaxTotalUpdatesSuggestContinueAsNewThreshold: dynamicconfig.WorkflowExecutionMaxTotalUpdatesSuggestContinueAsNewThreshold.Get(dc),
|
||||
|
||||
SendRawHistoryBetweenInternalServices: dynamicconfig.SendRawHistoryBetweenInternalServices.Get(dc),
|
||||
SendRawWorkflowHistory: dynamicconfig.SendRawWorkflowHistory.Get(dc),
|
||||
WorkflowIdReuseMinimalInterval: dynamicconfig.WorkflowIdReuseMinimalInterval.Get(dc),
|
||||
EnableWorkflowIdReuseStartTimeValidation: dynamicconfig.EnableWorkflowIdReuseStartTimeValidation.Get(dc),
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright (c) 2020 Temporal Technologies Inc. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package events
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
historypb "go.temporal.io/api/history/v1"
|
||||
"go.temporal.io/api/serviceerror"
|
||||
)
|
||||
|
||||
func VerifyHistoryIsComplete(
|
||||
events []*historypb.HistoryEvent,
|
||||
expectedFirstEventID int64,
|
||||
expectedLastEventID int64,
|
||||
isFirstPage bool,
|
||||
isLastPage bool,
|
||||
pageSize int,
|
||||
) error {
|
||||
|
||||
nEvents := len(events)
|
||||
if nEvents == 0 {
|
||||
if isLastPage {
|
||||
// we seem to be returning a non-nil pageToken on the lastPage which
|
||||
// in turn cases the client to call getHistory again - only to find
|
||||
// there are no more events to consume - bail out if this is the case here
|
||||
return nil
|
||||
}
|
||||
return serviceerror.NewDataLoss("History contains zero events.")
|
||||
}
|
||||
|
||||
firstEventID := events[0].GetEventId()
|
||||
lastEventID := events[nEvents-1].GetEventId()
|
||||
|
||||
if !isFirstPage { // at least one page of history has been read previously
|
||||
if firstEventID <= expectedFirstEventID {
|
||||
// not first page and no events have been read in the previous pages - not possible
|
||||
return serviceerror.NewDataLoss(fmt.Sprintf("Invalid history: expected first eventID to be > %v but got %v", expectedFirstEventID, firstEventID))
|
||||
}
|
||||
expectedFirstEventID = firstEventID
|
||||
}
|
||||
|
||||
if !isLastPage {
|
||||
// estimate lastEventID based on pageSize. This is a lower bound
|
||||
// since the persistence layer counts "batch of events" as a single page
|
||||
expectedLastEventID = expectedFirstEventID + int64(pageSize) - 1
|
||||
}
|
||||
|
||||
nExpectedEvents := expectedLastEventID - expectedFirstEventID + 1
|
||||
|
||||
if firstEventID == expectedFirstEventID &&
|
||||
((isLastPage && lastEventID == expectedLastEventID && int64(nEvents) == nExpectedEvents) ||
|
||||
(!isLastPage && lastEventID >= expectedLastEventID && int64(nEvents) >= nExpectedEvents)) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return serviceerror.NewDataLoss(fmt.Sprintf("Incomplete history: expected events [%v-%v] but got events [%v-%v] of length %v: isFirstPage=%v,isLastPage=%v,pageSize=%v",
|
||||
expectedFirstEventID,
|
||||
expectedLastEventID,
|
||||
firstEventID,
|
||||
lastEventID,
|
||||
nEvents,
|
||||
isFirstPage,
|
||||
isLastPage,
|
||||
pageSize))
|
||||
}
|
||||
@@ -2151,7 +2151,7 @@ func (h *Handler) StreamWorkflowReplicationMessages(
|
||||
func (h *Handler) GetWorkflowExecutionHistory(
|
||||
ctx context.Context,
|
||||
request *historyservice.GetWorkflowExecutionHistoryRequest,
|
||||
) (_ *historyservice.GetWorkflowExecutionHistoryResponse, retErr error) {
|
||||
) (_ *historyservice.GetWorkflowExecutionHistoryResponseWithRaw, retErr error) {
|
||||
defer log.CapturePanic(h.logger, &retErr)
|
||||
h.startWG.Wait()
|
||||
|
||||
|
||||
@@ -1011,7 +1011,7 @@ func (e *historyEngineImpl) GetReplicationStatus(
|
||||
func (e *historyEngineImpl) GetWorkflowExecutionHistory(
|
||||
ctx context.Context,
|
||||
request *historyservice.GetWorkflowExecutionHistoryRequest,
|
||||
) (_ *historyservice.GetWorkflowExecutionHistoryResponse, retError error) {
|
||||
) (_ *historyservice.GetWorkflowExecutionHistoryResponseWithRaw, retError error) {
|
||||
return getworkflowexecutionhistory.Invoke(ctx, e.shardContext, e.workflowConsistencyChecker, e.versionChecker, e.eventNotifier, request, e.persistenceVisibilityMgr)
|
||||
}
|
||||
|
||||
|
||||
@@ -5330,7 +5330,6 @@ func (s *engineSuite) TestReapplyEvents_ResetWorkflow() {
|
||||
func (s *engineSuite) TestEagerWorkflowStart_DoesNotCreateTransferTask() {
|
||||
var recordedTasks []tasks.Task
|
||||
|
||||
s.mockNamespaceCache.EXPECT().GetNamespaceName(gomock.Any()).Return(tests.Namespace, nil)
|
||||
s.mockVisibilityMgr.EXPECT().GetIndexName().Return("mock")
|
||||
s.mockSearchAttributesProvider.EXPECT().GetSearchAttributes("mock", false).Return(searchattribute.NameTypeMap{}, nil)
|
||||
s.mockExecutionMgr.EXPECT().CreateWorkflowExecution(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, request *persistence.CreateWorkflowExecutionRequest) (*persistence.CreateWorkflowExecutionResponse, error) {
|
||||
@@ -5587,6 +5586,119 @@ func (s *engineSuite) TestGetWorkflowExecutionHistory() {
|
||||
s.Equal("this workflow failed", attrs2.Failure.Message)
|
||||
}
|
||||
|
||||
func (s *engineSuite) TestGetWorkflowExecutionHistoryWhenInternalRawHistoryIsEnabled() {
|
||||
s.config.SendRawHistoryBetweenInternalServices = func() bool { return true }
|
||||
we := commonpb.WorkflowExecution{WorkflowId: "wid1", RunId: uuid.New()}
|
||||
namespaceEntry := namespace.NewLocalNamespaceForTest(
|
||||
&persistencespb.NamespaceInfo{Name: "test-namespace"},
|
||||
&persistencespb.NamespaceConfig{},
|
||||
"")
|
||||
s.mockNamespaceCache.EXPECT().GetNamespaceByID(gomock.Any()).Return(namespaceEntry, nil).AnyTimes()
|
||||
newRunID := uuid.New()
|
||||
|
||||
req := &historyservice.GetWorkflowExecutionHistoryRequest{
|
||||
NamespaceId: tests.NamespaceID.String(),
|
||||
Request: &workflowservice.GetWorkflowExecutionHistoryRequest{
|
||||
Execution: &we,
|
||||
MaximumPageSize: 10,
|
||||
NextPageToken: nil,
|
||||
WaitNewEvent: true,
|
||||
HistoryEventFilterType: enumspb.HISTORY_EVENT_FILTER_TYPE_CLOSE_EVENT,
|
||||
SkipArchival: true,
|
||||
},
|
||||
}
|
||||
|
||||
// set up mocks to simulate a failed workflow with a retry policy. the failure event is id 5.
|
||||
branchToken := []byte{1, 2, 3}
|
||||
|
||||
s.mockNamespaceCache.EXPECT().GetNamespaceName(tests.NamespaceID).Return(tests.Namespace, nil).AnyTimes()
|
||||
versionHistory := versionhistory.NewVersionHistory(branchToken, []*historyspb.VersionHistoryItem{
|
||||
versionhistory.NewVersionHistoryItem(int64(10), int64(100)),
|
||||
})
|
||||
versionHistories := versionhistory.NewVersionHistories(versionHistory)
|
||||
mState := &persistencespb.WorkflowMutableState{
|
||||
ExecutionState: &persistencespb.WorkflowExecutionState{
|
||||
RunId: we.RunId,
|
||||
State: enumsspb.WORKFLOW_EXECUTION_STATE_COMPLETED,
|
||||
Status: enumspb.WORKFLOW_EXECUTION_STATUS_FAILED,
|
||||
},
|
||||
NextEventId: 6,
|
||||
ExecutionInfo: &persistencespb.WorkflowExecutionInfo{
|
||||
NamespaceId: tests.NamespaceID.String(),
|
||||
WorkflowId: we.WorkflowId,
|
||||
VersionHistories: versionHistories,
|
||||
WorkflowTypeName: "mytype",
|
||||
LastFirstEventId: 5,
|
||||
LastFirstEventTxnId: 100,
|
||||
},
|
||||
}
|
||||
s.mockExecutionMgr.EXPECT().GetWorkflowExecution(gomock.Any(), &persistence.GetWorkflowExecutionRequest{
|
||||
ShardID: 1,
|
||||
NamespaceID: tests.NamespaceID.String(),
|
||||
WorkflowID: we.WorkflowId,
|
||||
RunID: we.RunId,
|
||||
}).Return(&persistence.GetWorkflowExecutionResponse{State: mState}, nil).AnyTimes()
|
||||
// GetWorkflowExecutionHistory will request the last event
|
||||
history := historypb.History{
|
||||
Events: []*historypb.HistoryEvent{
|
||||
{
|
||||
EventId: int64(5),
|
||||
EventType: enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_FAILED,
|
||||
Attributes: &historypb.HistoryEvent_WorkflowExecutionFailedEventAttributes{
|
||||
WorkflowExecutionFailedEventAttributes: &historypb.WorkflowExecutionFailedEventAttributes{
|
||||
Failure: &failurepb.Failure{Message: "this workflow failed"},
|
||||
RetryState: enumspb.RETRY_STATE_IN_PROGRESS,
|
||||
WorkflowTaskCompletedEventId: 4,
|
||||
NewExecutionRunId: newRunID,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
historyBlob, err := history.Marshal()
|
||||
s.NoError(err)
|
||||
|
||||
s.mockExecutionMgr.EXPECT().ReadRawHistoryBranch(gomock.Any(), &persistence.ReadHistoryBranchRequest{
|
||||
BranchToken: branchToken,
|
||||
MinEventID: 5,
|
||||
MaxEventID: 6,
|
||||
PageSize: 10,
|
||||
NextPageToken: nil,
|
||||
ShardID: 1,
|
||||
}).Return(&persistence.ReadRawHistoryBranchResponse{
|
||||
HistoryEventBlobs: []*commonpb.DataBlob{
|
||||
{
|
||||
EncodingType: enumspb.ENCODING_TYPE_PROTO3,
|
||||
Data: historyBlob,
|
||||
},
|
||||
},
|
||||
NextPageToken: []byte{},
|
||||
Size: 1,
|
||||
}, nil).Times(1)
|
||||
|
||||
s.mockExecutionMgr.EXPECT().TrimHistoryBranch(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
s.mockSearchAttributesProvider.EXPECT().GetSearchAttributes(gomock.Any(), false).Return(searchattribute.TestNameTypeMap, nil).AnyTimes()
|
||||
s.mockVisibilityMgr.EXPECT().GetIndexName().Return(esIndexName).AnyTimes()
|
||||
|
||||
engine, err := s.historyEngine.shardContext.GetEngine(context.Background())
|
||||
s.NoError(err)
|
||||
|
||||
resp, err := engine.GetWorkflowExecutionHistory(context.Background(), req)
|
||||
s.NoError(err)
|
||||
s.False(resp.Response.Archived)
|
||||
s.Len(resp.History, 1)
|
||||
err = history.Unmarshal(resp.History[0])
|
||||
s.NoError(err)
|
||||
event := history.Events[0]
|
||||
s.Equal(int64(5), event.EventId)
|
||||
s.Equal(enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_FAILED, event.EventType)
|
||||
attrs := event.GetWorkflowExecutionFailedEventAttributes()
|
||||
s.Equal("this workflow failed", attrs.Failure.Message)
|
||||
s.Equal(newRunID, attrs.NewExecutionRunId)
|
||||
s.Equal(enumspb.RETRY_STATE_IN_PROGRESS, attrs.RetryState)
|
||||
}
|
||||
|
||||
func (s *engineSuite) TestGetWorkflowExecutionHistory_RawHistoryWithTransientDecision() {
|
||||
we := commonpb.WorkflowExecution{WorkflowId: "wid1", RunId: uuid.New()}
|
||||
|
||||
@@ -5629,18 +5741,22 @@ func (s *engineSuite) TestGetWorkflowExecutionHistory_RawHistoryWithTransientDec
|
||||
}
|
||||
|
||||
s.mockNamespaceCache.EXPECT().GetNamespaceID(tests.Namespace).Return(tests.NamespaceID, nil).AnyTimes()
|
||||
historyBlob1, err := s.mockShard.GetPayloadSerializer().SerializeEvent(
|
||||
&historypb.HistoryEvent{
|
||||
EventId: int64(3),
|
||||
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_STARTED,
|
||||
historyBlob1, err := s.mockShard.GetPayloadSerializer().SerializeEvents(
|
||||
[]*historypb.HistoryEvent{
|
||||
{
|
||||
EventId: int64(3),
|
||||
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_STARTED,
|
||||
},
|
||||
},
|
||||
enumspb.ENCODING_TYPE_PROTO3,
|
||||
)
|
||||
s.NoError(err)
|
||||
historyBlob2, err := s.mockShard.GetPayloadSerializer().SerializeEvent(
|
||||
&historypb.HistoryEvent{
|
||||
EventId: int64(4),
|
||||
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_TIMED_OUT,
|
||||
historyBlob2, err := s.mockShard.GetPayloadSerializer().SerializeEvents(
|
||||
[]*historypb.HistoryEvent{
|
||||
{
|
||||
EventId: int64(4),
|
||||
EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_TIMED_OUT,
|
||||
},
|
||||
},
|
||||
enumspb.ENCODING_TYPE_PROTO3,
|
||||
)
|
||||
@@ -5663,13 +5779,11 @@ func (s *engineSuite) TestGetWorkflowExecutionHistory_RawHistoryWithTransientDec
|
||||
s.NoError(err)
|
||||
s.False(resp.Response.Archived)
|
||||
s.Empty(resp.Response.History.Events)
|
||||
s.Len(resp.Response.RawHistory, 4)
|
||||
event, err := s.mockShard.GetPayloadSerializer().DeserializeEvent(resp.Response.RawHistory[2])
|
||||
s.Len(resp.Response.RawHistory, 3)
|
||||
historyEvents, err := s.mockShard.GetPayloadSerializer().DeserializeEvents(resp.Response.RawHistory[2])
|
||||
s.NoError(err)
|
||||
s.Equal(enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED, event.EventType)
|
||||
event, err = s.mockShard.GetPayloadSerializer().DeserializeEvent(resp.Response.RawHistory[3])
|
||||
s.NoError(err)
|
||||
s.Equal(enumspb.EVENT_TYPE_WORKFLOW_TASK_STARTED, event.EventType)
|
||||
s.Equal(enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED, historyEvents[0].EventType)
|
||||
s.Equal(enumspb.EVENT_TYPE_WORKFLOW_TASK_STARTED, historyEvents[1].EventType)
|
||||
}
|
||||
|
||||
func (s *engineSuite) Test_GetWorkflowExecutionRawHistoryV2_FailedOnInvalidWorkflowID() {
|
||||
|
||||
@@ -109,7 +109,7 @@ type (
|
||||
GetReplicationStatus(ctx context.Context, request *historyservice.GetReplicationStatusRequest) (*historyservice.ShardReplicationStatus, error)
|
||||
UpdateWorkflowExecution(ctx context.Context, request *historyservice.UpdateWorkflowExecutionRequest) (*historyservice.UpdateWorkflowExecutionResponse, error)
|
||||
PollWorkflowExecutionUpdate(ctx context.Context, request *historyservice.PollWorkflowExecutionUpdateRequest) (*historyservice.PollWorkflowExecutionUpdateResponse, error)
|
||||
GetWorkflowExecutionHistory(ctx context.Context, request *historyservice.GetWorkflowExecutionHistoryRequest) (*historyservice.GetWorkflowExecutionHistoryResponse, error)
|
||||
GetWorkflowExecutionHistory(ctx context.Context, request *historyservice.GetWorkflowExecutionHistoryRequest) (*historyservice.GetWorkflowExecutionHistoryResponseWithRaw, error)
|
||||
GetWorkflowExecutionHistoryReverse(ctx context.Context, request *historyservice.GetWorkflowExecutionHistoryReverseRequest) (*historyservice.GetWorkflowExecutionHistoryReverseResponse, error)
|
||||
GetWorkflowExecutionRawHistory(ctx context.Context, request *historyservice.GetWorkflowExecutionRawHistoryRequest) (*historyservice.GetWorkflowExecutionRawHistoryResponse, error)
|
||||
GetWorkflowExecutionRawHistoryV2(ctx context.Context, request *historyservice.GetWorkflowExecutionRawHistoryV2Request) (*historyservice.GetWorkflowExecutionRawHistoryV2Response, error)
|
||||
|
||||
@@ -302,10 +302,10 @@ func (mr *MockEngineMockRecorder) GetReplicationTasksIter(ctx, pollingCluster, m
|
||||
}
|
||||
|
||||
// GetWorkflowExecutionHistory mocks base method.
|
||||
func (m *MockEngine) GetWorkflowExecutionHistory(ctx context.Context, request *historyservice.GetWorkflowExecutionHistoryRequest) (*historyservice.GetWorkflowExecutionHistoryResponse, error) {
|
||||
func (m *MockEngine) GetWorkflowExecutionHistory(ctx context.Context, request *historyservice.GetWorkflowExecutionHistoryRequest) (*historyservice.GetWorkflowExecutionHistoryResponseWithRaw, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetWorkflowExecutionHistory", ctx, request)
|
||||
ret0, _ := ret[0].(*historyservice.GetWorkflowExecutionHistoryResponse)
|
||||
ret0, _ := ret[0].(*historyservice.GetWorkflowExecutionHistoryResponseWithRaw)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import (
|
||||
"go.temporal.io/server/common/persistence"
|
||||
"go.temporal.io/server/common/persistence/visibility/manager"
|
||||
"go.temporal.io/server/common/resource"
|
||||
"go.temporal.io/server/common/searchattribute"
|
||||
"go.temporal.io/server/common/testing/testhooks"
|
||||
"go.temporal.io/server/common/tqid"
|
||||
"go.temporal.io/server/service/worker/deployment"
|
||||
@@ -92,6 +93,8 @@ func NewHandler(
|
||||
visibilityManager manager.VisibilityManager,
|
||||
nexusEndpointManager persistence.NexusEndpointManager,
|
||||
testHooks testhooks.TestHooks,
|
||||
saProvider searchattribute.Provider,
|
||||
saMapperProvider searchattribute.MapperProvider,
|
||||
) *Handler {
|
||||
handler := &Handler{
|
||||
config: config,
|
||||
@@ -116,6 +119,8 @@ func NewHandler(
|
||||
visibilityManager,
|
||||
nexusEndpointManager,
|
||||
testHooks,
|
||||
saProvider,
|
||||
saMapperProvider,
|
||||
),
|
||||
namespaceRegistry: namespaceRegistry,
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ import (
|
||||
"go.temporal.io/server/common/persistence/visibility/manager"
|
||||
"go.temporal.io/server/common/primitives/timestamp"
|
||||
"go.temporal.io/server/common/resource"
|
||||
"go.temporal.io/server/common/searchattribute"
|
||||
serviceerrors "go.temporal.io/server/common/serviceerror"
|
||||
"go.temporal.io/server/common/stream_batcher"
|
||||
"go.temporal.io/server/common/tasktoken"
|
||||
@@ -76,6 +77,7 @@ import (
|
||||
"go.temporal.io/server/common/tqid"
|
||||
"go.temporal.io/server/common/util"
|
||||
"go.temporal.io/server/common/worker_versioning"
|
||||
"go.temporal.io/server/service/history/api"
|
||||
"go.temporal.io/server/service/worker/deployment"
|
||||
"go.temporal.io/server/service/worker/workerdeployment"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
@@ -145,11 +147,14 @@ type (
|
||||
visibilityManager manager.VisibilityManager
|
||||
nexusEndpointClient *nexusEndpointClient
|
||||
nexusEndpointsOwnershipLostCh chan struct{}
|
||||
saMapperProvider searchattribute.MapperProvider
|
||||
saProvider searchattribute.Provider
|
||||
metricsHandler metrics.Handler
|
||||
partitionsLock sync.RWMutex // locks mutation of partitions
|
||||
partitions map[tqid.PartitionKey]taskQueuePartitionManager
|
||||
gaugeMetrics gaugeMetrics // per-namespace task queue counters
|
||||
config *Config
|
||||
versionChecker headers.VersionChecker
|
||||
testHooks testhooks.TestHooks
|
||||
// queryResults maps query TaskID (which is a UUID generated in QueryWorkflow() call) to a channel
|
||||
// that QueryWorkflow() will block on. The channel is unblocked either by worker sending response through
|
||||
@@ -221,6 +226,8 @@ func NewEngine(
|
||||
visibilityManager manager.VisibilityManager,
|
||||
nexusEndpointManager persistence.NexusEndpointManager,
|
||||
testHooks testhooks.TestHooks,
|
||||
saProvider searchattribute.Provider,
|
||||
saMapperProvider searchattribute.MapperProvider,
|
||||
) Engine {
|
||||
scopedMetricsHandler := metricsHandler.WithTags(metrics.OperationTag(metrics.MatchingEngineScope))
|
||||
e := &matchingEngineImpl{
|
||||
@@ -243,6 +250,8 @@ func NewEngine(
|
||||
visibilityManager: visibilityManager,
|
||||
nexusEndpointClient: newEndpointClient(config.NexusEndpointsRefreshInterval, nexusEndpointManager),
|
||||
nexusEndpointsOwnershipLostCh: make(chan struct{}),
|
||||
saProvider: saProvider,
|
||||
saMapperProvider: saMapperProvider,
|
||||
metricsHandler: scopedMetricsHandler,
|
||||
partitions: make(map[tqid.PartitionKey]taskQueuePartitionManager),
|
||||
gaugeMetrics: gaugeMetrics{
|
||||
@@ -252,6 +261,7 @@ func NewEngine(
|
||||
loadedPhysicalTaskQueueCount: make(map[taskQueueCounterKey]int),
|
||||
},
|
||||
config: config,
|
||||
versionChecker: headers.NewDefaultVersionChecker(),
|
||||
testHooks: testHooks,
|
||||
queryResults: collection.NewSyncMap[string, chan *queryResult](),
|
||||
nexusResults: collection.NewSyncMap[string, chan *nexusResult](),
|
||||
@@ -766,6 +776,23 @@ func (e *matchingEngineImpl) getHistoryForQueryTask(
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// History service can send history events in response.History.Events. In that case use that directly.
|
||||
// This happens when history.sendRawHistoryBetweenInternalServices is enabled.
|
||||
ns, err := e.namespaceRegistry.GetNamespaceName(nsID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
err = api.ProcessInternalRawHistory(
|
||||
ctx,
|
||||
e.saProvider,
|
||||
e.saMapperProvider,
|
||||
resp,
|
||||
e.visibilityManager,
|
||||
e.versionChecker,
|
||||
ns,
|
||||
false,
|
||||
)
|
||||
|
||||
hist := resp.GetResponse().GetHistory()
|
||||
if resp.GetResponse().GetRawHistory() != nil {
|
||||
historyEvents := make([]*historypb.HistoryEvent, 0, maxPageSize)
|
||||
|
||||
@@ -209,6 +209,9 @@ func (s *FunctionalTestBase) SetupSuiteWithCluster(clusterConfigFile string, opt
|
||||
if s.testClusterConfig.ESConfig != nil {
|
||||
s.testClusterConfig.DynamicConfigOverrides[dynamicconfig.SecondaryVisibilityWritingMode.Key()] = visibility.SecondaryVisibilityWritingModeDual
|
||||
}
|
||||
// Enable raw history for functional tests.
|
||||
// TODO (prathyush): remove this after setting it to true by default.
|
||||
s.testClusterConfig.DynamicConfigOverrides[dynamicconfig.SendRawHistoryBetweenInternalServices.Key()] = true
|
||||
|
||||
s.testClusterConfig.ServiceFxOptions = params.ServiceOptions
|
||||
s.testClusterConfig.EnableMetricsCapture = true
|
||||
|
||||
@@ -109,6 +109,8 @@ func (s *xdcBaseSuite) setupSuite(opts ...testcore.TestClusterOption) {
|
||||
s.dynamicConfigOverrides[dynamicconfig.ClusterMetadataRefreshInterval.Key()] = time.Second * 5
|
||||
s.dynamicConfigOverrides[dynamicconfig.NamespaceCacheRefreshInterval.Key()] = testcore.NamespaceCacheRefreshInterval
|
||||
s.dynamicConfigOverrides[dynamicconfig.EnableTransitionHistory.Key()] = s.enableTransitionHistory
|
||||
// TODO (prathyush): remove this after setting it to true by default.
|
||||
s.dynamicConfigOverrides[dynamicconfig.SendRawHistoryBetweenInternalServices.Key()] = true
|
||||
|
||||
fileName := "../testdata/xdc_clusters.yaml"
|
||||
if testcore.TestFlags.TestClusterConfigFile != "" {
|
||||
|
||||
Reference in New Issue
Block a user