mirror of
https://github.com/temporalio/temporal.git
synced 2026-08-30 18:41:49 -07:00
Dynamic partitioning: scale manager (#10365)
## What changed? Add scale manager component. ## Why? Part of dynamic partitioning. ## How did you test it? - [ ] built - [ ] run locally and tested manually - [ ] covered by existing tests - [x] added new unit test(s) - [x] added new functional test(s) - to come in future PRs ## Potential risks No behavior changes yet.
This commit is contained in:
@@ -5219,6 +5219,7 @@ type DescribeTaskQueuePartitionResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// contains k-v pairs of the type: buildID -> TaskQueueVersionInfoInternal
|
||||
VersionsInfoInternal map[string]*v114.TaskQueueVersionInfoInternal `protobuf:"bytes,1,rep,name=versions_info_internal,json=versionsInfoInternal,proto3" json:"versions_info_internal,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
||||
ScaleInfo *v114.PartitionScaleInfo `protobuf:"bytes,2,opt,name=scale_info,json=scaleInfo,proto3" json:"scale_info,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@@ -5260,6 +5261,13 @@ func (x *DescribeTaskQueuePartitionResponse) GetVersionsInfoInternal() map[strin
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *DescribeTaskQueuePartitionResponse) GetScaleInfo() *v114.PartitionScaleInfo {
|
||||
if x != nil {
|
||||
return x.ScaleInfo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ForceUnloadTaskQueuePartitionRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
|
||||
@@ -6294,9 +6302,11 @@ const file_temporal_server_api_adminservice_v1_request_response_proto_rawDesc =
|
||||
"!DescribeTaskQueuePartitionRequest\x12\x1c\n" +
|
||||
"\tnamespace\x18\x01 \x01(\tR\tnamespace\x12f\n" +
|
||||
"\x14task_queue_partition\x18\x02 \x01(\v24.temporal.server.api.taskqueue.v1.TaskQueuePartitionR\x12taskQueuePartition\x12Q\n" +
|
||||
"\tbuild_ids\x18\x03 \x01(\v24.temporal.api.taskqueue.v1.TaskQueueVersionSelectionR\bbuildIds\"\xc8\x02\n" +
|
||||
"\tbuild_ids\x18\x03 \x01(\v24.temporal.api.taskqueue.v1.TaskQueueVersionSelectionR\bbuildIds\"\x9d\x03\n" +
|
||||
"\"DescribeTaskQueuePartitionResponse\x12\x97\x01\n" +
|
||||
"\x16versions_info_internal\x18\x01 \x03(\v2a.temporal.server.api.adminservice.v1.DescribeTaskQueuePartitionResponse.VersionsInfoInternalEntryR\x14versionsInfoInternal\x1a\x87\x01\n" +
|
||||
"\x16versions_info_internal\x18\x01 \x03(\v2a.temporal.server.api.adminservice.v1.DescribeTaskQueuePartitionResponse.VersionsInfoInternalEntryR\x14versionsInfoInternal\x12S\n" +
|
||||
"\n" +
|
||||
"scale_info\x18\x02 \x01(\v24.temporal.server.api.taskqueue.v1.PartitionScaleInfoR\tscaleInfo\x1a\x87\x01\n" +
|
||||
"\x19VersionsInfoInternalEntry\x12\x10\n" +
|
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12T\n" +
|
||||
"\x05value\x18\x02 \x01(\v2>.temporal.server.api.taskqueue.v1.TaskQueueVersionInfoInternalR\x05value:\x028\x01\"\xac\x01\n" +
|
||||
@@ -6505,9 +6515,10 @@ var file_temporal_server_api_adminservice_v1_request_response_proto_goTypes = []
|
||||
(*v15.VersionedTransitionArtifact)(nil), // 144: temporal.server.api.replication.v1.VersionedTransitionArtifact
|
||||
(*v114.TaskQueuePartition)(nil), // 145: temporal.server.api.taskqueue.v1.TaskQueuePartition
|
||||
(*v115.TaskQueueVersionSelection)(nil), // 146: temporal.api.taskqueue.v1.TaskQueueVersionSelection
|
||||
(*v12.TaskQueueTypeUserData)(nil), // 147: temporal.server.api.persistence.v1.TaskQueueTypeUserData
|
||||
(v16.IndexedValueType)(0), // 148: temporal.api.enums.v1.IndexedValueType
|
||||
(*v114.TaskQueueVersionInfoInternal)(nil), // 149: temporal.server.api.taskqueue.v1.TaskQueueVersionInfoInternal
|
||||
(*v114.PartitionScaleInfo)(nil), // 147: temporal.server.api.taskqueue.v1.PartitionScaleInfo
|
||||
(*v12.TaskQueueTypeUserData)(nil), // 148: temporal.server.api.persistence.v1.TaskQueueTypeUserData
|
||||
(v16.IndexedValueType)(0), // 149: temporal.api.enums.v1.IndexedValueType
|
||||
(*v114.TaskQueueVersionInfoInternal)(nil), // 150: temporal.server.api.taskqueue.v1.TaskQueueVersionInfoInternal
|
||||
}
|
||||
var file_temporal_server_api_adminservice_v1_request_response_proto_depIdxs = []int32{
|
||||
106, // 0: temporal.server.api.adminservice.v1.RebuildMutableStateRequest.execution:type_name -> temporal.api.common.v1.WorkflowExecution
|
||||
@@ -6591,23 +6602,24 @@ var file_temporal_server_api_adminservice_v1_request_response_proto_depIdxs = []
|
||||
145, // 78: temporal.server.api.adminservice.v1.DescribeTaskQueuePartitionRequest.task_queue_partition:type_name -> temporal.server.api.taskqueue.v1.TaskQueuePartition
|
||||
146, // 79: temporal.server.api.adminservice.v1.DescribeTaskQueuePartitionRequest.build_ids:type_name -> temporal.api.taskqueue.v1.TaskQueueVersionSelection
|
||||
105, // 80: temporal.server.api.adminservice.v1.DescribeTaskQueuePartitionResponse.versions_info_internal:type_name -> temporal.server.api.adminservice.v1.DescribeTaskQueuePartitionResponse.VersionsInfoInternalEntry
|
||||
145, // 81: temporal.server.api.adminservice.v1.ForceUnloadTaskQueuePartitionRequest.task_queue_partition:type_name -> temporal.server.api.taskqueue.v1.TaskQueuePartition
|
||||
127, // 82: temporal.server.api.adminservice.v1.GetTaskQueueUserDataRequest.task_queue_type:type_name -> temporal.api.enums.v1.TaskQueueType
|
||||
147, // 83: temporal.server.api.adminservice.v1.GetTaskQueueUserDataResponse.user_data:type_name -> temporal.server.api.persistence.v1.TaskQueueTypeUserData
|
||||
106, // 84: temporal.server.api.adminservice.v1.StartAdminBatchOperationRequest.executions:type_name -> temporal.api.common.v1.WorkflowExecution
|
||||
93, // 85: temporal.server.api.adminservice.v1.StartAdminBatchOperationRequest.refresh_tasks_operation:type_name -> temporal.server.api.adminservice.v1.BatchOperationRefreshTasks
|
||||
0, // 86: temporal.server.api.adminservice.v1.MigrateScheduleRequest.target:type_name -> temporal.server.api.adminservice.v1.MigrateScheduleRequest.SchedulerTarget
|
||||
116, // 87: temporal.server.api.adminservice.v1.GetReplicationMessagesResponse.ShardMessagesEntry.value:type_name -> temporal.server.api.replication.v1.ReplicationMessages
|
||||
148, // 88: temporal.server.api.adminservice.v1.AddSearchAttributesRequest.SearchAttributesEntry.value:type_name -> temporal.api.enums.v1.IndexedValueType
|
||||
148, // 89: temporal.server.api.adminservice.v1.GetSearchAttributesResponse.CustomAttributesEntry.value:type_name -> temporal.api.enums.v1.IndexedValueType
|
||||
148, // 90: temporal.server.api.adminservice.v1.GetSearchAttributesResponse.SystemAttributesEntry.value:type_name -> temporal.api.enums.v1.IndexedValueType
|
||||
107, // 91: temporal.server.api.adminservice.v1.AddTasksRequest.Task.blob:type_name -> temporal.api.common.v1.DataBlob
|
||||
149, // 92: temporal.server.api.adminservice.v1.DescribeTaskQueuePartitionResponse.VersionsInfoInternalEntry.value:type_name -> temporal.server.api.taskqueue.v1.TaskQueueVersionInfoInternal
|
||||
93, // [93:93] is the sub-list for method output_type
|
||||
93, // [93:93] is the sub-list for method input_type
|
||||
93, // [93:93] is the sub-list for extension type_name
|
||||
93, // [93:93] is the sub-list for extension extendee
|
||||
0, // [0:93] is the sub-list for field type_name
|
||||
147, // 81: temporal.server.api.adminservice.v1.DescribeTaskQueuePartitionResponse.scale_info:type_name -> temporal.server.api.taskqueue.v1.PartitionScaleInfo
|
||||
145, // 82: temporal.server.api.adminservice.v1.ForceUnloadTaskQueuePartitionRequest.task_queue_partition:type_name -> temporal.server.api.taskqueue.v1.TaskQueuePartition
|
||||
127, // 83: temporal.server.api.adminservice.v1.GetTaskQueueUserDataRequest.task_queue_type:type_name -> temporal.api.enums.v1.TaskQueueType
|
||||
148, // 84: temporal.server.api.adminservice.v1.GetTaskQueueUserDataResponse.user_data:type_name -> temporal.server.api.persistence.v1.TaskQueueTypeUserData
|
||||
106, // 85: temporal.server.api.adminservice.v1.StartAdminBatchOperationRequest.executions:type_name -> temporal.api.common.v1.WorkflowExecution
|
||||
93, // 86: temporal.server.api.adminservice.v1.StartAdminBatchOperationRequest.refresh_tasks_operation:type_name -> temporal.server.api.adminservice.v1.BatchOperationRefreshTasks
|
||||
0, // 87: temporal.server.api.adminservice.v1.MigrateScheduleRequest.target:type_name -> temporal.server.api.adminservice.v1.MigrateScheduleRequest.SchedulerTarget
|
||||
116, // 88: temporal.server.api.adminservice.v1.GetReplicationMessagesResponse.ShardMessagesEntry.value:type_name -> temporal.server.api.replication.v1.ReplicationMessages
|
||||
149, // 89: temporal.server.api.adminservice.v1.AddSearchAttributesRequest.SearchAttributesEntry.value:type_name -> temporal.api.enums.v1.IndexedValueType
|
||||
149, // 90: temporal.server.api.adminservice.v1.GetSearchAttributesResponse.CustomAttributesEntry.value:type_name -> temporal.api.enums.v1.IndexedValueType
|
||||
149, // 91: temporal.server.api.adminservice.v1.GetSearchAttributesResponse.SystemAttributesEntry.value:type_name -> temporal.api.enums.v1.IndexedValueType
|
||||
107, // 92: temporal.server.api.adminservice.v1.AddTasksRequest.Task.blob:type_name -> temporal.api.common.v1.DataBlob
|
||||
150, // 93: temporal.server.api.adminservice.v1.DescribeTaskQueuePartitionResponse.VersionsInfoInternalEntry.value:type_name -> temporal.server.api.taskqueue.v1.TaskQueueVersionInfoInternal
|
||||
94, // [94:94] is the sub-list for method output_type
|
||||
94, // [94:94] is the sub-list for method input_type
|
||||
94, // [94:94] is the sub-list for extension type_name
|
||||
94, // [94:94] is the sub-list for extension extendee
|
||||
0, // [0:94] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_temporal_server_api_adminservice_v1_request_response_proto_init() }
|
||||
|
||||
@@ -1969,6 +1969,7 @@ func (x *DescribeTaskQueuePartitionRequest) GetReportInternalTaskQueueStatus() b
|
||||
type DescribeTaskQueuePartitionResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
VersionsInfoInternal map[string]*v18.TaskQueueVersionInfoInternal `protobuf:"bytes,1,rep,name=versions_info_internal,json=versionsInfoInternal,proto3" json:"versions_info_internal,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
||||
ScaleInfo *v18.PartitionScaleInfo `protobuf:"bytes,2,opt,name=scale_info,json=scaleInfo,proto3" json:"scale_info,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@@ -2010,6 +2011,13 @@ func (x *DescribeTaskQueuePartitionResponse) GetVersionsInfoInternal() map[strin
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *DescribeTaskQueuePartitionResponse) GetScaleInfo() *v18.PartitionScaleInfo {
|
||||
if x != nil {
|
||||
return x.ScaleInfo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ListTaskQueuePartitionsRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
|
||||
@@ -5965,9 +5973,11 @@ const file_temporal_server_api_matchingservice_v1_request_response_proto_rawDesc
|
||||
"\bversions\x18\x03 \x01(\v24.temporal.api.taskqueue.v1.TaskQueueVersionSelectionR\bversions\x12!\n" +
|
||||
"\freport_stats\x18\x04 \x01(\bR\vreportStats\x12%\n" +
|
||||
"\x0ereport_pollers\x18\x05 \x01(\bR\rreportPollers\x12H\n" +
|
||||
"!report_internal_task_queue_status\x18\x06 \x01(\bR\x1dreportInternalTaskQueueStatus\"\xcb\x02\n" +
|
||||
"!report_internal_task_queue_status\x18\x06 \x01(\bR\x1dreportInternalTaskQueueStatus\"\xa0\x03\n" +
|
||||
"\"DescribeTaskQueuePartitionResponse\x12\x9a\x01\n" +
|
||||
"\x16versions_info_internal\x18\x01 \x03(\v2d.temporal.server.api.matchingservice.v1.DescribeTaskQueuePartitionResponse.VersionsInfoInternalEntryR\x14versionsInfoInternal\x1a\x87\x01\n" +
|
||||
"\x16versions_info_internal\x18\x01 \x03(\v2d.temporal.server.api.matchingservice.v1.DescribeTaskQueuePartitionResponse.VersionsInfoInternalEntryR\x14versionsInfoInternal\x12S\n" +
|
||||
"\n" +
|
||||
"scale_info\x18\x02 \x01(\v24.temporal.server.api.taskqueue.v1.PartitionScaleInfoR\tscaleInfo\x1a\x87\x01\n" +
|
||||
"\x19VersionsInfoInternalEntry\x12\x10\n" +
|
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12T\n" +
|
||||
"\x05value\x18\x02 \x01(\v2>.temporal.server.api.taskqueue.v1.TaskQueueVersionInfoInternalR\x05value:\x028\x01\"\xa6\x01\n" +
|
||||
@@ -6333,40 +6343,41 @@ var file_temporal_server_api_matchingservice_v1_request_response_proto_goTypes =
|
||||
(*v1.DescribeTaskQueueResponse)(nil), // 118: temporal.api.workflowservice.v1.DescribeTaskQueueResponse
|
||||
(*v18.TaskQueuePartition)(nil), // 119: temporal.server.api.taskqueue.v1.TaskQueuePartition
|
||||
(*v14.TaskQueueVersionSelection)(nil), // 120: temporal.api.taskqueue.v1.TaskQueueVersionSelection
|
||||
(*v14.TaskQueuePartitionMetadata)(nil), // 121: temporal.api.taskqueue.v1.TaskQueuePartitionMetadata
|
||||
(*v1.GetWorkerVersioningRulesRequest)(nil), // 122: temporal.api.workflowservice.v1.GetWorkerVersioningRulesRequest
|
||||
(*v1.GetWorkerVersioningRulesResponse)(nil), // 123: temporal.api.workflowservice.v1.GetWorkerVersioningRulesResponse
|
||||
(*v1.UpdateWorkerVersioningRulesRequest)(nil), // 124: temporal.api.workflowservice.v1.UpdateWorkerVersioningRulesRequest
|
||||
(*v1.UpdateWorkerVersioningRulesResponse)(nil), // 125: temporal.api.workflowservice.v1.UpdateWorkerVersioningRulesResponse
|
||||
(*v1.GetWorkerBuildIdCompatibilityRequest)(nil), // 126: temporal.api.workflowservice.v1.GetWorkerBuildIdCompatibilityRequest
|
||||
(*v1.GetWorkerBuildIdCompatibilityResponse)(nil), // 127: temporal.api.workflowservice.v1.GetWorkerBuildIdCompatibilityResponse
|
||||
(*v111.VersionedTaskQueueUserData)(nil), // 128: temporal.server.api.persistence.v1.VersionedTaskQueueUserData
|
||||
(*v18.VersionedEphemeralData)(nil), // 129: temporal.server.api.taskqueue.v1.VersionedEphemeralData
|
||||
(*v110.DeploymentVersionData)(nil), // 130: temporal.server.api.deployment.v1.DeploymentVersionData
|
||||
(*v112.RoutingConfig)(nil), // 131: temporal.api.deployment.v1.RoutingConfig
|
||||
(*v111.TaskQueueUserData)(nil), // 132: temporal.server.api.persistence.v1.TaskQueueUserData
|
||||
(*v113.Request)(nil), // 133: temporal.api.nexus.v1.Request
|
||||
(*v113.HandlerError)(nil), // 134: temporal.api.nexus.v1.HandlerError
|
||||
(*v113.Response)(nil), // 135: temporal.api.nexus.v1.Response
|
||||
(*v114.Failure)(nil), // 136: temporal.api.failure.v1.Failure
|
||||
(*v1.PollNexusTaskQueueRequest)(nil), // 137: temporal.api.workflowservice.v1.PollNexusTaskQueueRequest
|
||||
(*v1.PollNexusTaskQueueResponse)(nil), // 138: temporal.api.workflowservice.v1.PollNexusTaskQueueResponse
|
||||
(*v1.RespondNexusTaskCompletedRequest)(nil), // 139: temporal.api.workflowservice.v1.RespondNexusTaskCompletedRequest
|
||||
(*v1.RespondNexusTaskFailedRequest)(nil), // 140: temporal.api.workflowservice.v1.RespondNexusTaskFailedRequest
|
||||
(*v111.NexusEndpointSpec)(nil), // 141: temporal.server.api.persistence.v1.NexusEndpointSpec
|
||||
(*v111.NexusEndpointEntry)(nil), // 142: temporal.server.api.persistence.v1.NexusEndpointEntry
|
||||
(*v1.RecordWorkerHeartbeatRequest)(nil), // 143: temporal.api.workflowservice.v1.RecordWorkerHeartbeatRequest
|
||||
(*v1.ListWorkersRequest)(nil), // 144: temporal.api.workflowservice.v1.ListWorkersRequest
|
||||
(*v115.WorkerInfo)(nil), // 145: temporal.api.worker.v1.WorkerInfo
|
||||
(*v115.WorkerListInfo)(nil), // 146: temporal.api.worker.v1.WorkerListInfo
|
||||
(*v1.UpdateTaskQueueConfigRequest)(nil), // 147: temporal.api.workflowservice.v1.UpdateTaskQueueConfigRequest
|
||||
(*v14.TaskQueueConfig)(nil), // 148: temporal.api.taskqueue.v1.TaskQueueConfig
|
||||
(*v1.DescribeWorkerRequest)(nil), // 149: temporal.api.workflowservice.v1.DescribeWorkerRequest
|
||||
(v116.FairnessState)(0), // 150: temporal.server.api.enums.v1.FairnessState
|
||||
(*v14.TaskQueueStats)(nil), // 151: temporal.api.taskqueue.v1.TaskQueueStats
|
||||
(*v18.TaskQueueVersionInfoInternal)(nil), // 152: temporal.server.api.taskqueue.v1.TaskQueueVersionInfoInternal
|
||||
(*v1.UpdateWorkerBuildIdCompatibilityRequest)(nil), // 153: temporal.api.workflowservice.v1.UpdateWorkerBuildIdCompatibilityRequest
|
||||
(*v110.WorkerDeploymentVersionData)(nil), // 154: temporal.server.api.deployment.v1.WorkerDeploymentVersionData
|
||||
(*v18.PartitionScaleInfo)(nil), // 121: temporal.server.api.taskqueue.v1.PartitionScaleInfo
|
||||
(*v14.TaskQueuePartitionMetadata)(nil), // 122: temporal.api.taskqueue.v1.TaskQueuePartitionMetadata
|
||||
(*v1.GetWorkerVersioningRulesRequest)(nil), // 123: temporal.api.workflowservice.v1.GetWorkerVersioningRulesRequest
|
||||
(*v1.GetWorkerVersioningRulesResponse)(nil), // 124: temporal.api.workflowservice.v1.GetWorkerVersioningRulesResponse
|
||||
(*v1.UpdateWorkerVersioningRulesRequest)(nil), // 125: temporal.api.workflowservice.v1.UpdateWorkerVersioningRulesRequest
|
||||
(*v1.UpdateWorkerVersioningRulesResponse)(nil), // 126: temporal.api.workflowservice.v1.UpdateWorkerVersioningRulesResponse
|
||||
(*v1.GetWorkerBuildIdCompatibilityRequest)(nil), // 127: temporal.api.workflowservice.v1.GetWorkerBuildIdCompatibilityRequest
|
||||
(*v1.GetWorkerBuildIdCompatibilityResponse)(nil), // 128: temporal.api.workflowservice.v1.GetWorkerBuildIdCompatibilityResponse
|
||||
(*v111.VersionedTaskQueueUserData)(nil), // 129: temporal.server.api.persistence.v1.VersionedTaskQueueUserData
|
||||
(*v18.VersionedEphemeralData)(nil), // 130: temporal.server.api.taskqueue.v1.VersionedEphemeralData
|
||||
(*v110.DeploymentVersionData)(nil), // 131: temporal.server.api.deployment.v1.DeploymentVersionData
|
||||
(*v112.RoutingConfig)(nil), // 132: temporal.api.deployment.v1.RoutingConfig
|
||||
(*v111.TaskQueueUserData)(nil), // 133: temporal.server.api.persistence.v1.TaskQueueUserData
|
||||
(*v113.Request)(nil), // 134: temporal.api.nexus.v1.Request
|
||||
(*v113.HandlerError)(nil), // 135: temporal.api.nexus.v1.HandlerError
|
||||
(*v113.Response)(nil), // 136: temporal.api.nexus.v1.Response
|
||||
(*v114.Failure)(nil), // 137: temporal.api.failure.v1.Failure
|
||||
(*v1.PollNexusTaskQueueRequest)(nil), // 138: temporal.api.workflowservice.v1.PollNexusTaskQueueRequest
|
||||
(*v1.PollNexusTaskQueueResponse)(nil), // 139: temporal.api.workflowservice.v1.PollNexusTaskQueueResponse
|
||||
(*v1.RespondNexusTaskCompletedRequest)(nil), // 140: temporal.api.workflowservice.v1.RespondNexusTaskCompletedRequest
|
||||
(*v1.RespondNexusTaskFailedRequest)(nil), // 141: temporal.api.workflowservice.v1.RespondNexusTaskFailedRequest
|
||||
(*v111.NexusEndpointSpec)(nil), // 142: temporal.server.api.persistence.v1.NexusEndpointSpec
|
||||
(*v111.NexusEndpointEntry)(nil), // 143: temporal.server.api.persistence.v1.NexusEndpointEntry
|
||||
(*v1.RecordWorkerHeartbeatRequest)(nil), // 144: temporal.api.workflowservice.v1.RecordWorkerHeartbeatRequest
|
||||
(*v1.ListWorkersRequest)(nil), // 145: temporal.api.workflowservice.v1.ListWorkersRequest
|
||||
(*v115.WorkerInfo)(nil), // 146: temporal.api.worker.v1.WorkerInfo
|
||||
(*v115.WorkerListInfo)(nil), // 147: temporal.api.worker.v1.WorkerListInfo
|
||||
(*v1.UpdateTaskQueueConfigRequest)(nil), // 148: temporal.api.workflowservice.v1.UpdateTaskQueueConfigRequest
|
||||
(*v14.TaskQueueConfig)(nil), // 149: temporal.api.taskqueue.v1.TaskQueueConfig
|
||||
(*v1.DescribeWorkerRequest)(nil), // 150: temporal.api.workflowservice.v1.DescribeWorkerRequest
|
||||
(v116.FairnessState)(0), // 151: temporal.server.api.enums.v1.FairnessState
|
||||
(*v14.TaskQueueStats)(nil), // 152: temporal.api.taskqueue.v1.TaskQueueStats
|
||||
(*v18.TaskQueueVersionInfoInternal)(nil), // 153: temporal.server.api.taskqueue.v1.TaskQueueVersionInfoInternal
|
||||
(*v1.UpdateWorkerBuildIdCompatibilityRequest)(nil), // 154: temporal.api.workflowservice.v1.UpdateWorkerBuildIdCompatibilityRequest
|
||||
(*v110.WorkerDeploymentVersionData)(nil), // 155: temporal.server.api.deployment.v1.WorkerDeploymentVersionData
|
||||
}
|
||||
var file_temporal_server_api_matchingservice_v1_request_response_proto_depIdxs = []int32{
|
||||
92, // 0: temporal.server.api.matchingservice.v1.PollWorkflowTaskQueueRequest.poll_request:type_name -> temporal.api.workflowservice.v1.PollWorkflowTaskQueueRequest
|
||||
@@ -6449,77 +6460,78 @@ var file_temporal_server_api_matchingservice_v1_request_response_proto_depIdxs =
|
||||
119, // 77: temporal.server.api.matchingservice.v1.DescribeTaskQueuePartitionRequest.task_queue_partition:type_name -> temporal.server.api.taskqueue.v1.TaskQueuePartition
|
||||
120, // 78: temporal.server.api.matchingservice.v1.DescribeTaskQueuePartitionRequest.versions:type_name -> temporal.api.taskqueue.v1.TaskQueueVersionSelection
|
||||
87, // 79: temporal.server.api.matchingservice.v1.DescribeTaskQueuePartitionResponse.versions_info_internal:type_name -> temporal.server.api.matchingservice.v1.DescribeTaskQueuePartitionResponse.VersionsInfoInternalEntry
|
||||
97, // 80: temporal.server.api.matchingservice.v1.ListTaskQueuePartitionsRequest.task_queue:type_name -> temporal.api.taskqueue.v1.TaskQueue
|
||||
121, // 81: temporal.server.api.matchingservice.v1.ListTaskQueuePartitionsResponse.activity_task_queue_partitions:type_name -> temporal.api.taskqueue.v1.TaskQueuePartitionMetadata
|
||||
121, // 82: temporal.server.api.matchingservice.v1.ListTaskQueuePartitionsResponse.workflow_task_queue_partitions:type_name -> temporal.api.taskqueue.v1.TaskQueuePartitionMetadata
|
||||
88, // 83: temporal.server.api.matchingservice.v1.UpdateWorkerBuildIdCompatibilityRequest.apply_public_request:type_name -> temporal.server.api.matchingservice.v1.UpdateWorkerBuildIdCompatibilityRequest.ApplyPublicRequest
|
||||
89, // 84: temporal.server.api.matchingservice.v1.UpdateWorkerBuildIdCompatibilityRequest.remove_build_ids:type_name -> temporal.server.api.matchingservice.v1.UpdateWorkerBuildIdCompatibilityRequest.RemoveBuildIds
|
||||
122, // 85: temporal.server.api.matchingservice.v1.GetWorkerVersioningRulesRequest.request:type_name -> temporal.api.workflowservice.v1.GetWorkerVersioningRulesRequest
|
||||
123, // 86: temporal.server.api.matchingservice.v1.GetWorkerVersioningRulesResponse.response:type_name -> temporal.api.workflowservice.v1.GetWorkerVersioningRulesResponse
|
||||
124, // 87: temporal.server.api.matchingservice.v1.UpdateWorkerVersioningRulesRequest.request:type_name -> temporal.api.workflowservice.v1.UpdateWorkerVersioningRulesRequest
|
||||
125, // 88: temporal.server.api.matchingservice.v1.UpdateWorkerVersioningRulesResponse.response:type_name -> temporal.api.workflowservice.v1.UpdateWorkerVersioningRulesResponse
|
||||
126, // 89: temporal.server.api.matchingservice.v1.GetWorkerBuildIdCompatibilityRequest.request:type_name -> temporal.api.workflowservice.v1.GetWorkerBuildIdCompatibilityRequest
|
||||
127, // 90: temporal.server.api.matchingservice.v1.GetWorkerBuildIdCompatibilityResponse.response:type_name -> temporal.api.workflowservice.v1.GetWorkerBuildIdCompatibilityResponse
|
||||
115, // 91: temporal.server.api.matchingservice.v1.GetTaskQueueUserDataRequest.task_queue_type:type_name -> temporal.api.enums.v1.TaskQueueType
|
||||
128, // 92: temporal.server.api.matchingservice.v1.GetTaskQueueUserDataResponse.user_data:type_name -> temporal.server.api.persistence.v1.VersionedTaskQueueUserData
|
||||
129, // 93: temporal.server.api.matchingservice.v1.GetTaskQueueUserDataResponse.ephemeral_data:type_name -> temporal.server.api.taskqueue.v1.VersionedEphemeralData
|
||||
115, // 94: temporal.server.api.matchingservice.v1.SyncDeploymentUserDataRequest.task_queue_types:type_name -> temporal.api.enums.v1.TaskQueueType
|
||||
130, // 95: temporal.server.api.matchingservice.v1.SyncDeploymentUserDataRequest.update_version_data:type_name -> temporal.server.api.deployment.v1.DeploymentVersionData
|
||||
117, // 96: temporal.server.api.matchingservice.v1.SyncDeploymentUserDataRequest.forget_version:type_name -> temporal.server.api.deployment.v1.WorkerDeploymentVersion
|
||||
131, // 97: temporal.server.api.matchingservice.v1.SyncDeploymentUserDataRequest.update_routing_config:type_name -> temporal.api.deployment.v1.RoutingConfig
|
||||
90, // 98: temporal.server.api.matchingservice.v1.SyncDeploymentUserDataRequest.upsert_versions_data:type_name -> temporal.server.api.matchingservice.v1.SyncDeploymentUserDataRequest.UpsertVersionsDataEntry
|
||||
132, // 99: temporal.server.api.matchingservice.v1.ApplyTaskQueueUserDataReplicationEventRequest.user_data:type_name -> temporal.server.api.persistence.v1.TaskQueueUserData
|
||||
119, // 100: temporal.server.api.matchingservice.v1.ForceLoadTaskQueuePartitionRequest.task_queue_partition:type_name -> temporal.server.api.taskqueue.v1.TaskQueuePartition
|
||||
115, // 101: temporal.server.api.matchingservice.v1.ForceUnloadTaskQueueRequest.task_queue_type:type_name -> temporal.api.enums.v1.TaskQueueType
|
||||
119, // 102: temporal.server.api.matchingservice.v1.ForceUnloadTaskQueuePartitionRequest.task_queue_partition:type_name -> temporal.server.api.taskqueue.v1.TaskQueuePartition
|
||||
128, // 103: temporal.server.api.matchingservice.v1.UpdateTaskQueueUserDataRequest.user_data:type_name -> temporal.server.api.persistence.v1.VersionedTaskQueueUserData
|
||||
132, // 104: temporal.server.api.matchingservice.v1.ReplicateTaskQueueUserDataRequest.user_data:type_name -> temporal.server.api.persistence.v1.TaskQueueUserData
|
||||
97, // 105: temporal.server.api.matchingservice.v1.DispatchNexusTaskRequest.task_queue:type_name -> temporal.api.taskqueue.v1.TaskQueue
|
||||
133, // 106: temporal.server.api.matchingservice.v1.DispatchNexusTaskRequest.request:type_name -> temporal.api.nexus.v1.Request
|
||||
111, // 107: temporal.server.api.matchingservice.v1.DispatchNexusTaskRequest.forward_info:type_name -> temporal.server.api.taskqueue.v1.TaskForwardInfo
|
||||
134, // 108: temporal.server.api.matchingservice.v1.DispatchNexusTaskResponse.handler_error:type_name -> temporal.api.nexus.v1.HandlerError
|
||||
135, // 109: temporal.server.api.matchingservice.v1.DispatchNexusTaskResponse.response:type_name -> temporal.api.nexus.v1.Response
|
||||
91, // 110: temporal.server.api.matchingservice.v1.DispatchNexusTaskResponse.request_timeout:type_name -> temporal.server.api.matchingservice.v1.DispatchNexusTaskResponse.Timeout
|
||||
136, // 111: temporal.server.api.matchingservice.v1.DispatchNexusTaskResponse.failure:type_name -> temporal.api.failure.v1.Failure
|
||||
137, // 112: temporal.server.api.matchingservice.v1.PollNexusTaskQueueRequest.request:type_name -> temporal.api.workflowservice.v1.PollNexusTaskQueueRequest
|
||||
81, // 113: temporal.server.api.matchingservice.v1.PollNexusTaskQueueRequest.conditions:type_name -> temporal.server.api.matchingservice.v1.PollConditions
|
||||
138, // 114: temporal.server.api.matchingservice.v1.PollNexusTaskQueueResponse.response:type_name -> temporal.api.workflowservice.v1.PollNexusTaskQueueResponse
|
||||
97, // 115: temporal.server.api.matchingservice.v1.RespondNexusTaskCompletedRequest.task_queue:type_name -> temporal.api.taskqueue.v1.TaskQueue
|
||||
139, // 116: temporal.server.api.matchingservice.v1.RespondNexusTaskCompletedRequest.request:type_name -> temporal.api.workflowservice.v1.RespondNexusTaskCompletedRequest
|
||||
97, // 117: temporal.server.api.matchingservice.v1.RespondNexusTaskFailedRequest.task_queue:type_name -> temporal.api.taskqueue.v1.TaskQueue
|
||||
140, // 118: temporal.server.api.matchingservice.v1.RespondNexusTaskFailedRequest.request:type_name -> temporal.api.workflowservice.v1.RespondNexusTaskFailedRequest
|
||||
141, // 119: temporal.server.api.matchingservice.v1.CreateNexusEndpointRequest.spec:type_name -> temporal.server.api.persistence.v1.NexusEndpointSpec
|
||||
142, // 120: temporal.server.api.matchingservice.v1.CreateNexusEndpointResponse.entry:type_name -> temporal.server.api.persistence.v1.NexusEndpointEntry
|
||||
141, // 121: temporal.server.api.matchingservice.v1.UpdateNexusEndpointRequest.spec:type_name -> temporal.server.api.persistence.v1.NexusEndpointSpec
|
||||
142, // 122: temporal.server.api.matchingservice.v1.UpdateNexusEndpointResponse.entry:type_name -> temporal.server.api.persistence.v1.NexusEndpointEntry
|
||||
142, // 123: temporal.server.api.matchingservice.v1.ListNexusEndpointsResponse.entries:type_name -> temporal.server.api.persistence.v1.NexusEndpointEntry
|
||||
143, // 124: temporal.server.api.matchingservice.v1.RecordWorkerHeartbeatRequest.heartbeart_request:type_name -> temporal.api.workflowservice.v1.RecordWorkerHeartbeatRequest
|
||||
144, // 125: temporal.server.api.matchingservice.v1.ListWorkersRequest.list_request:type_name -> temporal.api.workflowservice.v1.ListWorkersRequest
|
||||
145, // 126: temporal.server.api.matchingservice.v1.ListWorkersResponse.workers_info:type_name -> temporal.api.worker.v1.WorkerInfo
|
||||
146, // 127: temporal.server.api.matchingservice.v1.ListWorkersResponse.workers:type_name -> temporal.api.worker.v1.WorkerListInfo
|
||||
147, // 128: temporal.server.api.matchingservice.v1.UpdateTaskQueueConfigRequest.update_taskqueue_config:type_name -> temporal.api.workflowservice.v1.UpdateTaskQueueConfigRequest
|
||||
148, // 129: temporal.server.api.matchingservice.v1.UpdateTaskQueueConfigResponse.updated_taskqueue_config:type_name -> temporal.api.taskqueue.v1.TaskQueueConfig
|
||||
149, // 130: temporal.server.api.matchingservice.v1.DescribeWorkerRequest.request:type_name -> temporal.api.workflowservice.v1.DescribeWorkerRequest
|
||||
145, // 131: temporal.server.api.matchingservice.v1.DescribeWorkerResponse.worker_info:type_name -> temporal.api.worker.v1.WorkerInfo
|
||||
115, // 132: temporal.server.api.matchingservice.v1.UpdateFairnessStateRequest.task_queue_type:type_name -> temporal.api.enums.v1.TaskQueueType
|
||||
150, // 133: temporal.server.api.matchingservice.v1.UpdateFairnessStateRequest.fairness_state:type_name -> temporal.server.api.enums.v1.FairnessState
|
||||
115, // 134: temporal.server.api.matchingservice.v1.CheckTaskQueueVersionMembershipRequest.task_queue_type:type_name -> temporal.api.enums.v1.TaskQueueType
|
||||
117, // 135: temporal.server.api.matchingservice.v1.CheckTaskQueueVersionMembershipRequest.version:type_name -> temporal.server.api.deployment.v1.WorkerDeploymentVersion
|
||||
95, // 136: temporal.server.api.matchingservice.v1.PollWorkflowTaskQueueResponse.QueriesEntry.value:type_name -> temporal.api.query.v1.WorkflowQuery
|
||||
95, // 137: temporal.server.api.matchingservice.v1.PollWorkflowTaskQueueResponseWithRawHistory.QueriesEntry.value:type_name -> temporal.api.query.v1.WorkflowQuery
|
||||
115, // 138: temporal.server.api.matchingservice.v1.DescribeVersionedTaskQueuesRequest.VersionTaskQueue.type:type_name -> temporal.api.enums.v1.TaskQueueType
|
||||
115, // 139: temporal.server.api.matchingservice.v1.DescribeVersionedTaskQueuesResponse.VersionTaskQueue.type:type_name -> temporal.api.enums.v1.TaskQueueType
|
||||
151, // 140: temporal.server.api.matchingservice.v1.DescribeVersionedTaskQueuesResponse.VersionTaskQueue.stats:type_name -> temporal.api.taskqueue.v1.TaskQueueStats
|
||||
86, // 141: temporal.server.api.matchingservice.v1.DescribeVersionedTaskQueuesResponse.VersionTaskQueue.stats_by_priority_key:type_name -> temporal.server.api.matchingservice.v1.DescribeVersionedTaskQueuesResponse.VersionTaskQueue.StatsByPriorityKeyEntry
|
||||
151, // 142: temporal.server.api.matchingservice.v1.DescribeVersionedTaskQueuesResponse.VersionTaskQueue.StatsByPriorityKeyEntry.value:type_name -> temporal.api.taskqueue.v1.TaskQueueStats
|
||||
152, // 143: temporal.server.api.matchingservice.v1.DescribeTaskQueuePartitionResponse.VersionsInfoInternalEntry.value:type_name -> temporal.server.api.taskqueue.v1.TaskQueueVersionInfoInternal
|
||||
153, // 144: temporal.server.api.matchingservice.v1.UpdateWorkerBuildIdCompatibilityRequest.ApplyPublicRequest.request:type_name -> temporal.api.workflowservice.v1.UpdateWorkerBuildIdCompatibilityRequest
|
||||
154, // 145: temporal.server.api.matchingservice.v1.SyncDeploymentUserDataRequest.UpsertVersionsDataEntry.value:type_name -> temporal.server.api.deployment.v1.WorkerDeploymentVersionData
|
||||
146, // [146:146] is the sub-list for method output_type
|
||||
146, // [146:146] is the sub-list for method input_type
|
||||
146, // [146:146] is the sub-list for extension type_name
|
||||
146, // [146:146] is the sub-list for extension extendee
|
||||
0, // [0:146] is the sub-list for field type_name
|
||||
121, // 80: temporal.server.api.matchingservice.v1.DescribeTaskQueuePartitionResponse.scale_info:type_name -> temporal.server.api.taskqueue.v1.PartitionScaleInfo
|
||||
97, // 81: temporal.server.api.matchingservice.v1.ListTaskQueuePartitionsRequest.task_queue:type_name -> temporal.api.taskqueue.v1.TaskQueue
|
||||
122, // 82: temporal.server.api.matchingservice.v1.ListTaskQueuePartitionsResponse.activity_task_queue_partitions:type_name -> temporal.api.taskqueue.v1.TaskQueuePartitionMetadata
|
||||
122, // 83: temporal.server.api.matchingservice.v1.ListTaskQueuePartitionsResponse.workflow_task_queue_partitions:type_name -> temporal.api.taskqueue.v1.TaskQueuePartitionMetadata
|
||||
88, // 84: temporal.server.api.matchingservice.v1.UpdateWorkerBuildIdCompatibilityRequest.apply_public_request:type_name -> temporal.server.api.matchingservice.v1.UpdateWorkerBuildIdCompatibilityRequest.ApplyPublicRequest
|
||||
89, // 85: temporal.server.api.matchingservice.v1.UpdateWorkerBuildIdCompatibilityRequest.remove_build_ids:type_name -> temporal.server.api.matchingservice.v1.UpdateWorkerBuildIdCompatibilityRequest.RemoveBuildIds
|
||||
123, // 86: temporal.server.api.matchingservice.v1.GetWorkerVersioningRulesRequest.request:type_name -> temporal.api.workflowservice.v1.GetWorkerVersioningRulesRequest
|
||||
124, // 87: temporal.server.api.matchingservice.v1.GetWorkerVersioningRulesResponse.response:type_name -> temporal.api.workflowservice.v1.GetWorkerVersioningRulesResponse
|
||||
125, // 88: temporal.server.api.matchingservice.v1.UpdateWorkerVersioningRulesRequest.request:type_name -> temporal.api.workflowservice.v1.UpdateWorkerVersioningRulesRequest
|
||||
126, // 89: temporal.server.api.matchingservice.v1.UpdateWorkerVersioningRulesResponse.response:type_name -> temporal.api.workflowservice.v1.UpdateWorkerVersioningRulesResponse
|
||||
127, // 90: temporal.server.api.matchingservice.v1.GetWorkerBuildIdCompatibilityRequest.request:type_name -> temporal.api.workflowservice.v1.GetWorkerBuildIdCompatibilityRequest
|
||||
128, // 91: temporal.server.api.matchingservice.v1.GetWorkerBuildIdCompatibilityResponse.response:type_name -> temporal.api.workflowservice.v1.GetWorkerBuildIdCompatibilityResponse
|
||||
115, // 92: temporal.server.api.matchingservice.v1.GetTaskQueueUserDataRequest.task_queue_type:type_name -> temporal.api.enums.v1.TaskQueueType
|
||||
129, // 93: temporal.server.api.matchingservice.v1.GetTaskQueueUserDataResponse.user_data:type_name -> temporal.server.api.persistence.v1.VersionedTaskQueueUserData
|
||||
130, // 94: temporal.server.api.matchingservice.v1.GetTaskQueueUserDataResponse.ephemeral_data:type_name -> temporal.server.api.taskqueue.v1.VersionedEphemeralData
|
||||
115, // 95: temporal.server.api.matchingservice.v1.SyncDeploymentUserDataRequest.task_queue_types:type_name -> temporal.api.enums.v1.TaskQueueType
|
||||
131, // 96: temporal.server.api.matchingservice.v1.SyncDeploymentUserDataRequest.update_version_data:type_name -> temporal.server.api.deployment.v1.DeploymentVersionData
|
||||
117, // 97: temporal.server.api.matchingservice.v1.SyncDeploymentUserDataRequest.forget_version:type_name -> temporal.server.api.deployment.v1.WorkerDeploymentVersion
|
||||
132, // 98: temporal.server.api.matchingservice.v1.SyncDeploymentUserDataRequest.update_routing_config:type_name -> temporal.api.deployment.v1.RoutingConfig
|
||||
90, // 99: temporal.server.api.matchingservice.v1.SyncDeploymentUserDataRequest.upsert_versions_data:type_name -> temporal.server.api.matchingservice.v1.SyncDeploymentUserDataRequest.UpsertVersionsDataEntry
|
||||
133, // 100: temporal.server.api.matchingservice.v1.ApplyTaskQueueUserDataReplicationEventRequest.user_data:type_name -> temporal.server.api.persistence.v1.TaskQueueUserData
|
||||
119, // 101: temporal.server.api.matchingservice.v1.ForceLoadTaskQueuePartitionRequest.task_queue_partition:type_name -> temporal.server.api.taskqueue.v1.TaskQueuePartition
|
||||
115, // 102: temporal.server.api.matchingservice.v1.ForceUnloadTaskQueueRequest.task_queue_type:type_name -> temporal.api.enums.v1.TaskQueueType
|
||||
119, // 103: temporal.server.api.matchingservice.v1.ForceUnloadTaskQueuePartitionRequest.task_queue_partition:type_name -> temporal.server.api.taskqueue.v1.TaskQueuePartition
|
||||
129, // 104: temporal.server.api.matchingservice.v1.UpdateTaskQueueUserDataRequest.user_data:type_name -> temporal.server.api.persistence.v1.VersionedTaskQueueUserData
|
||||
133, // 105: temporal.server.api.matchingservice.v1.ReplicateTaskQueueUserDataRequest.user_data:type_name -> temporal.server.api.persistence.v1.TaskQueueUserData
|
||||
97, // 106: temporal.server.api.matchingservice.v1.DispatchNexusTaskRequest.task_queue:type_name -> temporal.api.taskqueue.v1.TaskQueue
|
||||
134, // 107: temporal.server.api.matchingservice.v1.DispatchNexusTaskRequest.request:type_name -> temporal.api.nexus.v1.Request
|
||||
111, // 108: temporal.server.api.matchingservice.v1.DispatchNexusTaskRequest.forward_info:type_name -> temporal.server.api.taskqueue.v1.TaskForwardInfo
|
||||
135, // 109: temporal.server.api.matchingservice.v1.DispatchNexusTaskResponse.handler_error:type_name -> temporal.api.nexus.v1.HandlerError
|
||||
136, // 110: temporal.server.api.matchingservice.v1.DispatchNexusTaskResponse.response:type_name -> temporal.api.nexus.v1.Response
|
||||
91, // 111: temporal.server.api.matchingservice.v1.DispatchNexusTaskResponse.request_timeout:type_name -> temporal.server.api.matchingservice.v1.DispatchNexusTaskResponse.Timeout
|
||||
137, // 112: temporal.server.api.matchingservice.v1.DispatchNexusTaskResponse.failure:type_name -> temporal.api.failure.v1.Failure
|
||||
138, // 113: temporal.server.api.matchingservice.v1.PollNexusTaskQueueRequest.request:type_name -> temporal.api.workflowservice.v1.PollNexusTaskQueueRequest
|
||||
81, // 114: temporal.server.api.matchingservice.v1.PollNexusTaskQueueRequest.conditions:type_name -> temporal.server.api.matchingservice.v1.PollConditions
|
||||
139, // 115: temporal.server.api.matchingservice.v1.PollNexusTaskQueueResponse.response:type_name -> temporal.api.workflowservice.v1.PollNexusTaskQueueResponse
|
||||
97, // 116: temporal.server.api.matchingservice.v1.RespondNexusTaskCompletedRequest.task_queue:type_name -> temporal.api.taskqueue.v1.TaskQueue
|
||||
140, // 117: temporal.server.api.matchingservice.v1.RespondNexusTaskCompletedRequest.request:type_name -> temporal.api.workflowservice.v1.RespondNexusTaskCompletedRequest
|
||||
97, // 118: temporal.server.api.matchingservice.v1.RespondNexusTaskFailedRequest.task_queue:type_name -> temporal.api.taskqueue.v1.TaskQueue
|
||||
141, // 119: temporal.server.api.matchingservice.v1.RespondNexusTaskFailedRequest.request:type_name -> temporal.api.workflowservice.v1.RespondNexusTaskFailedRequest
|
||||
142, // 120: temporal.server.api.matchingservice.v1.CreateNexusEndpointRequest.spec:type_name -> temporal.server.api.persistence.v1.NexusEndpointSpec
|
||||
143, // 121: temporal.server.api.matchingservice.v1.CreateNexusEndpointResponse.entry:type_name -> temporal.server.api.persistence.v1.NexusEndpointEntry
|
||||
142, // 122: temporal.server.api.matchingservice.v1.UpdateNexusEndpointRequest.spec:type_name -> temporal.server.api.persistence.v1.NexusEndpointSpec
|
||||
143, // 123: temporal.server.api.matchingservice.v1.UpdateNexusEndpointResponse.entry:type_name -> temporal.server.api.persistence.v1.NexusEndpointEntry
|
||||
143, // 124: temporal.server.api.matchingservice.v1.ListNexusEndpointsResponse.entries:type_name -> temporal.server.api.persistence.v1.NexusEndpointEntry
|
||||
144, // 125: temporal.server.api.matchingservice.v1.RecordWorkerHeartbeatRequest.heartbeart_request:type_name -> temporal.api.workflowservice.v1.RecordWorkerHeartbeatRequest
|
||||
145, // 126: temporal.server.api.matchingservice.v1.ListWorkersRequest.list_request:type_name -> temporal.api.workflowservice.v1.ListWorkersRequest
|
||||
146, // 127: temporal.server.api.matchingservice.v1.ListWorkersResponse.workers_info:type_name -> temporal.api.worker.v1.WorkerInfo
|
||||
147, // 128: temporal.server.api.matchingservice.v1.ListWorkersResponse.workers:type_name -> temporal.api.worker.v1.WorkerListInfo
|
||||
148, // 129: temporal.server.api.matchingservice.v1.UpdateTaskQueueConfigRequest.update_taskqueue_config:type_name -> temporal.api.workflowservice.v1.UpdateTaskQueueConfigRequest
|
||||
149, // 130: temporal.server.api.matchingservice.v1.UpdateTaskQueueConfigResponse.updated_taskqueue_config:type_name -> temporal.api.taskqueue.v1.TaskQueueConfig
|
||||
150, // 131: temporal.server.api.matchingservice.v1.DescribeWorkerRequest.request:type_name -> temporal.api.workflowservice.v1.DescribeWorkerRequest
|
||||
146, // 132: temporal.server.api.matchingservice.v1.DescribeWorkerResponse.worker_info:type_name -> temporal.api.worker.v1.WorkerInfo
|
||||
115, // 133: temporal.server.api.matchingservice.v1.UpdateFairnessStateRequest.task_queue_type:type_name -> temporal.api.enums.v1.TaskQueueType
|
||||
151, // 134: temporal.server.api.matchingservice.v1.UpdateFairnessStateRequest.fairness_state:type_name -> temporal.server.api.enums.v1.FairnessState
|
||||
115, // 135: temporal.server.api.matchingservice.v1.CheckTaskQueueVersionMembershipRequest.task_queue_type:type_name -> temporal.api.enums.v1.TaskQueueType
|
||||
117, // 136: temporal.server.api.matchingservice.v1.CheckTaskQueueVersionMembershipRequest.version:type_name -> temporal.server.api.deployment.v1.WorkerDeploymentVersion
|
||||
95, // 137: temporal.server.api.matchingservice.v1.PollWorkflowTaskQueueResponse.QueriesEntry.value:type_name -> temporal.api.query.v1.WorkflowQuery
|
||||
95, // 138: temporal.server.api.matchingservice.v1.PollWorkflowTaskQueueResponseWithRawHistory.QueriesEntry.value:type_name -> temporal.api.query.v1.WorkflowQuery
|
||||
115, // 139: temporal.server.api.matchingservice.v1.DescribeVersionedTaskQueuesRequest.VersionTaskQueue.type:type_name -> temporal.api.enums.v1.TaskQueueType
|
||||
115, // 140: temporal.server.api.matchingservice.v1.DescribeVersionedTaskQueuesResponse.VersionTaskQueue.type:type_name -> temporal.api.enums.v1.TaskQueueType
|
||||
152, // 141: temporal.server.api.matchingservice.v1.DescribeVersionedTaskQueuesResponse.VersionTaskQueue.stats:type_name -> temporal.api.taskqueue.v1.TaskQueueStats
|
||||
86, // 142: temporal.server.api.matchingservice.v1.DescribeVersionedTaskQueuesResponse.VersionTaskQueue.stats_by_priority_key:type_name -> temporal.server.api.matchingservice.v1.DescribeVersionedTaskQueuesResponse.VersionTaskQueue.StatsByPriorityKeyEntry
|
||||
152, // 143: temporal.server.api.matchingservice.v1.DescribeVersionedTaskQueuesResponse.VersionTaskQueue.StatsByPriorityKeyEntry.value:type_name -> temporal.api.taskqueue.v1.TaskQueueStats
|
||||
153, // 144: temporal.server.api.matchingservice.v1.DescribeTaskQueuePartitionResponse.VersionsInfoInternalEntry.value:type_name -> temporal.server.api.taskqueue.v1.TaskQueueVersionInfoInternal
|
||||
154, // 145: temporal.server.api.matchingservice.v1.UpdateWorkerBuildIdCompatibilityRequest.ApplyPublicRequest.request:type_name -> temporal.api.workflowservice.v1.UpdateWorkerBuildIdCompatibilityRequest
|
||||
155, // 146: temporal.server.api.matchingservice.v1.SyncDeploymentUserDataRequest.UpsertVersionsDataEntry.value:type_name -> temporal.server.api.deployment.v1.WorkerDeploymentVersionData
|
||||
147, // [147:147] is the sub-list for method output_type
|
||||
147, // [147:147] is the sub-list for method input_type
|
||||
147, // [147:147] is the sub-list for extension type_name
|
||||
147, // [147:147] is the sub-list for extension extendee
|
||||
0, // [0:147] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_temporal_server_api_matchingservice_v1_request_response_proto_init() }
|
||||
|
||||
@@ -5,6 +5,43 @@ import (
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// Marshal an object of type TaskKey to the protobuf v3 wire format
|
||||
func (val *TaskKey) Marshal() ([]byte, error) {
|
||||
return proto.Marshal(val)
|
||||
}
|
||||
|
||||
// Unmarshal an object of type TaskKey from the protobuf v3 wire format
|
||||
func (val *TaskKey) Unmarshal(buf []byte) error {
|
||||
return proto.Unmarshal(buf, val)
|
||||
}
|
||||
|
||||
// Size returns the size of the object, in bytes, once serialized
|
||||
func (val *TaskKey) Size() int {
|
||||
return proto.Size(val)
|
||||
}
|
||||
|
||||
// Equal returns whether two TaskKey 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 *TaskKey) Equal(that interface{}) bool {
|
||||
if that == nil {
|
||||
return this == nil
|
||||
}
|
||||
|
||||
var that1 *TaskKey
|
||||
switch t := that.(type) {
|
||||
case *TaskKey:
|
||||
that1 = t
|
||||
case TaskKey:
|
||||
that1 = &t
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
return proto.Equal(this, that1)
|
||||
}
|
||||
|
||||
// Marshal an object of type QueueState to the protobuf v3 wire format
|
||||
func (val *QueueState) Marshal() ([]byte, error) {
|
||||
return proto.Marshal(val)
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
v1 "go.temporal.io/api/common/v1"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -23,6 +24,58 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type TaskKey struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
FireTime *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=fire_time,json=fireTime,proto3" json:"fire_time,omitempty"`
|
||||
TaskId int64 `protobuf:"varint,2,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TaskKey) Reset() {
|
||||
*x = TaskKey{}
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *TaskKey) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TaskKey) ProtoMessage() {}
|
||||
|
||||
func (x *TaskKey) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TaskKey.ProtoReflect.Descriptor instead.
|
||||
func (*TaskKey) Descriptor() ([]byte, []int) {
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *TaskKey) GetFireTime() *timestamppb.Timestamp {
|
||||
if x != nil {
|
||||
return x.FireTime
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *TaskKey) GetTaskId() int64 {
|
||||
if x != nil {
|
||||
return x.TaskId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type QueueState struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
ReaderStates map[int64]*QueueReaderState `protobuf:"bytes,1,rep,name=reader_states,json=readerStates,proto3" json:"reader_states,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
||||
@@ -33,7 +86,7 @@ type QueueState struct {
|
||||
|
||||
func (x *QueueState) Reset() {
|
||||
*x = QueueState{}
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[0]
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -45,7 +98,7 @@ func (x *QueueState) String() string {
|
||||
func (*QueueState) ProtoMessage() {}
|
||||
|
||||
func (x *QueueState) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[0]
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -58,7 +111,7 @@ func (x *QueueState) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use QueueState.ProtoReflect.Descriptor instead.
|
||||
func (*QueueState) Descriptor() ([]byte, []int) {
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{0}
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *QueueState) GetReaderStates() map[int64]*QueueReaderState {
|
||||
@@ -84,7 +137,7 @@ type QueueReaderState struct {
|
||||
|
||||
func (x *QueueReaderState) Reset() {
|
||||
*x = QueueReaderState{}
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[1]
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -96,7 +149,7 @@ func (x *QueueReaderState) String() string {
|
||||
func (*QueueReaderState) ProtoMessage() {}
|
||||
|
||||
func (x *QueueReaderState) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[1]
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[2]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -109,7 +162,7 @@ func (x *QueueReaderState) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use QueueReaderState.ProtoReflect.Descriptor instead.
|
||||
func (*QueueReaderState) Descriptor() ([]byte, []int) {
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{1}
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *QueueReaderState) GetScopes() []*QueueSliceScope {
|
||||
@@ -129,7 +182,7 @@ type QueueSliceScope struct {
|
||||
|
||||
func (x *QueueSliceScope) Reset() {
|
||||
*x = QueueSliceScope{}
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[2]
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -141,7 +194,7 @@ func (x *QueueSliceScope) String() string {
|
||||
func (*QueueSliceScope) ProtoMessage() {}
|
||||
|
||||
func (x *QueueSliceScope) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[2]
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[3]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -154,7 +207,7 @@ func (x *QueueSliceScope) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use QueueSliceScope.ProtoReflect.Descriptor instead.
|
||||
func (*QueueSliceScope) Descriptor() ([]byte, []int) {
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{2}
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *QueueSliceScope) GetRange() *QueueSliceRange {
|
||||
@@ -181,7 +234,7 @@ type QueueSliceRange struct {
|
||||
|
||||
func (x *QueueSliceRange) Reset() {
|
||||
*x = QueueSliceRange{}
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[3]
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -193,7 +246,7 @@ func (x *QueueSliceRange) String() string {
|
||||
func (*QueueSliceRange) ProtoMessage() {}
|
||||
|
||||
func (x *QueueSliceRange) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[3]
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[4]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -206,7 +259,7 @@ func (x *QueueSliceRange) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use QueueSliceRange.ProtoReflect.Descriptor instead.
|
||||
func (*QueueSliceRange) Descriptor() ([]byte, []int) {
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{3}
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *QueueSliceRange) GetInclusiveMin() *TaskKey {
|
||||
@@ -232,7 +285,7 @@ type ReadQueueMessagesNextPageToken struct {
|
||||
|
||||
func (x *ReadQueueMessagesNextPageToken) Reset() {
|
||||
*x = ReadQueueMessagesNextPageToken{}
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[4]
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -244,7 +297,7 @@ func (x *ReadQueueMessagesNextPageToken) String() string {
|
||||
func (*ReadQueueMessagesNextPageToken) ProtoMessage() {}
|
||||
|
||||
func (x *ReadQueueMessagesNextPageToken) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[4]
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[5]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -257,7 +310,7 @@ func (x *ReadQueueMessagesNextPageToken) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ReadQueueMessagesNextPageToken.ProtoReflect.Descriptor instead.
|
||||
func (*ReadQueueMessagesNextPageToken) Descriptor() ([]byte, []int) {
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{4}
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *ReadQueueMessagesNextPageToken) GetLastReadMessageId() int64 {
|
||||
@@ -276,7 +329,7 @@ type ListQueuesNextPageToken struct {
|
||||
|
||||
func (x *ListQueuesNextPageToken) Reset() {
|
||||
*x = ListQueuesNextPageToken{}
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[5]
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -288,7 +341,7 @@ func (x *ListQueuesNextPageToken) String() string {
|
||||
func (*ListQueuesNextPageToken) ProtoMessage() {}
|
||||
|
||||
func (x *ListQueuesNextPageToken) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[5]
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[6]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -301,7 +354,7 @@ func (x *ListQueuesNextPageToken) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ListQueuesNextPageToken.ProtoReflect.Descriptor instead.
|
||||
func (*ListQueuesNextPageToken) Descriptor() ([]byte, []int) {
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{5}
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *ListQueuesNextPageToken) GetLastReadQueueNumber() int64 {
|
||||
@@ -330,7 +383,7 @@ type HistoryTask struct {
|
||||
|
||||
func (x *HistoryTask) Reset() {
|
||||
*x = HistoryTask{}
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[6]
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -342,7 +395,7 @@ func (x *HistoryTask) String() string {
|
||||
func (*HistoryTask) ProtoMessage() {}
|
||||
|
||||
func (x *HistoryTask) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[6]
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[7]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -355,7 +408,7 @@ func (x *HistoryTask) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use HistoryTask.ProtoReflect.Descriptor instead.
|
||||
func (*HistoryTask) Descriptor() ([]byte, []int) {
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{6}
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *HistoryTask) GetShardId() int32 {
|
||||
@@ -392,7 +445,7 @@ type QueuePartition struct {
|
||||
|
||||
func (x *QueuePartition) Reset() {
|
||||
*x = QueuePartition{}
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[7]
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -404,7 +457,7 @@ func (x *QueuePartition) String() string {
|
||||
func (*QueuePartition) ProtoMessage() {}
|
||||
|
||||
func (x *QueuePartition) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[7]
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[8]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -417,7 +470,7 @@ func (x *QueuePartition) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use QueuePartition.ProtoReflect.Descriptor instead.
|
||||
func (*QueuePartition) Descriptor() ([]byte, []int) {
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{7}
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *QueuePartition) GetMinMessageId() int64 {
|
||||
@@ -437,7 +490,7 @@ type Queue struct {
|
||||
|
||||
func (x *Queue) Reset() {
|
||||
*x = Queue{}
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[8]
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -449,7 +502,7 @@ func (x *Queue) String() string {
|
||||
func (*Queue) ProtoMessage() {}
|
||||
|
||||
func (x *Queue) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[8]
|
||||
mi := &file_temporal_server_api_persistence_v1_queues_proto_msgTypes[9]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -462,7 +515,7 @@ func (x *Queue) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Queue.ProtoReflect.Descriptor instead.
|
||||
func (*Queue) Descriptor() ([]byte, []int) {
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{8}
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *Queue) GetPartitions() map[int32]*QueuePartition {
|
||||
@@ -476,7 +529,10 @@ var File_temporal_server_api_persistence_v1_queues_proto protoreflect.FileDescri
|
||||
|
||||
const file_temporal_server_api_persistence_v1_queues_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"/temporal/server/api/persistence/v1/queues.proto\x12\"temporal.server.api.persistence.v1\x1a$temporal/api/common/v1/message.proto\x1a3temporal/server/api/persistence/v1/predicates.proto\x1a.temporal/server/api/persistence/v1/tasks.proto\"\xde\x02\n" +
|
||||
"/temporal/server/api/persistence/v1/queues.proto\x12\"temporal.server.api.persistence.v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a$temporal/api/common/v1/message.proto\x1a3temporal/server/api/persistence/v1/predicates.proto\"[\n" +
|
||||
"\aTaskKey\x127\n" +
|
||||
"\tfire_time\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampR\bfireTime\x12\x17\n" +
|
||||
"\atask_id\x18\x02 \x01(\x03R\x06taskId\"\xde\x02\n" +
|
||||
"\n" +
|
||||
"QueueState\x12e\n" +
|
||||
"\rreader_states\x18\x01 \x03(\v2@.temporal.server.api.persistence.v1.QueueState.ReaderStatesEntryR\freaderStates\x12r\n" +
|
||||
@@ -521,40 +577,42 @@ func file_temporal_server_api_persistence_v1_queues_proto_rawDescGZIP() []byte {
|
||||
return file_temporal_server_api_persistence_v1_queues_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_temporal_server_api_persistence_v1_queues_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
|
||||
var file_temporal_server_api_persistence_v1_queues_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
|
||||
var file_temporal_server_api_persistence_v1_queues_proto_goTypes = []any{
|
||||
(*QueueState)(nil), // 0: temporal.server.api.persistence.v1.QueueState
|
||||
(*QueueReaderState)(nil), // 1: temporal.server.api.persistence.v1.QueueReaderState
|
||||
(*QueueSliceScope)(nil), // 2: temporal.server.api.persistence.v1.QueueSliceScope
|
||||
(*QueueSliceRange)(nil), // 3: temporal.server.api.persistence.v1.QueueSliceRange
|
||||
(*ReadQueueMessagesNextPageToken)(nil), // 4: temporal.server.api.persistence.v1.ReadQueueMessagesNextPageToken
|
||||
(*ListQueuesNextPageToken)(nil), // 5: temporal.server.api.persistence.v1.ListQueuesNextPageToken
|
||||
(*HistoryTask)(nil), // 6: temporal.server.api.persistence.v1.HistoryTask
|
||||
(*QueuePartition)(nil), // 7: temporal.server.api.persistence.v1.QueuePartition
|
||||
(*Queue)(nil), // 8: temporal.server.api.persistence.v1.Queue
|
||||
nil, // 9: temporal.server.api.persistence.v1.QueueState.ReaderStatesEntry
|
||||
nil, // 10: temporal.server.api.persistence.v1.Queue.PartitionsEntry
|
||||
(*TaskKey)(nil), // 11: temporal.server.api.persistence.v1.TaskKey
|
||||
(*Predicate)(nil), // 12: temporal.server.api.persistence.v1.Predicate
|
||||
(*v1.DataBlob)(nil), // 13: temporal.api.common.v1.DataBlob
|
||||
(*TaskKey)(nil), // 0: temporal.server.api.persistence.v1.TaskKey
|
||||
(*QueueState)(nil), // 1: temporal.server.api.persistence.v1.QueueState
|
||||
(*QueueReaderState)(nil), // 2: temporal.server.api.persistence.v1.QueueReaderState
|
||||
(*QueueSliceScope)(nil), // 3: temporal.server.api.persistence.v1.QueueSliceScope
|
||||
(*QueueSliceRange)(nil), // 4: temporal.server.api.persistence.v1.QueueSliceRange
|
||||
(*ReadQueueMessagesNextPageToken)(nil), // 5: temporal.server.api.persistence.v1.ReadQueueMessagesNextPageToken
|
||||
(*ListQueuesNextPageToken)(nil), // 6: temporal.server.api.persistence.v1.ListQueuesNextPageToken
|
||||
(*HistoryTask)(nil), // 7: temporal.server.api.persistence.v1.HistoryTask
|
||||
(*QueuePartition)(nil), // 8: temporal.server.api.persistence.v1.QueuePartition
|
||||
(*Queue)(nil), // 9: temporal.server.api.persistence.v1.Queue
|
||||
nil, // 10: temporal.server.api.persistence.v1.QueueState.ReaderStatesEntry
|
||||
nil, // 11: temporal.server.api.persistence.v1.Queue.PartitionsEntry
|
||||
(*timestamppb.Timestamp)(nil), // 12: google.protobuf.Timestamp
|
||||
(*Predicate)(nil), // 13: temporal.server.api.persistence.v1.Predicate
|
||||
(*v1.DataBlob)(nil), // 14: temporal.api.common.v1.DataBlob
|
||||
}
|
||||
var file_temporal_server_api_persistence_v1_queues_proto_depIdxs = []int32{
|
||||
9, // 0: temporal.server.api.persistence.v1.QueueState.reader_states:type_name -> temporal.server.api.persistence.v1.QueueState.ReaderStatesEntry
|
||||
11, // 1: temporal.server.api.persistence.v1.QueueState.exclusive_reader_high_watermark:type_name -> temporal.server.api.persistence.v1.TaskKey
|
||||
2, // 2: temporal.server.api.persistence.v1.QueueReaderState.scopes:type_name -> temporal.server.api.persistence.v1.QueueSliceScope
|
||||
3, // 3: temporal.server.api.persistence.v1.QueueSliceScope.range:type_name -> temporal.server.api.persistence.v1.QueueSliceRange
|
||||
12, // 4: temporal.server.api.persistence.v1.QueueSliceScope.predicate:type_name -> temporal.server.api.persistence.v1.Predicate
|
||||
11, // 5: temporal.server.api.persistence.v1.QueueSliceRange.inclusive_min:type_name -> temporal.server.api.persistence.v1.TaskKey
|
||||
11, // 6: temporal.server.api.persistence.v1.QueueSliceRange.exclusive_max:type_name -> temporal.server.api.persistence.v1.TaskKey
|
||||
13, // 7: temporal.server.api.persistence.v1.HistoryTask.blob:type_name -> temporal.api.common.v1.DataBlob
|
||||
10, // 8: temporal.server.api.persistence.v1.Queue.partitions:type_name -> temporal.server.api.persistence.v1.Queue.PartitionsEntry
|
||||
1, // 9: temporal.server.api.persistence.v1.QueueState.ReaderStatesEntry.value:type_name -> temporal.server.api.persistence.v1.QueueReaderState
|
||||
7, // 10: temporal.server.api.persistence.v1.Queue.PartitionsEntry.value:type_name -> temporal.server.api.persistence.v1.QueuePartition
|
||||
11, // [11:11] is the sub-list for method output_type
|
||||
11, // [11:11] is the sub-list for method input_type
|
||||
11, // [11:11] is the sub-list for extension type_name
|
||||
11, // [11:11] is the sub-list for extension extendee
|
||||
0, // [0:11] is the sub-list for field type_name
|
||||
12, // 0: temporal.server.api.persistence.v1.TaskKey.fire_time:type_name -> google.protobuf.Timestamp
|
||||
10, // 1: temporal.server.api.persistence.v1.QueueState.reader_states:type_name -> temporal.server.api.persistence.v1.QueueState.ReaderStatesEntry
|
||||
0, // 2: temporal.server.api.persistence.v1.QueueState.exclusive_reader_high_watermark:type_name -> temporal.server.api.persistence.v1.TaskKey
|
||||
3, // 3: temporal.server.api.persistence.v1.QueueReaderState.scopes:type_name -> temporal.server.api.persistence.v1.QueueSliceScope
|
||||
4, // 4: temporal.server.api.persistence.v1.QueueSliceScope.range:type_name -> temporal.server.api.persistence.v1.QueueSliceRange
|
||||
13, // 5: temporal.server.api.persistence.v1.QueueSliceScope.predicate:type_name -> temporal.server.api.persistence.v1.Predicate
|
||||
0, // 6: temporal.server.api.persistence.v1.QueueSliceRange.inclusive_min:type_name -> temporal.server.api.persistence.v1.TaskKey
|
||||
0, // 7: temporal.server.api.persistence.v1.QueueSliceRange.exclusive_max:type_name -> temporal.server.api.persistence.v1.TaskKey
|
||||
14, // 8: temporal.server.api.persistence.v1.HistoryTask.blob:type_name -> temporal.api.common.v1.DataBlob
|
||||
11, // 9: temporal.server.api.persistence.v1.Queue.partitions:type_name -> temporal.server.api.persistence.v1.Queue.PartitionsEntry
|
||||
2, // 10: temporal.server.api.persistence.v1.QueueState.ReaderStatesEntry.value:type_name -> temporal.server.api.persistence.v1.QueueReaderState
|
||||
8, // 11: temporal.server.api.persistence.v1.Queue.PartitionsEntry.value:type_name -> temporal.server.api.persistence.v1.QueuePartition
|
||||
12, // [12:12] is the sub-list for method output_type
|
||||
12, // [12:12] is the sub-list for method input_type
|
||||
12, // [12:12] is the sub-list for extension type_name
|
||||
12, // [12:12] is the sub-list for extension extendee
|
||||
0, // [0:12] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_temporal_server_api_persistence_v1_queues_proto_init() }
|
||||
@@ -563,14 +621,13 @@ func file_temporal_server_api_persistence_v1_queues_proto_init() {
|
||||
return
|
||||
}
|
||||
file_temporal_server_api_persistence_v1_predicates_proto_init()
|
||||
file_temporal_server_api_persistence_v1_tasks_proto_init()
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_temporal_server_api_persistence_v1_queues_proto_rawDesc), len(file_temporal_server_api_persistence_v1_queues_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 11,
|
||||
NumMessages: 12,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
@@ -227,35 +227,35 @@ func (this *SubqueueKey) Equal(that interface{}) bool {
|
||||
return proto.Equal(this, that1)
|
||||
}
|
||||
|
||||
// Marshal an object of type TaskKey to the protobuf v3 wire format
|
||||
func (val *TaskKey) Marshal() ([]byte, error) {
|
||||
// Marshal an object of type PartitionScaleState to the protobuf v3 wire format
|
||||
func (val *PartitionScaleState) Marshal() ([]byte, error) {
|
||||
return proto.Marshal(val)
|
||||
}
|
||||
|
||||
// Unmarshal an object of type TaskKey from the protobuf v3 wire format
|
||||
func (val *TaskKey) Unmarshal(buf []byte) error {
|
||||
// Unmarshal an object of type PartitionScaleState from the protobuf v3 wire format
|
||||
func (val *PartitionScaleState) Unmarshal(buf []byte) error {
|
||||
return proto.Unmarshal(buf, val)
|
||||
}
|
||||
|
||||
// Size returns the size of the object, in bytes, once serialized
|
||||
func (val *TaskKey) Size() int {
|
||||
func (val *PartitionScaleState) Size() int {
|
||||
return proto.Size(val)
|
||||
}
|
||||
|
||||
// Equal returns whether two TaskKey values are equivalent by recursively
|
||||
// Equal returns whether two PartitionScaleState 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 *TaskKey) Equal(that interface{}) bool {
|
||||
func (this *PartitionScaleState) Equal(that interface{}) bool {
|
||||
if that == nil {
|
||||
return this == nil
|
||||
}
|
||||
|
||||
var that1 *TaskKey
|
||||
var that1 *PartitionScaleState
|
||||
switch t := that.(type) {
|
||||
case *TaskKey:
|
||||
case *PartitionScaleState:
|
||||
that1 = t
|
||||
case TaskKey:
|
||||
case PartitionScaleState:
|
||||
that1 = &t
|
||||
default:
|
||||
return false
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
v11 "go.temporal.io/server/api/taskqueue/v1"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
@@ -252,8 +253,10 @@ type TaskQueueInfo struct {
|
||||
// After determinining that the inactive table has no more tasks left, then this
|
||||
// can be cleared on the active table.
|
||||
OtherHasTasks bool `protobuf:"varint,10,opt,name=other_has_tasks,json=otherHasTasks,proto3" json:"other_has_tasks,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
// Dynamic partition scaling state (root only):
|
||||
PartitionScaleState *PartitionScaleState `protobuf:"bytes,11,opt,name=partition_scale_state,json=partitionScaleState,proto3" json:"partition_scale_state,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TaskQueueInfo) Reset() {
|
||||
@@ -356,6 +359,13 @@ func (x *TaskQueueInfo) GetOtherHasTasks() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *TaskQueueInfo) GetPartitionScaleState() *PartitionScaleState {
|
||||
if x != nil {
|
||||
return x.PartitionScaleState
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type SubqueueInfo struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Key is the information used by a splitting algorithm to decide which tasks should go in
|
||||
@@ -544,28 +554,43 @@ func (x *SubqueueKey) GetPriority() int32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
type TaskKey struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
FireTime *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=fire_time,json=fireTime,proto3" json:"fire_time,omitempty"`
|
||||
TaskId int64 `protobuf:"varint,2,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
type PartitionScaleState struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Target number of partitions. Zero means managed scaling is not enabled.
|
||||
Target int32 `protobuf:"varint,1,opt,name=target,proto3" json:"target,omitempty"`
|
||||
// Highest value that target has ever been set to.
|
||||
MaxTarget int32 `protobuf:"varint,2,opt,name=max_target,json=maxTarget,proto3" json:"max_target,omitempty"`
|
||||
// Version number for target. This should change every time target changes.
|
||||
TargetVersion int64 `protobuf:"fixed64,3,opt,name=target_version,json=targetVersion,proto3" json:"target_version,omitempty"`
|
||||
// Bit field of partitions that may have backlog. Partition i is represented by:
|
||||
// backlog_state[i/64] & (1 << i%64).
|
||||
// (-- api-linter: core::0141::forbidden-types=disabled
|
||||
//
|
||||
// aip.dev/not-precedent: This is a bit field --)
|
||||
BacklogState []uint64 `protobuf:"varint,4,rep,packed,name=backlog_state,json=backlogState,proto3" json:"backlog_state,omitempty"`
|
||||
// Arbitrary state kept by the scaler implementation.
|
||||
// (-- api-linter: core::0146::any=disabled
|
||||
//
|
||||
// aip.dev/not-precedent: This is not public. --)
|
||||
PrivateScalerState *anypb.Any `protobuf:"bytes,100,opt,name=private_scaler_state,json=privateScalerState,proto3" json:"private_scaler_state,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TaskKey) Reset() {
|
||||
*x = TaskKey{}
|
||||
func (x *PartitionScaleState) Reset() {
|
||||
*x = PartitionScaleState{}
|
||||
mi := &file_temporal_server_api_persistence_v1_tasks_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *TaskKey) String() string {
|
||||
func (x *PartitionScaleState) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TaskKey) ProtoMessage() {}
|
||||
func (*PartitionScaleState) ProtoMessage() {}
|
||||
|
||||
func (x *TaskKey) ProtoReflect() protoreflect.Message {
|
||||
func (x *PartitionScaleState) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_temporal_server_api_persistence_v1_tasks_proto_msgTypes[6]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
@@ -577,30 +602,51 @@ func (x *TaskKey) ProtoReflect() protoreflect.Message {
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TaskKey.ProtoReflect.Descriptor instead.
|
||||
func (*TaskKey) Descriptor() ([]byte, []int) {
|
||||
// Deprecated: Use PartitionScaleState.ProtoReflect.Descriptor instead.
|
||||
func (*PartitionScaleState) Descriptor() ([]byte, []int) {
|
||||
return file_temporal_server_api_persistence_v1_tasks_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *TaskKey) GetFireTime() *timestamppb.Timestamp {
|
||||
func (x *PartitionScaleState) GetTarget() int32 {
|
||||
if x != nil {
|
||||
return x.FireTime
|
||||
return x.Target
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *PartitionScaleState) GetMaxTarget() int32 {
|
||||
if x != nil {
|
||||
return x.MaxTarget
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *PartitionScaleState) GetTargetVersion() int64 {
|
||||
if x != nil {
|
||||
return x.TargetVersion
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *PartitionScaleState) GetBacklogState() []uint64 {
|
||||
if x != nil {
|
||||
return x.BacklogState
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *TaskKey) GetTaskId() int64 {
|
||||
func (x *PartitionScaleState) GetPrivateScalerState() *anypb.Any {
|
||||
if x != nil {
|
||||
return x.TaskId
|
||||
return x.PrivateScalerState
|
||||
}
|
||||
return 0
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_temporal_server_api_persistence_v1_tasks_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_temporal_server_api_persistence_v1_tasks_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
".temporal/server/api/persistence/v1/tasks.proto\x12\"temporal.server.api.persistence.v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a$temporal/api/common/v1/message.proto\x1a&temporal/api/enums/v1/task_queue.proto\x1a*temporal/server/api/clock/v1/message.proto\x1a.temporal/server/api/taskqueue/v1/message.proto\"\x8b\x01\n" +
|
||||
".temporal/server/api/persistence/v1/tasks.proto\x12\"temporal.server.api.persistence.v1\x1a\x19google/protobuf/any.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a$temporal/api/common/v1/message.proto\x1a&temporal/api/enums/v1/task_queue.proto\x1a*temporal/server/api/clock/v1/message.proto\x1a.temporal/server/api/taskqueue/v1/message.proto\"\x8b\x01\n" +
|
||||
"\x11AllocatedTaskInfo\x12@\n" +
|
||||
"\x04data\x18\x01 \x01(\v2,.temporal.server.api.persistence.v1.TaskInfoR\x04data\x12\x1b\n" +
|
||||
"\ttask_pass\x18\x03 \x01(\x03R\btaskPass\x12\x17\n" +
|
||||
@@ -620,7 +666,7 @@ const file_temporal_server_api_persistence_v1_tasks_proto_rawDesc = "" +
|
||||
"\x05stamp\x18\t \x01(\x05R\x05stamp\x12<\n" +
|
||||
"\bpriority\x18\n" +
|
||||
" \x01(\v2 .temporal.api.common.v1.PriorityR\bpriority\x12#\n" +
|
||||
"\rcomponent_ref\x18\v \x01(\fR\fcomponentRef\"\x97\x04\n" +
|
||||
"\rcomponent_ref\x18\v \x01(\fR\fcomponentRef\"\x84\x05\n" +
|
||||
"\rTaskQueueInfo\x12!\n" +
|
||||
"\fnamespace_id\x18\x01 \x01(\tR\vnamespaceId\x12\x12\n" +
|
||||
"\x04name\x18\x02 \x01(\tR\x04name\x12A\n" +
|
||||
@@ -633,7 +679,8 @@ const file_temporal_server_api_persistence_v1_tasks_proto_rawDesc = "" +
|
||||
"\x19approximate_backlog_count\x18\b \x01(\x03R\x17approximateBacklogCount\x12N\n" +
|
||||
"\tsubqueues\x18\t \x03(\v20.temporal.server.api.persistence.v1.SubqueueInfoR\tsubqueues\x12&\n" +
|
||||
"\x0fother_has_tasks\x18\n" +
|
||||
" \x01(\bR\rotherHasTasks\"\xc2\x03\n" +
|
||||
" \x01(\bR\rotherHasTasks\x12k\n" +
|
||||
"\x15partition_scale_state\x18\v \x01(\v27.temporal.server.api.persistence.v1.PartitionScaleStateR\x13partitionScaleState\"\xc2\x03\n" +
|
||||
"\fSubqueueInfo\x12A\n" +
|
||||
"\x03key\x18\x01 \x01(\v2/.temporal.server.api.persistence.v1.SubqueueKeyR\x03key\x12\x1b\n" +
|
||||
"\tack_level\x18\x02 \x01(\x03R\backLevel\x12Q\n" +
|
||||
@@ -645,10 +692,14 @@ const file_temporal_server_api_persistence_v1_tasks_proto_rawDesc = "" +
|
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||
"\x05count\x18\x02 \x01(\x03R\x05count\")\n" +
|
||||
"\vSubqueueKey\x12\x1a\n" +
|
||||
"\bpriority\x18\x01 \x01(\x05R\bpriority\"[\n" +
|
||||
"\aTaskKey\x127\n" +
|
||||
"\tfire_time\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampR\bfireTime\x12\x17\n" +
|
||||
"\atask_id\x18\x02 \x01(\x03R\x06taskIdB6Z4go.temporal.io/server/api/persistence/v1;persistenceb\x06proto3"
|
||||
"\bpriority\x18\x01 \x01(\x05R\bpriority\"\xe0\x01\n" +
|
||||
"\x13PartitionScaleState\x12\x16\n" +
|
||||
"\x06target\x18\x01 \x01(\x05R\x06target\x12\x1d\n" +
|
||||
"\n" +
|
||||
"max_target\x18\x02 \x01(\x05R\tmaxTarget\x12%\n" +
|
||||
"\x0etarget_version\x18\x03 \x01(\x10R\rtargetVersion\x12#\n" +
|
||||
"\rbacklog_state\x18\x04 \x03(\x04R\fbacklogState\x12F\n" +
|
||||
"\x14private_scaler_state\x18d \x01(\v2\x14.google.protobuf.AnyR\x12privateScalerStateB6Z4go.temporal.io/server/api/persistence/v1;persistenceb\x06proto3"
|
||||
|
||||
var (
|
||||
file_temporal_server_api_persistence_v1_tasks_proto_rawDescOnce sync.Once
|
||||
@@ -670,7 +721,7 @@ var file_temporal_server_api_persistence_v1_tasks_proto_goTypes = []any{
|
||||
(*SubqueueInfo)(nil), // 3: temporal.server.api.persistence.v1.SubqueueInfo
|
||||
(*FairnessKeyCount)(nil), // 4: temporal.server.api.persistence.v1.FairnessKeyCount
|
||||
(*SubqueueKey)(nil), // 5: temporal.server.api.persistence.v1.SubqueueKey
|
||||
(*TaskKey)(nil), // 6: temporal.server.api.persistence.v1.TaskKey
|
||||
(*PartitionScaleState)(nil), // 6: temporal.server.api.persistence.v1.PartitionScaleState
|
||||
(*timestamppb.Timestamp)(nil), // 7: google.protobuf.Timestamp
|
||||
(*v1.VectorClock)(nil), // 8: temporal.server.api.clock.v1.VectorClock
|
||||
(*v11.TaskVersionDirective)(nil), // 9: temporal.server.api.taskqueue.v1.TaskVersionDirective
|
||||
@@ -678,6 +729,7 @@ var file_temporal_server_api_persistence_v1_tasks_proto_goTypes = []any{
|
||||
(v13.TaskQueueType)(0), // 11: temporal.api.enums.v1.TaskQueueType
|
||||
(v13.TaskQueueKind)(0), // 12: temporal.api.enums.v1.TaskQueueKind
|
||||
(*v11.FairLevel)(nil), // 13: temporal.server.api.taskqueue.v1.FairLevel
|
||||
(*anypb.Any)(nil), // 14: google.protobuf.Any
|
||||
}
|
||||
var file_temporal_server_api_persistence_v1_tasks_proto_depIdxs = []int32{
|
||||
1, // 0: temporal.server.api.persistence.v1.AllocatedTaskInfo.data:type_name -> temporal.server.api.persistence.v1.TaskInfo
|
||||
@@ -691,16 +743,17 @@ var file_temporal_server_api_persistence_v1_tasks_proto_depIdxs = []int32{
|
||||
7, // 8: temporal.server.api.persistence.v1.TaskQueueInfo.expiry_time:type_name -> google.protobuf.Timestamp
|
||||
7, // 9: temporal.server.api.persistence.v1.TaskQueueInfo.last_update_time:type_name -> google.protobuf.Timestamp
|
||||
3, // 10: temporal.server.api.persistence.v1.TaskQueueInfo.subqueues:type_name -> temporal.server.api.persistence.v1.SubqueueInfo
|
||||
5, // 11: temporal.server.api.persistence.v1.SubqueueInfo.key:type_name -> temporal.server.api.persistence.v1.SubqueueKey
|
||||
13, // 12: temporal.server.api.persistence.v1.SubqueueInfo.fair_ack_level:type_name -> temporal.server.api.taskqueue.v1.FairLevel
|
||||
13, // 13: temporal.server.api.persistence.v1.SubqueueInfo.fair_max_read_level:type_name -> temporal.server.api.taskqueue.v1.FairLevel
|
||||
4, // 14: temporal.server.api.persistence.v1.SubqueueInfo.top_k_fairness_counts:type_name -> temporal.server.api.persistence.v1.FairnessKeyCount
|
||||
7, // 15: temporal.server.api.persistence.v1.TaskKey.fire_time:type_name -> google.protobuf.Timestamp
|
||||
16, // [16:16] is the sub-list for method output_type
|
||||
16, // [16:16] is the sub-list for method input_type
|
||||
16, // [16:16] is the sub-list for extension type_name
|
||||
16, // [16:16] is the sub-list for extension extendee
|
||||
0, // [0:16] is the sub-list for field type_name
|
||||
6, // 11: temporal.server.api.persistence.v1.TaskQueueInfo.partition_scale_state:type_name -> temporal.server.api.persistence.v1.PartitionScaleState
|
||||
5, // 12: temporal.server.api.persistence.v1.SubqueueInfo.key:type_name -> temporal.server.api.persistence.v1.SubqueueKey
|
||||
13, // 13: temporal.server.api.persistence.v1.SubqueueInfo.fair_ack_level:type_name -> temporal.server.api.taskqueue.v1.FairLevel
|
||||
13, // 14: temporal.server.api.persistence.v1.SubqueueInfo.fair_max_read_level:type_name -> temporal.server.api.taskqueue.v1.FairLevel
|
||||
4, // 15: temporal.server.api.persistence.v1.SubqueueInfo.top_k_fairness_counts:type_name -> temporal.server.api.persistence.v1.FairnessKeyCount
|
||||
14, // 16: temporal.server.api.persistence.v1.PartitionScaleState.private_scaler_state:type_name -> google.protobuf.Any
|
||||
17, // [17:17] is the sub-list for method output_type
|
||||
17, // [17:17] is the sub-list for method input_type
|
||||
17, // [17:17] is the sub-list for extension type_name
|
||||
17, // [17:17] is the sub-list for extension extendee
|
||||
0, // [0:17] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_temporal_server_api_persistence_v1_tasks_proto_init() }
|
||||
|
||||
@@ -29,10 +29,11 @@ func (pc PartitionCounts) Valid() bool {
|
||||
}
|
||||
|
||||
func (pc PartitionCounts) encode() (string, error) {
|
||||
b, err := proto.Marshal(&taskqueuespb.ClientPartitionCounts{
|
||||
cpc := taskqueuespb.ClientPartitionCounts{
|
||||
Read: pc.Read,
|
||||
Write: pc.Write,
|
||||
})
|
||||
}
|
||||
b, err := proto.Marshal(&cpc)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -55,6 +56,10 @@ func (pc PartitionCounts) SetTrailer(ctx context.Context) error {
|
||||
return grpc.SetTrailer(ctx, metadata.Pairs(partitionCountsTrailerName, v))
|
||||
}
|
||||
|
||||
func (pc PartitionCounts) Equal(other PartitionCounts) bool {
|
||||
return pc.Read == other.Read && pc.Write == other.Write
|
||||
}
|
||||
|
||||
func parsePartitionCounts(hdr string) (PartitionCounts, error) {
|
||||
var cpc taskqueuespb.ClientPartitionCounts
|
||||
err := proto.Unmarshal([]byte(hdr), &cpc)
|
||||
@@ -120,7 +125,7 @@ func invokeWithPartitionCounts[Req, Res any](
|
||||
logger.Info("partition count trailer parse error", tag.Error(parseErr))
|
||||
// continue with zero value for newPc
|
||||
}
|
||||
if newPc != pc {
|
||||
if !newPc.Equal(pc) {
|
||||
cache.put(pkey, newPc)
|
||||
pc = newPc
|
||||
}
|
||||
|
||||
@@ -1536,6 +1536,16 @@ default as namespace cardinality can be high and this requires a metrics collect
|
||||
},
|
||||
`How far off client partition scale values have to be to reject RPCs.`,
|
||||
)
|
||||
MatchingPartitionScaleManager = NewTaskQueueTypedSetting(
|
||||
"matching.partitionScaleManager",
|
||||
PartitionScaleManagerSettings{
|
||||
MaxRate: 0.33,
|
||||
BatchSize: 100,
|
||||
BackgroundInterval: 23 * time.Second,
|
||||
DrainBufferTime: 15 * time.Second,
|
||||
},
|
||||
`Settings for partition scale manager.`,
|
||||
)
|
||||
|
||||
// Worker registry settings
|
||||
MatchingWorkerRegistryNumBuckets = NewGlobalIntSetting(
|
||||
|
||||
@@ -128,3 +128,21 @@ type PartitionScaleAllowedDrift struct {
|
||||
Delta int32
|
||||
Ratio float32
|
||||
}
|
||||
|
||||
type PartitionScaleManagerSettings struct {
|
||||
// MaxRate limits scale change frequency.
|
||||
MaxRate float32
|
||||
// BatchSize is the size of a batch to send to the partition scaler. (Needs task queue
|
||||
// reload.)
|
||||
BatchSize int32
|
||||
// BackgroundInterval is the interval for background work:
|
||||
// - send signals to the scaler even if not a full batch of tasks has been received yet
|
||||
// - check drained partition state
|
||||
BackgroundInterval time.Duration
|
||||
// DrainBufferTime is how long to wait until after scaling down before we can consider
|
||||
// draining queues. It's needed because there's a tiny window where tasks may be written
|
||||
// after a scale down, since draining state is only checked at the start of an RPC. This
|
||||
// should be set to the maximum time of an AddTask call that may write to a backlog. Note
|
||||
// that query/nexus tasks will be processed without interruption even after scale down.
|
||||
DrainBufferTime time.Duration
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ var (
|
||||
ComponentShardContext = component("shard-context")
|
||||
ComponentShardEngine = component("shard-engine")
|
||||
ComponentMatchingEngine = component("matching-engine")
|
||||
ComponentPartitionScaler = component("partition-scaler")
|
||||
ComponentReplicator = component("replicator")
|
||||
ComponentReplicationTaskProcessor = component("replication-task-processor")
|
||||
ComponentHSMStateReplicator = component("hsm-state-replicator")
|
||||
|
||||
@@ -1245,6 +1245,9 @@ var (
|
||||
"task_retry_transient",
|
||||
WithDescription("Count of tasks that hit a transient error during match or forward and are retried immediately"),
|
||||
)
|
||||
PartitionScaleEvents = NewCounterDef("partition_scale_events")
|
||||
PartitionScaleRead = NewGaugeDef("partition_scale_read")
|
||||
PartitionScaleWrite = NewGaugeDef("partition_scale_write")
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------------
|
||||
// Matching service: Metrics to track the health of worker registry.
|
||||
|
||||
@@ -319,6 +319,8 @@ func IsServiceClientTransientError(err error) bool {
|
||||
return err.Scope != enumspb.RESOURCE_EXHAUSTED_SCOPE_NAMESPACE
|
||||
case *serviceerrors.ShardOwnershipLost:
|
||||
return true
|
||||
case *serviceerrors.StalePartitionCounts:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -593,6 +593,7 @@ message DescribeTaskQueuePartitionRequest {
|
||||
message DescribeTaskQueuePartitionResponse {
|
||||
// contains k-v pairs of the type: buildID -> TaskQueueVersionInfoInternal
|
||||
map<string, temporal.server.api.taskqueue.v1.TaskQueueVersionInfoInternal> versions_info_internal = 1;
|
||||
temporal.server.api.taskqueue.v1.PartitionScaleInfo scale_info = 2;
|
||||
}
|
||||
|
||||
message ForceUnloadTaskQueuePartitionRequest {
|
||||
|
||||
@@ -312,6 +312,7 @@ message DescribeTaskQueuePartitionRequest {
|
||||
|
||||
message DescribeTaskQueuePartitionResponse {
|
||||
map<string, temporal.server.api.taskqueue.v1.TaskQueueVersionInfoInternal> versions_info_internal = 1;
|
||||
temporal.server.api.taskqueue.v1.PartitionScaleInfo scale_info = 2;
|
||||
}
|
||||
|
||||
message ListTaskQueuePartitionsRequest {
|
||||
|
||||
@@ -2,12 +2,17 @@ syntax = "proto3";
|
||||
|
||||
package temporal.server.api.persistence.v1;
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "temporal/api/common/v1/message.proto";
|
||||
import "temporal/server/api/persistence/v1/predicates.proto";
|
||||
import "temporal/server/api/persistence/v1/tasks.proto";
|
||||
|
||||
option go_package = "go.temporal.io/server/api/persistence/v1;persistence";
|
||||
|
||||
message TaskKey {
|
||||
google.protobuf.Timestamp fire_time = 1;
|
||||
int64 task_id = 2;
|
||||
}
|
||||
|
||||
message QueueState {
|
||||
map<int64, QueueReaderState> reader_states = 1;
|
||||
TaskKey exclusive_reader_high_watermark = 2;
|
||||
|
||||
@@ -2,6 +2,7 @@ syntax = "proto3";
|
||||
|
||||
package temporal.server.api.persistence.v1;
|
||||
|
||||
import "google/protobuf/any.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "temporal/api/common/v1/message.proto";
|
||||
import "temporal/api/enums/v1/task_queue.proto";
|
||||
@@ -72,6 +73,9 @@ message TaskQueueInfo {
|
||||
// After determinining that the inactive table has no more tasks left, then this
|
||||
// can be cleared on the active table.
|
||||
bool other_has_tasks = 10;
|
||||
|
||||
// Dynamic partition scaling state (root only):
|
||||
PartitionScaleState partition_scale_state = 11;
|
||||
}
|
||||
|
||||
message SubqueueInfo {
|
||||
@@ -104,7 +108,24 @@ message SubqueueKey {
|
||||
int32 priority = 1;
|
||||
}
|
||||
|
||||
message TaskKey {
|
||||
google.protobuf.Timestamp fire_time = 1;
|
||||
int64 task_id = 2;
|
||||
message PartitionScaleState {
|
||||
// Target number of partitions. Zero means managed scaling is not enabled.
|
||||
int32 target = 1;
|
||||
|
||||
// Highest value that target has ever been set to.
|
||||
int32 max_target = 2;
|
||||
|
||||
// Version number for target. This should change every time target changes.
|
||||
sfixed64 target_version = 3;
|
||||
|
||||
// Bit field of partitions that may have backlog. Partition i is represented by:
|
||||
// backlog_state[i/64] & (1 << i%64).
|
||||
// (-- api-linter: core::0141::forbidden-types=disabled
|
||||
// aip.dev/not-precedent: This is a bit field --)
|
||||
repeated uint64 backlog_state = 4;
|
||||
|
||||
// Arbitrary state kept by the scaler implementation.
|
||||
// (-- api-linter: core::0146::any=disabled
|
||||
// aip.dev/not-precedent: This is not public. --)
|
||||
google.protobuf.Any private_scaler_state = 100;
|
||||
}
|
||||
|
||||
@@ -1811,6 +1811,7 @@ func (adh *AdminHandler) DescribeTaskQueuePartition(
|
||||
|
||||
return &adminservice.DescribeTaskQueuePartitionResponse{
|
||||
VersionsInfoInternal: resp.VersionsInfoInternal,
|
||||
ScaleInfo: resp.ScaleInfo,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ func (s *BacklogManagerTestSuite) SetupTest() {
|
||||
s.ptqMgr.EXPECT().QueueKey().Return(queue).AnyTimes()
|
||||
s.ptqMgr.EXPECT().ProcessSpooledTask(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
s.ptqMgr.EXPECT().GetFairnessWeightOverrides().AnyTimes().Return(fairnessWeightOverrides{ /* To avoid deadlock with gomock method */ })
|
||||
s.ptqMgr.EXPECT().StartScaleManager(gomock.Any()).AnyTimes()
|
||||
|
||||
var ctx context.Context
|
||||
ctx, s.cancelCtx = context.WithCancel(context.Background())
|
||||
|
||||
46
service/matching/bits.go
Normal file
46
service/matching/bits.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package matching
|
||||
|
||||
import "math/bits"
|
||||
|
||||
// bitSet encapsulates simple bit manipulation functions on a uint64 slice.
|
||||
type bitSet []uint64
|
||||
|
||||
// len returns the index of the highest set bit.
|
||||
func (bs bitSet) len() int32 {
|
||||
i := len(bs) - 1
|
||||
if i < 0 {
|
||||
return 0
|
||||
}
|
||||
return int32(bits.Len64(bs[i]) + i*64)
|
||||
}
|
||||
|
||||
// get returns true if a specific bit is set.
|
||||
func (bs bitSet) get(i int32) bool {
|
||||
if len(bs) < int(i)/64+1 {
|
||||
return false
|
||||
}
|
||||
return bs[i/64]&(1<<(i%64)) != 0
|
||||
}
|
||||
|
||||
// set sets a bit, growing the slice if necessary.
|
||||
// note: caller must assign the result, as with append.
|
||||
func (bs bitSet) set(i int32) bitSet {
|
||||
for len(bs) < int(i)/64+1 {
|
||||
bs = append(bs, 0)
|
||||
}
|
||||
bs[i/64] |= 1 << (i % 64)
|
||||
return bs
|
||||
}
|
||||
|
||||
// clear clears a bit (and shrinks the slice to the minimum required).
|
||||
// note: caller must assign the result, as with append.
|
||||
func (bs bitSet) clear(i int32) bitSet {
|
||||
if len(bs) < int(i)/64+1 {
|
||||
return bs
|
||||
}
|
||||
bs[i/64] &^= 1 << (i % 64)
|
||||
for len(bs) > 0 && bs[len(bs)-1] == 0 {
|
||||
bs = bs[:len(bs)-1]
|
||||
}
|
||||
return bs
|
||||
}
|
||||
60
service/matching/bits_test.go
Normal file
60
service/matching/bits_test.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package matching
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestBitSet(t *testing.T) {
|
||||
var bs bitSet
|
||||
|
||||
// setting and reading individual bits
|
||||
require.False(t, bs.get(0))
|
||||
|
||||
bs = bs.set(0)
|
||||
require.Equal(t, bitSet{1}, bs)
|
||||
require.Equal(t, int32(1), bs.len())
|
||||
require.True(t, bs.get(0))
|
||||
require.False(t, bs.get(1))
|
||||
|
||||
bs = bs.set(5)
|
||||
require.Equal(t, bitSet{0b100001}, bs)
|
||||
require.Equal(t, int32(6), bs.len())
|
||||
require.True(t, bs.get(5))
|
||||
require.False(t, bs.get(4))
|
||||
|
||||
// bit in second word
|
||||
bs = bs.set(64)
|
||||
require.Equal(t, bitSet{0b100001, 1}, bs)
|
||||
require.Equal(t, int32(65), bs.len())
|
||||
require.True(t, bs.get(64))
|
||||
require.False(t, bs.get(65))
|
||||
|
||||
// bit at word boundary
|
||||
bs = bs.set(63)
|
||||
require.Equal(t, bitSet{0b100001 | (1 << 63), 1}, bs)
|
||||
require.Equal(t, int32(65), bs.len())
|
||||
|
||||
// clear high bit, read should drop back
|
||||
bs = bs.clear(64)
|
||||
require.Equal(t, bitSet{0b100001 | (1 << 63)}, bs) // trailing zero word trimmed
|
||||
require.Equal(t, int32(64), bs.len())
|
||||
require.False(t, bs.get(64))
|
||||
|
||||
// clear all bits one by one
|
||||
bs = bs.clear(63)
|
||||
bs = bs.clear(5)
|
||||
bs = bs.clear(0)
|
||||
require.Empty(t, bs)
|
||||
require.Equal(t, int32(0), bs.len())
|
||||
require.False(t, bs.get(0))
|
||||
|
||||
// clearing a bit that's already clear or out of range is a no-op
|
||||
bs = bs.clear(999)
|
||||
require.Empty(t, bs)
|
||||
|
||||
// read on nil returns 0
|
||||
var nilbs bitSet
|
||||
require.Equal(t, int32(0), nilbs.len())
|
||||
}
|
||||
@@ -134,8 +134,9 @@ type (
|
||||
PollerScalingWaitTime dynamicconfig.DurationPropertyFnWithTaskQueueFilter
|
||||
PollerScalingDecisionsPerSecond dynamicconfig.FloatPropertyFnWithTaskQueueFilter
|
||||
|
||||
FairnessCounter dynamicconfig.TypedPropertyFnWithTaskQueueFilter[counter.CounterParams]
|
||||
PartitionScaleAllowedDrift dynamicconfig.TypedPropertyFnWithTaskQueueFilter[dynamicconfig.PartitionScaleAllowedDrift]
|
||||
FairnessCounter dynamicconfig.TypedPropertyFnWithTaskQueueFilter[counter.CounterParams]
|
||||
PartitionScaleAllowedDrift dynamicconfig.TypedPropertyFnWithTaskQueueFilter[dynamicconfig.PartitionScaleAllowedDrift]
|
||||
PartitionScaleManagerSettings dynamicconfig.TypedPropertyFnWithTaskQueueFilter[dynamicconfig.PartitionScaleManagerSettings]
|
||||
|
||||
LogAllReqErrors dynamicconfig.BoolPropertyFnWithNamespaceFilter
|
||||
}
|
||||
@@ -223,8 +224,9 @@ type (
|
||||
PollerScalingWaitTime func() time.Duration
|
||||
PollerScalingDecisionsPerSecond func() float64
|
||||
|
||||
FairnessCounter func() counter.CounterParams
|
||||
PartitionScaleAllowedDrift func() dynamicconfig.PartitionScaleAllowedDrift
|
||||
FairnessCounter func() counter.CounterParams
|
||||
PartitionScaleAllowedDrift func() dynamicconfig.PartitionScaleAllowedDrift
|
||||
PartitionScaleManagerSettings func() dynamicconfig.PartitionScaleManagerSettings
|
||||
|
||||
loadCause loadCause
|
||||
}
|
||||
@@ -371,8 +373,9 @@ func NewConfig(
|
||||
PollerScalingWaitTime: dynamicconfig.MatchingPollerScalingWaitTime.Get(dc),
|
||||
PollerScalingDecisionsPerSecond: dynamicconfig.MatchingPollerScalingDecisionsPerSecond.Get(dc),
|
||||
|
||||
FairnessCounter: dynamicconfig.MatchingFairnessCounter.Get(dc),
|
||||
PartitionScaleAllowedDrift: dynamicconfig.MatchingPartitionScaleAllowedDrift.Get(dc),
|
||||
FairnessCounter: dynamicconfig.MatchingFairnessCounter.Get(dc),
|
||||
PartitionScaleAllowedDrift: dynamicconfig.MatchingPartitionScaleAllowedDrift.Get(dc),
|
||||
PartitionScaleManagerSettings: dynamicconfig.MatchingPartitionScaleManager.Get(dc),
|
||||
|
||||
LogAllReqErrors: dynamicconfig.LogAllReqErrors.Get(dc),
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ type (
|
||||
rangeID int64
|
||||
subqueues []*dbSubqueue
|
||||
otherHasTasks bool
|
||||
scaleState *persistencespb.PartitionScaleState
|
||||
|
||||
// used to avoid unnecessary metadata writes:
|
||||
lastChange time.Time // updated when metadata is changed in memory
|
||||
@@ -62,6 +63,7 @@ type (
|
||||
ackLevel int64 // TODO(pri): old matcher cleanup, delete later
|
||||
subqueues []persistencespb.SubqueueInfo
|
||||
otherHasTasks bool
|
||||
scaleState *persistencespb.PartitionScaleState
|
||||
}
|
||||
|
||||
subqueueIndex int
|
||||
@@ -165,6 +167,7 @@ func (db *taskQueueDB) RenewLease(
|
||||
ackLevel: db.subqueues[subqueueZero].AckLevel, // TODO(pri): cleanup, only used by old backlog manager
|
||||
subqueues: db.cloneSubqueues(),
|
||||
otherHasTasks: !db.isDraining && db.otherHasTasks,
|
||||
scaleState: db.scaleState,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -187,6 +190,7 @@ func (db *taskQueueDB) takeOverTaskQueueLocked(
|
||||
response.TaskQueueInfo.AckLevel,
|
||||
response.TaskQueueInfo.ApproximateBacklogCount,
|
||||
)
|
||||
db.scaleState = response.TaskQueueInfo.PartitionScaleState
|
||||
err := db.updateTaskQueueLocked(ctx, true)
|
||||
if err != nil {
|
||||
db.rangeID = 0
|
||||
@@ -492,6 +496,19 @@ func (db *taskQueueDB) SetOtherHasTasks(ctx context.Context, value bool) error {
|
||||
return db.updateTaskQueueLocked(ctx, false)
|
||||
}
|
||||
|
||||
// UpdateScaleState sets the partition scale state (in memory). If syncToDB is true, it also tries to persist it to the DB.
|
||||
// If syncToDB is false, ctx is not used.
|
||||
func (db *taskQueueDB) UpdateScaleState(ctx context.Context, scaleState *persistencespb.PartitionScaleState, syncToDB bool) error {
|
||||
db.Lock()
|
||||
defer db.Unlock()
|
||||
db.scaleState = scaleState
|
||||
db.lastChange = time.Now()
|
||||
if syncToDB {
|
||||
return db.updateTaskQueueLocked(ctx, false)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateTasks creates a batch of given tasks for this task queue
|
||||
func (db *taskQueueDB) CreateTasks(
|
||||
ctx context.Context,
|
||||
@@ -795,6 +812,7 @@ func (db *taskQueueDB) cachedQueueInfo() *persistencespb.TaskQueueInfo {
|
||||
ApproximateBacklogCount: db.subqueues[subqueueZero].ApproximateBacklogCount, // backwards compatibility
|
||||
Subqueues: infos,
|
||||
OtherHasTasks: db.otherHasTasks,
|
||||
PartitionScaleState: db.scaleState,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -143,6 +143,12 @@ func (c *fairBacklogManagerImpl) initState(state taskQueueState, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Pass scale info back to physical tq from unversioned (default) queue.
|
||||
// This must be done before c.initializedError.Set().
|
||||
if c.queueKey().Partition().IsRoot() && !c.queueKey().IsVersioned() {
|
||||
c.pqMgr.StartScaleManager(state.scaleState)
|
||||
}
|
||||
|
||||
if state.otherHasTasks {
|
||||
c.pqMgr.SetupDraining()
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ var Module = fx.Options(
|
||||
fx.Provide(ServiceResolverProvider),
|
||||
fx.Provide(ServerProvider),
|
||||
fx.Provide(NewService),
|
||||
fx.Provide(func() PartitionScalerFactory { return nil }),
|
||||
fx.Invoke(ServiceLifetimeHooks),
|
||||
)
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ type (
|
||||
WorkersRegistry workers.Registry
|
||||
Serializer serialization.Serializer
|
||||
TaskHookFactories []hooks.TaskHookFactory `group:"TaskHookFactories"`
|
||||
PartitionScalerFactory PartitionScalerFactory
|
||||
}
|
||||
)
|
||||
|
||||
@@ -117,6 +118,7 @@ func NewHandler(
|
||||
params.RateLimiter,
|
||||
params.Serializer,
|
||||
params.TaskHookFactories,
|
||||
params.PartitionScalerFactory,
|
||||
),
|
||||
namespaceRegistry: params.NamespaceRegistry,
|
||||
workersRegistry: params.WorkersRegistry,
|
||||
|
||||
@@ -167,6 +167,7 @@ type (
|
||||
partitions map[tqid.PartitionKey]taskQueuePartitionManager
|
||||
gaugeMetrics gaugeMetrics // per-namespace task queue counters
|
||||
config *Config
|
||||
partitionScalerFactory PartitionScalerFactory
|
||||
versionChecker headers.VersionChecker
|
||||
testHooks testhooks.TestHooks
|
||||
// queryResults maps query TaskID (which is a UUID generated in QueryWorkflow() call) to a channel
|
||||
@@ -282,6 +283,7 @@ func NewEngine(
|
||||
rateLimiter TaskDispatchRateLimiter,
|
||||
historySerializer serialization.Serializer,
|
||||
taskHookFactories []hooks.TaskHookFactory,
|
||||
partitionScalerFactory PartitionScalerFactory,
|
||||
) Engine {
|
||||
scopedMetricsHandler := metricsHandler.WithTags(metrics.OperationTag(metrics.MatchingEngineScope))
|
||||
e := &matchingEngineImpl{
|
||||
@@ -326,6 +328,7 @@ func NewEngine(
|
||||
userDataUpdateBatchers: collection.NewSyncMap[namespace.ID, *stream_batcher.Batcher[*userDataUpdate, error]](),
|
||||
rateLimiter: rateLimiter,
|
||||
taskHookFactories: taskHookFactories,
|
||||
partitionScalerFactory: partitionScalerFactory,
|
||||
}
|
||||
e.nexusEndpointsOwnershipLostCh.Store(make(chan struct{}))
|
||||
e.reachabilityCache = newReachabilityCache(
|
||||
|
||||
50
service/matching/partition_scaler_interface.go
Normal file
50
service/matching/partition_scaler_interface.go
Normal file
@@ -0,0 +1,50 @@
|
||||
//go:generate mockgen -package $GOPACKAGE -source $GOFILE -destination partition_scaler_mock.go
|
||||
|
||||
package matching
|
||||
|
||||
import (
|
||||
enumspb "go.temporal.io/api/enums/v1"
|
||||
"go.temporal.io/server/common/namespace"
|
||||
"google.golang.org/protobuf/types/known/anypb"
|
||||
)
|
||||
|
||||
// PartitionScalerFactory is a pluggable interface to control partition scaling.
|
||||
type PartitionScalerFactory interface {
|
||||
// New will be called for a new root partition. It should return a new PartitionScaler
|
||||
// (or nil to disable).
|
||||
New(nsName namespace.Name, tqName string, tqType enumspb.TaskQueueType) PartitionScaler
|
||||
}
|
||||
|
||||
// PartitionScaler is an instance of a scaler for one task queue.
|
||||
type PartitionScaler interface {
|
||||
// OnTasks will be called once per batch of tasks added, either sync match or async. The
|
||||
// NumTasks count may be estimated based on assumptions of load balancing across
|
||||
// partitions.
|
||||
//
|
||||
// It will be given the current partition count target and its
|
||||
// private state (optional). It returns a PartitionScalerDecision, which will usually be
|
||||
// "no change". To make a change, it should return a number in NewTarget. Zero means
|
||||
// disable managed scaling.
|
||||
//
|
||||
// Changes may be ignored if values are out of range, if changed too often, or other
|
||||
// reasons. Private state will not be updated if target doesn't also change, or if the
|
||||
// change is ignored due to rate limit or any other reason.
|
||||
//
|
||||
// It will also be called periodically with less than a full batch, or even zero, to allow
|
||||
// timely scale down when there are no/few tasks.
|
||||
OnTasks(PartitionScalerInput) PartitionScalerDecision
|
||||
// Stop will be called when unloading the partition.
|
||||
Stop()
|
||||
}
|
||||
|
||||
type PartitionScalerInput struct {
|
||||
NumTasks int // new tasks added since last call
|
||||
CurrentTarget int
|
||||
PrivateState *anypb.Any
|
||||
}
|
||||
|
||||
type PartitionScalerDecision struct {
|
||||
NoChange bool // if true, don't do anything
|
||||
NewTarget int // if zero, disable managed scaling, otherwise set partition target
|
||||
PrivateState *anypb.Any // optional private state to be stored with target
|
||||
}
|
||||
106
service/matching/partition_scaler_mock.go
Normal file
106
service/matching/partition_scaler_mock.go
Normal file
@@ -0,0 +1,106 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: partition_scaler_interface.go
|
||||
//
|
||||
// Generated by this command:
|
||||
//
|
||||
// mockgen -package matching -source partition_scaler_interface.go -destination partition_scaler_mock.go
|
||||
//
|
||||
|
||||
// Package matching is a generated GoMock package.
|
||||
package matching
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
enums "go.temporal.io/api/enums/v1"
|
||||
namespace "go.temporal.io/server/common/namespace"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockPartitionScalerFactory is a mock of PartitionScalerFactory interface.
|
||||
type MockPartitionScalerFactory struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockPartitionScalerFactoryMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockPartitionScalerFactoryMockRecorder is the mock recorder for MockPartitionScalerFactory.
|
||||
type MockPartitionScalerFactoryMockRecorder struct {
|
||||
mock *MockPartitionScalerFactory
|
||||
}
|
||||
|
||||
// NewMockPartitionScalerFactory creates a new mock instance.
|
||||
func NewMockPartitionScalerFactory(ctrl *gomock.Controller) *MockPartitionScalerFactory {
|
||||
mock := &MockPartitionScalerFactory{ctrl: ctrl}
|
||||
mock.recorder = &MockPartitionScalerFactoryMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockPartitionScalerFactory) EXPECT() *MockPartitionScalerFactoryMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// New mocks base method.
|
||||
func (m *MockPartitionScalerFactory) New(nsName namespace.Name, tqName string, tqType enums.TaskQueueType) PartitionScaler {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "New", nsName, tqName, tqType)
|
||||
ret0, _ := ret[0].(PartitionScaler)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// New indicates an expected call of New.
|
||||
func (mr *MockPartitionScalerFactoryMockRecorder) New(nsName, tqName, tqType any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "New", reflect.TypeOf((*MockPartitionScalerFactory)(nil).New), nsName, tqName, tqType)
|
||||
}
|
||||
|
||||
// MockPartitionScaler is a mock of PartitionScaler interface.
|
||||
type MockPartitionScaler struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockPartitionScalerMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockPartitionScalerMockRecorder is the mock recorder for MockPartitionScaler.
|
||||
type MockPartitionScalerMockRecorder struct {
|
||||
mock *MockPartitionScaler
|
||||
}
|
||||
|
||||
// NewMockPartitionScaler creates a new mock instance.
|
||||
func NewMockPartitionScaler(ctrl *gomock.Controller) *MockPartitionScaler {
|
||||
mock := &MockPartitionScaler{ctrl: ctrl}
|
||||
mock.recorder = &MockPartitionScalerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockPartitionScaler) EXPECT() *MockPartitionScalerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// OnTasks mocks base method.
|
||||
func (m *MockPartitionScaler) OnTasks(arg0 PartitionScalerInput) PartitionScalerDecision {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "OnTasks", arg0)
|
||||
ret0, _ := ret[0].(PartitionScalerDecision)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// OnTasks indicates an expected call of OnTasks.
|
||||
func (mr *MockPartitionScalerMockRecorder) OnTasks(arg0 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnTasks", reflect.TypeOf((*MockPartitionScaler)(nil).OnTasks), arg0)
|
||||
}
|
||||
|
||||
// Stop mocks base method.
|
||||
func (m *MockPartitionScaler) Stop() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Stop")
|
||||
}
|
||||
|
||||
// Stop indicates an expected call of Stop.
|
||||
func (mr *MockPartitionScalerMockRecorder) Stop() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockPartitionScaler)(nil).Stop))
|
||||
}
|
||||
@@ -352,6 +352,20 @@ func (c *physicalTaskQueueManagerImpl) WaitUntilInitialized(ctx context.Context)
|
||||
return err
|
||||
}
|
||||
|
||||
// StartScaleManager is called by backlog manager after it's loaded metadata from the default queue. (New matcher only.)
|
||||
func (c *physicalTaskQueueManagerImpl) StartScaleManager(scaleState *persistencespb.PartitionScaleState) {
|
||||
c.partitionMgr.StartScaleManager(scaleState)
|
||||
}
|
||||
|
||||
func (c *physicalTaskQueueManagerImpl) UpdateScaleState(scaleState *persistencespb.PartitionScaleState, syncToDB bool) error {
|
||||
if !syncToDB {
|
||||
return c.backlogMgr.getDB().UpdateScaleState(c.tqCtx /* unused */, scaleState, false)
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(c.tqCtx, ioTimeout)
|
||||
defer cancel()
|
||||
return c.backlogMgr.getDB().UpdateScaleState(ctx, scaleState, true)
|
||||
}
|
||||
|
||||
// Call this to set up dual-read from the other table.
|
||||
// Must be called by the active backlog manager before it sets itself initialized.
|
||||
// Must only be called when using new matcher.
|
||||
|
||||
@@ -18,6 +18,11 @@ type (
|
||||
Start()
|
||||
Stop(unloadCause)
|
||||
WaitUntilInitialized(context.Context) error
|
||||
// StartScaleManager is called by backlog manager after it's loaded metadata from the
|
||||
// default queue. (New matcher only.)
|
||||
StartScaleManager(*persistencespb.PartitionScaleState)
|
||||
// UpdateScaleState is called from the scale manager to update the scale state in the db.
|
||||
UpdateScaleState(*persistencespb.PartitionScaleState, bool) error
|
||||
SetupDraining()
|
||||
// FinishedDraining is called by a draining backlog manager when it has fully drained.
|
||||
FinishedDraining()
|
||||
|
||||
@@ -357,6 +357,18 @@ func (mr *MockphysicalTaskQueueManagerMockRecorder) Start() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockphysicalTaskQueueManager)(nil).Start))
|
||||
}
|
||||
|
||||
// StartScaleManager mocks base method.
|
||||
func (m *MockphysicalTaskQueueManager) StartScaleManager(arg0 *persistence.PartitionScaleState) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "StartScaleManager", arg0)
|
||||
}
|
||||
|
||||
// StartScaleManager indicates an expected call of StartScaleManager.
|
||||
func (mr *MockphysicalTaskQueueManagerMockRecorder) StartScaleManager(arg0 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartScaleManager", reflect.TypeOf((*MockphysicalTaskQueueManager)(nil).StartScaleManager), arg0)
|
||||
}
|
||||
|
||||
// Stop mocks base method.
|
||||
func (m *MockphysicalTaskQueueManager) Stop(arg0 unloadCause) {
|
||||
m.ctrl.T.Helper()
|
||||
@@ -420,6 +432,20 @@ func (mr *MockphysicalTaskQueueManagerMockRecorder) UpdateRemotePriorityBacklogs
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateRemotePriorityBacklogs", reflect.TypeOf((*MockphysicalTaskQueueManager)(nil).UpdateRemotePriorityBacklogs), arg0)
|
||||
}
|
||||
|
||||
// UpdateScaleState mocks base method.
|
||||
func (m *MockphysicalTaskQueueManager) UpdateScaleState(arg0 *persistence.PartitionScaleState, arg1 bool) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateScaleState", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UpdateScaleState indicates an expected call of UpdateScaleState.
|
||||
func (mr *MockphysicalTaskQueueManagerMockRecorder) UpdateScaleState(arg0, arg1 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateScaleState", reflect.TypeOf((*MockphysicalTaskQueueManager)(nil).UpdateScaleState), arg0, arg1)
|
||||
}
|
||||
|
||||
// UserDataChanged mocks base method.
|
||||
func (m *MockphysicalTaskQueueManager) UserDataChanged() {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
@@ -156,6 +156,12 @@ func (c *priBacklogManagerImpl) initState(state taskQueueState, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Pass scale info back to physical tq from unversioned (default) queue.
|
||||
// This must be done before c.initializedError.Set().
|
||||
if c.queueKey().Partition().IsRoot() && !c.queueKey().IsVersioned() {
|
||||
c.pqMgr.StartScaleManager(state.scaleState)
|
||||
}
|
||||
|
||||
if state.otherHasTasks {
|
||||
c.pqMgr.SetupDraining()
|
||||
}
|
||||
|
||||
357
service/matching/scale_manager.go
Normal file
357
service/matching/scale_manager.go
Normal file
@@ -0,0 +1,357 @@
|
||||
//go:generate mockgen -package $GOPACKAGE -source $GOFILE -destination scale_manager_mock.go
|
||||
|
||||
package matching
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
taskqueuepb "go.temporal.io/api/taskqueue/v1"
|
||||
"go.temporal.io/server/api/matchingservice/v1"
|
||||
persistencespb "go.temporal.io/server/api/persistence/v1"
|
||||
taskqueuespb "go.temporal.io/server/api/taskqueue/v1"
|
||||
"go.temporal.io/server/common"
|
||||
"go.temporal.io/server/common/backoff"
|
||||
"go.temporal.io/server/common/clock"
|
||||
"go.temporal.io/server/common/dynamicconfig"
|
||||
"go.temporal.io/server/common/goro"
|
||||
"go.temporal.io/server/common/log"
|
||||
"go.temporal.io/server/common/log/tag"
|
||||
"go.temporal.io/server/common/metrics"
|
||||
"go.temporal.io/server/common/tqid"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// scaleManager keeps some state and manages the interaction with partitionScaler.
|
||||
// scaleManager runs on the root partition only.
|
||||
//
|
||||
// All scaler/state work is funneled through a single background goroutine. That
|
||||
// goroutine owns scaleState/scaleDB/lastDecision and is the only caller of
|
||||
// partitionScaler, so the scaler implementation can rely on serial calls and
|
||||
// scaleState needs no lock. AddedTasks talks to the worker only via the atomic
|
||||
// batch counter and the wakeup channel, so it never blocks.
|
||||
type scaleManager struct {
|
||||
partition tqid.Partition
|
||||
logger log.Logger
|
||||
metricsHandler metrics.Handler
|
||||
userDataManager userDataManager
|
||||
matchingClient matchingservice.MatchingServiceClient
|
||||
partitionScaler PartitionScaler
|
||||
batchSize int64 // fixed at creation time
|
||||
settings dynamicconfig.TypedPropertyFn[dynamicconfig.PartitionScaleManagerSettings]
|
||||
getWritePartitions dynamicconfig.IntPropertyFn
|
||||
emitGaugeMetrics dynamicconfig.BoolPropertyFn
|
||||
timeSource clock.TimeSource
|
||||
background *goro.Handle
|
||||
|
||||
// owned by the worker goroutine after Start starts it
|
||||
scaleState *persistencespb.PartitionScaleState
|
||||
scaleDB scaleDB
|
||||
nextDecision time.Time
|
||||
|
||||
batch atomic.Int64
|
||||
wakeup chan struct{}
|
||||
}
|
||||
|
||||
// scaleDB is used to write scale state to persistence. It's a sub-interface of
|
||||
// physicalTaskQueueManager (for the default queue).
|
||||
type scaleDB interface {
|
||||
UpdateScaleState(*persistencespb.PartitionScaleState, bool) error
|
||||
}
|
||||
|
||||
func newScaleManager(
|
||||
baseCtx context.Context,
|
||||
partition tqid.Partition,
|
||||
logger log.Logger,
|
||||
metricsHandler metrics.Handler,
|
||||
userDataManager userDataManager,
|
||||
matchingClient matchingservice.MatchingServiceClient,
|
||||
partitionScaler PartitionScaler,
|
||||
timeSource clock.TimeSource,
|
||||
settings dynamicconfig.TypedPropertyFn[dynamicconfig.PartitionScaleManagerSettings],
|
||||
getWritePartitions dynamicconfig.IntPropertyFn,
|
||||
emitGaugeMetrics dynamicconfig.BoolPropertyFn,
|
||||
) *scaleManager {
|
||||
return &scaleManager{
|
||||
partition: partition,
|
||||
logger: log.With(logger, tag.ComponentPartitionScaler),
|
||||
metricsHandler: metricsHandler,
|
||||
userDataManager: userDataManager,
|
||||
matchingClient: matchingClient,
|
||||
partitionScaler: partitionScaler,
|
||||
batchSize: int64(settings().BatchSize),
|
||||
settings: settings,
|
||||
getWritePartitions: getWritePartitions,
|
||||
emitGaugeMetrics: emitGaugeMetrics,
|
||||
timeSource: timeSource,
|
||||
background: goro.NewHandle(baseCtx),
|
||||
wakeup: make(chan struct{}, 1),
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *scaleManager) Stop() {
|
||||
if sm == nil {
|
||||
return
|
||||
}
|
||||
sm.background.Cancel()
|
||||
sm.partitionScaler.Stop()
|
||||
if sm.emitGaugeMetrics() {
|
||||
// this is unfortunate but at least allows max() across pods to get the right value
|
||||
metrics.PartitionScaleRead.With(sm.metricsHandler).Record(float64(-1))
|
||||
metrics.PartitionScaleWrite.With(sm.metricsHandler).Record(float64(-1))
|
||||
}
|
||||
}
|
||||
|
||||
// Start is called when the root partitions's default queue has loaded its metadata.
|
||||
// Must be called at most once.
|
||||
func (sm *scaleManager) Start(scaleState *persistencespb.PartitionScaleState, scaleDB scaleDB) {
|
||||
if sm == nil {
|
||||
return
|
||||
}
|
||||
// backgroundWork can assume sm.scaleDB is set since we set it before starting it.
|
||||
sm.scaleDB = scaleDB
|
||||
sm.setState(scaleState)
|
||||
sm.background.Go(sm.backgroundWork)
|
||||
}
|
||||
|
||||
// AddedTasks is called on a batch of tasks added.
|
||||
// This is called in the task add path, so it shouldn't block.
|
||||
func (sm *scaleManager) AddedTasks(numTasks int) {
|
||||
if sm == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// scale target batch size by numTasks (since numTasks is scaled by partitions)
|
||||
batchSize := int64(numTasks) * sm.batchSize
|
||||
if sm.batch.Add(int64(numTasks)) < batchSize {
|
||||
return // not enough for a batch yet
|
||||
}
|
||||
|
||||
// non-blocking signal
|
||||
select {
|
||||
case sm.wakeup <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *scaleManager) backgroundWork(ctx context.Context) error {
|
||||
timerCh := func() <-chan time.Time {
|
||||
ch, _ := sm.timeSource.NewTimer(backoff.Jitter(sm.settings().BackgroundInterval, 0.05))
|
||||
return ch
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
|
||||
case <-sm.wakeup:
|
||||
sm.callScaler()
|
||||
|
||||
case <-timerCh():
|
||||
// call scaler even if batch == 0, to allow scale down when no tasks are coming in
|
||||
sm.callScaler()
|
||||
// check child partitions periodically
|
||||
sm.updateDrainState(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// callScaler runs the scaler on the accumulated batch and persists the resulting state if it
|
||||
// changed.
|
||||
// Called from backgroundWork only.
|
||||
func (sm *scaleManager) callScaler() {
|
||||
// don't bother calling during cooldown period
|
||||
if !sm.nextDecision.IsZero() && sm.timeSource.Now().Before(sm.nextDecision) {
|
||||
return
|
||||
}
|
||||
|
||||
// grab current batch (may be zero)
|
||||
tasks := int(sm.batch.Swap(0))
|
||||
|
||||
decision := sm.partitionScaler.OnTasks(PartitionScalerInput{
|
||||
NumTasks: tasks,
|
||||
CurrentTarget: int(sm.scaleState.GetTarget()),
|
||||
PrivateState: sm.scaleState.GetPrivateScalerState(),
|
||||
})
|
||||
if decision.NoChange ||
|
||||
decision.NewTarget == int(sm.scaleState.GetTarget()) {
|
||||
return
|
||||
}
|
||||
|
||||
target := int32(decision.NewTarget)
|
||||
|
||||
newState := common.CloneProto(sm.scaleState)
|
||||
if newState == nil {
|
||||
newState = &persistencespb.PartitionScaleState{}
|
||||
}
|
||||
prevTarget := newState.Target
|
||||
newState.Target = target
|
||||
newState.MaxTarget = max(newState.MaxTarget, target)
|
||||
newState.TargetVersion = sm.timeSource.Now().UnixNano()
|
||||
newState.PrivateScalerState = decision.PrivateState
|
||||
|
||||
mayHaveBacklog := target
|
||||
if prevTarget == 0 {
|
||||
// Turning on managed partition scaling: consider all partitions from dynamic
|
||||
// config as having backlog also.
|
||||
mayHaveBacklog = max(mayHaveBacklog, int32(sm.getWritePartitions()))
|
||||
}
|
||||
for i := range mayHaveBacklog {
|
||||
newState.BacklogState = bitSet(newState.BacklogState).set(i)
|
||||
}
|
||||
|
||||
// we must succesfully write to the db before making new state active
|
||||
if err := sm.scaleDB.UpdateScaleState(newState, true); err != nil {
|
||||
sm.logger.Error("failed to update state", tag.Error(err), tag.Operation("scale"))
|
||||
return
|
||||
}
|
||||
|
||||
cooldown := time.Duration(float32(time.Second) / sm.settings().MaxRate)
|
||||
sm.nextDecision = sm.timeSource.Now().Add(cooldown)
|
||||
|
||||
sm.logger.Info("new target",
|
||||
tag.Int32("target", target),
|
||||
tag.Int32("prev-target", prevTarget),
|
||||
tag.Int32("max-target", newState.MaxTarget))
|
||||
metrics.PartitionScaleEvents.With(sm.metricsHandler).Record(1)
|
||||
|
||||
sm.setState(newState)
|
||||
}
|
||||
|
||||
// setState updates the current scale state and syncs it to ephemeral data.
|
||||
// This should only be called _after_ the state is persisted to the db.
|
||||
// Called from backgroundWork or LoadedMetadata only.
|
||||
func (sm *scaleManager) setState(newState *persistencespb.PartitionScaleState) {
|
||||
prevInfo := scaleStateToInfo(sm.scaleState)
|
||||
|
||||
sm.scaleState = newState
|
||||
|
||||
newInfo := scaleStateToInfo(sm.scaleState)
|
||||
|
||||
// only push ephemeral data if _info_ changed, not on any state change
|
||||
if !proto.Equal(prevInfo, newInfo) {
|
||||
sm.userDataManager.SetPartitionScale(newInfo)
|
||||
}
|
||||
|
||||
if sm.emitGaugeMetrics() {
|
||||
metrics.PartitionScaleRead.With(sm.metricsHandler).Record(float64(newInfo.Read))
|
||||
metrics.PartitionScaleWrite.With(sm.metricsHandler).Record(float64(newInfo.Write))
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *scaleManager) describeRequest(id int32) *matchingservice.DescribeTaskQueuePartitionRequest {
|
||||
return &matchingservice.DescribeTaskQueuePartitionRequest{
|
||||
NamespaceId: sm.partition.NamespaceId(),
|
||||
TaskQueuePartition: &taskqueuespb.TaskQueuePartition{
|
||||
TaskQueue: sm.partition.TaskQueue().Name(),
|
||||
TaskQueueType: sm.partition.TaskType(),
|
||||
PartitionId: &taskqueuespb.TaskQueuePartition_NormalPartitionId{NormalPartitionId: id},
|
||||
},
|
||||
Versions: &taskqueuepb.TaskQueueVersionSelection{
|
||||
Unversioned: true,
|
||||
// TODO(dp)(carlydf): deal with inactive/deleted versions (use user data version info)
|
||||
AllActive: true,
|
||||
},
|
||||
ReportInternalTaskQueueStatus: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *scaleManager) updateDrainState(ctx context.Context) {
|
||||
scaleState := sm.scaleState
|
||||
read := scaleStateToReadCount(scaleState)
|
||||
if read == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// check if we should evaluate drain state
|
||||
target := scaleState.GetTarget()
|
||||
checkDrain := target > 0 &&
|
||||
sm.timeSource.Since(time.Unix(0, scaleState.GetTargetVersion())) >= sm.settings().DrainBufferTime
|
||||
info := scaleStateToInfo(scaleState)
|
||||
var toClear []int32
|
||||
|
||||
for id := range read {
|
||||
// note: right now, this call is useless if checkDrain is false, or for partitions < write.
|
||||
// later we'll need these calls to update backlog and other stats, so we just do it always
|
||||
// now to simplify the future diff.
|
||||
callCtx, cancel := context.WithTimeout(ctx, ioTimeout)
|
||||
res, err := sm.matchingClient.DescribeTaskQueuePartition(callCtx, sm.describeRequest(id))
|
||||
cancel()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// check drain state for partitions in the draining range
|
||||
if checkDrain &&
|
||||
id >= target &&
|
||||
bitSet(scaleState.BacklogState).get(id) &&
|
||||
partitionIsFullyDrained(res, info) {
|
||||
toClear = append(toClear, id)
|
||||
}
|
||||
}
|
||||
|
||||
if len(toClear) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
newState := common.CloneProto(scaleState)
|
||||
if newState == nil {
|
||||
newState = &persistencespb.PartitionScaleState{}
|
||||
}
|
||||
for _, i := range toClear {
|
||||
newState.BacklogState = bitSet(newState.BacklogState).clear(i)
|
||||
}
|
||||
|
||||
// sync to db (must be persisted before taking effect)
|
||||
if err := sm.scaleDB.UpdateScaleState(newState, true); err != nil {
|
||||
sm.logger.Error("failed to update state", tag.Error(err), tag.Operation("drain"))
|
||||
return
|
||||
}
|
||||
|
||||
sm.logger.Info("drain",
|
||||
tag.Any("drained-partitions", toClear),
|
||||
tag.Int32("target", info.Write),
|
||||
tag.Int32("prev-read", info.Read),
|
||||
tag.Int32("read", bitSet(newState.BacklogState).len()))
|
||||
|
||||
sm.setState(newState)
|
||||
}
|
||||
|
||||
func partitionIsFullyDrained(
|
||||
res *matchingservice.DescribeTaskQueuePartitionResponse,
|
||||
info *taskqueuespb.PartitionScaleInfo,
|
||||
) bool {
|
||||
// Require that the partition agrees with the current scale state, i.e. it knows that
|
||||
// it's draining, i.e. it knows it can't accept any new tasks. We include the version
|
||||
// as well as just the read+write counts to avoid an ABA problem.
|
||||
resInfo := res.GetScaleInfo()
|
||||
if resInfo == nil ||
|
||||
resInfo.Version != info.Version ||
|
||||
resInfo.Read != info.Read ||
|
||||
resInfo.Write != info.Write {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, v := range res.GetVersionsInfoInternal() {
|
||||
for _, q := range v.GetPhysicalTaskQueueInfo().GetInternalTaskQueueStatus() {
|
||||
if !q.GetBacklogDrained() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func scaleStateToReadCount(scaleState *persistencespb.PartitionScaleState) int32 {
|
||||
return max(scaleState.GetTarget(), bitSet(scaleState.GetBacklogState()).len())
|
||||
}
|
||||
|
||||
func scaleStateToInfo(scaleState *persistencespb.PartitionScaleState) *taskqueuespb.PartitionScaleInfo {
|
||||
// note if scaleState == nil, read and write will both be 0
|
||||
return &taskqueuespb.PartitionScaleInfo{
|
||||
Read: scaleStateToReadCount(scaleState),
|
||||
Write: scaleState.GetTarget(),
|
||||
Version: scaleState.GetTargetVersion(),
|
||||
}
|
||||
}
|
||||
55
service/matching/scale_manager_mock.go
Normal file
55
service/matching/scale_manager_mock.go
Normal file
@@ -0,0 +1,55 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: scale_manager.go
|
||||
//
|
||||
// Generated by this command:
|
||||
//
|
||||
// mockgen -package matching -source scale_manager.go -destination scale_manager_mock.go
|
||||
//
|
||||
|
||||
// Package matching is a generated GoMock package.
|
||||
package matching
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
persistence "go.temporal.io/server/api/persistence/v1"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockscaleDB is a mock of scaleDB interface.
|
||||
type MockscaleDB struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockscaleDBMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockscaleDBMockRecorder is the mock recorder for MockscaleDB.
|
||||
type MockscaleDBMockRecorder struct {
|
||||
mock *MockscaleDB
|
||||
}
|
||||
|
||||
// NewMockscaleDB creates a new mock instance.
|
||||
func NewMockscaleDB(ctrl *gomock.Controller) *MockscaleDB {
|
||||
mock := &MockscaleDB{ctrl: ctrl}
|
||||
mock.recorder = &MockscaleDBMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockscaleDB) EXPECT() *MockscaleDBMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// UpdateScaleState mocks base method.
|
||||
func (m *MockscaleDB) UpdateScaleState(arg0 *persistence.PartitionScaleState, arg1 bool) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateScaleState", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UpdateScaleState indicates an expected call of UpdateScaleState.
|
||||
func (mr *MockscaleDBMockRecorder) UpdateScaleState(arg0, arg1 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateScaleState", reflect.TypeOf((*MockscaleDB)(nil).UpdateScaleState), arg0, arg1)
|
||||
}
|
||||
521
service/matching/scale_manager_test.go
Normal file
521
service/matching/scale_manager_test.go
Normal file
@@ -0,0 +1,521 @@
|
||||
package matching
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
enumspb "go.temporal.io/api/enums/v1"
|
||||
"go.temporal.io/server/api/matchingservice/v1"
|
||||
"go.temporal.io/server/api/matchingservicemock/v1"
|
||||
persistencespb "go.temporal.io/server/api/persistence/v1"
|
||||
taskqueuespb "go.temporal.io/server/api/taskqueue/v1"
|
||||
"go.temporal.io/server/common"
|
||||
"go.temporal.io/server/common/clock"
|
||||
"go.temporal.io/server/common/dynamicconfig"
|
||||
"go.temporal.io/server/common/log"
|
||||
"go.temporal.io/server/common/metrics"
|
||||
"go.temporal.io/server/common/testing/await"
|
||||
"go.temporal.io/server/common/testing/protorequire"
|
||||
"go.temporal.io/server/common/testing/protoutils"
|
||||
"go.temporal.io/server/common/tqid"
|
||||
"go.uber.org/mock/gomock"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
||||
type ScaleManagerSuite struct {
|
||||
suite.Suite
|
||||
protorequire.ProtoAssertions
|
||||
controller *gomock.Controller
|
||||
scaler *MockPartitionScaler
|
||||
scaleDB *MockscaleDB
|
||||
userData *MockuserDataManager
|
||||
matching *matchingservicemock.MockMatchingServiceClient
|
||||
timeSource *clock.EventTimeSource
|
||||
|
||||
sm *scaleManager
|
||||
settings dynamicconfig.PartitionScaleManagerSettings
|
||||
}
|
||||
|
||||
func TestScaleManagerSuite(t *testing.T) {
|
||||
suite.Run(t, new(ScaleManagerSuite))
|
||||
}
|
||||
|
||||
func (s *ScaleManagerSuite) SetupTest() {
|
||||
s.ProtoAssertions = protorequire.New(s.T())
|
||||
s.controller = gomock.NewController(s.T())
|
||||
s.scaler = NewMockPartitionScaler(s.controller)
|
||||
s.scaleDB = NewMockscaleDB(s.controller)
|
||||
s.userData = NewMockuserDataManager(s.controller)
|
||||
s.matching = matchingservicemock.NewMockMatchingServiceClient(s.controller)
|
||||
s.timeSource = clock.NewEventTimeSource()
|
||||
|
||||
// scaler.Stop is called from sm.Stop in TearDownTest, but only if the test
|
||||
// actually started the manager.
|
||||
s.scaler.EXPECT().Stop().AnyTimes()
|
||||
|
||||
s.settings = dynamicconfig.PartitionScaleManagerSettings{
|
||||
MaxRate: 10, // 100ms cooldown
|
||||
BatchSize: 1,
|
||||
BackgroundInterval: time.Hour, // disabled by default
|
||||
DrainBufferTime: time.Hour, // disabled by default
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScaleManagerSuite) TearDownTest() {
|
||||
if s.sm != nil {
|
||||
s.sm.Stop()
|
||||
// wait for the worker to actually exit, otherwise mock callbacks may
|
||||
// race with controller.Finish
|
||||
<-s.sm.background.Done()
|
||||
s.sm = nil
|
||||
}
|
||||
}
|
||||
|
||||
// startManager builds and starts the scaleManager. Call this after configuring
|
||||
// EXPECTs and tweaking s.settings. Pass initial=nil to start with no prior state.
|
||||
func (s *ScaleManagerSuite) startManager(writePartitions int, initial *persistencespb.PartitionScaleState) {
|
||||
s.sm = newScaleManager(
|
||||
context.Background(),
|
||||
tqid.MustNormalPartitionFromRpcName("tq", "ns-id", enumspb.TASK_QUEUE_TYPE_WORKFLOW),
|
||||
log.NewTestLogger(),
|
||||
metrics.NoopMetricsHandler,
|
||||
s.userData,
|
||||
s.matching,
|
||||
s.scaler,
|
||||
s.timeSource,
|
||||
dynamicconfig.GetTypedPropertyFn(s.settings),
|
||||
dynamicconfig.GetIntPropertyFn(writePartitions),
|
||||
dynamicconfig.GetBoolPropertyFn(false),
|
||||
)
|
||||
s.sm.Start(initial, s.scaleDB)
|
||||
}
|
||||
|
||||
// fireBackgroundTimer waits for the worker to register its periodic timer and
|
||||
// then advances the fake clock past the timer's deadline.
|
||||
func (s *ScaleManagerSuite) fireBackgroundTimer() {
|
||||
await.RequireTruef(s.T(), func() bool { return s.timeSource.NumTimers() >= 1 },
|
||||
time.Second, time.Millisecond,
|
||||
"worker never registered a periodic timer")
|
||||
// BackgroundInterval has up to 5% jitter; advance comfortably past it.
|
||||
s.timeSource.Advance(s.settings.BackgroundInterval*2 + time.Millisecond)
|
||||
}
|
||||
|
||||
// waitRecv blocks until ch yields a value, failing the test on timeout.
|
||||
func waitRecv[T any](s *ScaleManagerSuite, ch <-chan T, msg string) T {
|
||||
s.T().Helper()
|
||||
select {
|
||||
case v := <-ch:
|
||||
return v
|
||||
case <-time.After(2 * time.Second):
|
||||
s.FailNow("timed out waiting", msg)
|
||||
var zero T
|
||||
return zero
|
||||
}
|
||||
}
|
||||
|
||||
// assertNoRecv asserts that ch yields no value within d.
|
||||
func assertNoRecv[T any](s *ScaleManagerSuite, ch <-chan T, d time.Duration, msg string) {
|
||||
s.T().Helper()
|
||||
select {
|
||||
case <-ch:
|
||||
s.FailNow("unexpected event", msg)
|
||||
case <-time.After(d):
|
||||
}
|
||||
}
|
||||
|
||||
// --- tests ---
|
||||
|
||||
// TestAddedTasksWakesScalerOnFullBatch verifies that the scaler is only called
|
||||
// once cumulative batch reaches numTasks*BatchSize.
|
||||
func (s *ScaleManagerSuite) TestAddedTasksWakesScalerOnFullBatch() {
|
||||
s.settings.BatchSize = 5
|
||||
|
||||
inputs := make(chan PartitionScalerInput, 1)
|
||||
s.scaler.EXPECT().OnTasks(gomock.Any()).
|
||||
Do(func(in PartitionScalerInput) { inputs <- in }).
|
||||
Return(PartitionScalerDecision{NoChange: true}).AnyTimes()
|
||||
|
||||
s.startManager(4, nil)
|
||||
|
||||
for range 4 {
|
||||
s.sm.AddedTasks(1)
|
||||
}
|
||||
assertNoRecv(s, inputs, 30*time.Millisecond, "scaler called below threshold")
|
||||
|
||||
s.sm.AddedTasks(1) // cumulative 5 hits threshold
|
||||
in := waitRecv(s, inputs, "scaler never called")
|
||||
s.Equal(5, in.NumTasks, "all 5 tasks should accumulate before firing")
|
||||
}
|
||||
|
||||
// TestPeriodicTimerCallsScaler verifies that the scaler is called periodically
|
||||
// even with no AddedTasks activity (so we can scale down).
|
||||
func (s *ScaleManagerSuite) TestPeriodicTimerCallsScaler() {
|
||||
s.settings.BackgroundInterval = 50 * time.Millisecond
|
||||
|
||||
inputs := make(chan PartitionScalerInput, 4)
|
||||
s.scaler.EXPECT().OnTasks(gomock.Any()).
|
||||
Do(func(in PartitionScalerInput) {
|
||||
select {
|
||||
case inputs <- in:
|
||||
default: // ignore the rest
|
||||
}
|
||||
}).
|
||||
Return(PartitionScalerDecision{NoChange: true}).
|
||||
MinTimes(1)
|
||||
|
||||
s.startManager(4, nil)
|
||||
s.fireBackgroundTimer()
|
||||
|
||||
in := waitRecv(s, inputs, "scaler never called")
|
||||
s.Zero(in.NumTasks)
|
||||
}
|
||||
|
||||
// TestDecisionPersistsAndUpdatesEphemeralData verifies the full happy path.
|
||||
// When prevTarget was 0, BacklogState should also cover all partitions from
|
||||
// dynamic config (not just the new target).
|
||||
func (s *ScaleManagerSuite) TestDecisionPersistsAndUpdatesEphemeralData() {
|
||||
s.scaler.EXPECT().OnTasks(gomock.Any()).
|
||||
Return(PartitionScalerDecision{NewTarget: 2})
|
||||
|
||||
dbWrites := make(chan *persistencespb.PartitionScaleState, 1)
|
||||
s.scaleDB.EXPECT().UpdateScaleState(gomock.Any(), gomock.Any()).
|
||||
Do(func(state *persistencespb.PartitionScaleState, _ bool) {
|
||||
dbWrites <- common.CloneProto(state)
|
||||
}).
|
||||
Return(nil)
|
||||
|
||||
scaleInfos := make(chan *taskqueuespb.PartitionScaleInfo, 1)
|
||||
s.userData.EXPECT().SetPartitionScale(gomock.Any()).
|
||||
Do(func(info *taskqueuespb.PartitionScaleInfo) { scaleInfos <- info })
|
||||
|
||||
s.startManager(4, nil) // 4 write partitions in dynamic config
|
||||
|
||||
s.sm.AddedTasks(1)
|
||||
state := waitRecv(s, dbWrites, "no db write")
|
||||
s.Equal(int32(2), state.Target)
|
||||
s.Equal(int32(2), state.MaxTarget)
|
||||
s.Equal(s.timeSource.Now().UnixNano(), state.TargetVersion)
|
||||
s.Equal(int32(4), bitSet(state.BacklogState).len(),
|
||||
"BacklogState should cover all dynamic-config write partitions on initial scale-up")
|
||||
|
||||
info := waitRecv(s, scaleInfos, "no ephemeral data update")
|
||||
s.Equal(int32(4), info.Read)
|
||||
s.Equal(int32(2), info.Write)
|
||||
}
|
||||
|
||||
// TestNoChangeDecisionSkipsWrite covers two skip paths: explicit NoChange, and
|
||||
// a decision whose NewTarget equals the current target. Neither should cause
|
||||
// a DB write or an ephemeral data update.
|
||||
func (s *ScaleManagerSuite) TestNoChangeDecisionSkipsWrite() {
|
||||
inputs := make(chan PartitionScalerInput, 2)
|
||||
gomock.InOrder(
|
||||
s.scaler.EXPECT().OnTasks(gomock.Any()).
|
||||
Do(func(in PartitionScalerInput) { inputs <- in }).
|
||||
Return(PartitionScalerDecision{NoChange: true}),
|
||||
s.scaler.EXPECT().OnTasks(gomock.Any()).
|
||||
Do(func(in PartitionScalerInput) { inputs <- in }).
|
||||
Return(PartitionScalerDecision{NewTarget: 3}), // same as current
|
||||
)
|
||||
|
||||
var dbWrites, scalePushes atomic.Int32
|
||||
s.scaleDB.EXPECT().UpdateScaleState(gomock.Any(), gomock.Any()).
|
||||
DoAndReturn(func(*persistencespb.PartitionScaleState, bool) error {
|
||||
dbWrites.Add(1)
|
||||
return nil
|
||||
}).AnyTimes()
|
||||
s.userData.EXPECT().SetPartitionScale(gomock.Any()).
|
||||
Do(func(*taskqueuespb.PartitionScaleInfo) { scalePushes.Add(1) }).AnyTimes()
|
||||
|
||||
s.startManager(4, &persistencespb.PartitionScaleState{Target: 3})
|
||||
|
||||
// Start pushes ephemeral data once (Read/Write change 0 → 3).
|
||||
await.RequireTrue(s.T(), func() bool { return scalePushes.Load() >= 1 },
|
||||
time.Second, time.Millisecond)
|
||||
baseline := scalePushes.Load()
|
||||
|
||||
s.sm.AddedTasks(1)
|
||||
waitRecv(s, inputs, "first decision never delivered")
|
||||
s.sm.AddedTasks(1)
|
||||
waitRecv(s, inputs, "second decision never delivered")
|
||||
|
||||
s.Require().Never(func() bool {
|
||||
return dbWrites.Load() > 0 || scalePushes.Load() > baseline
|
||||
}, 30*time.Millisecond, time.Millisecond, "unexpected DB write or ephemeral push")
|
||||
}
|
||||
|
||||
// TestCooldown verifies that after a decision the scaler is not called again
|
||||
// until 1/MaxRate of fake time has elapsed, and that batched tasks accumulate
|
||||
// across the cooldown window rather than being dropped.
|
||||
func (s *ScaleManagerSuite) TestCooldown() {
|
||||
// MaxRate=10 → 100ms cooldown.
|
||||
inputs := make(chan PartitionScalerInput, 2)
|
||||
gomock.InOrder(
|
||||
s.scaler.EXPECT().OnTasks(gomock.Any()).
|
||||
Do(func(in PartitionScalerInput) { inputs <- in }).
|
||||
Return(PartitionScalerDecision{NewTarget: 2}),
|
||||
s.scaler.EXPECT().OnTasks(gomock.Any()).
|
||||
Do(func(in PartitionScalerInput) { inputs <- in }).
|
||||
Return(PartitionScalerDecision{NewTarget: 4}),
|
||||
)
|
||||
|
||||
dbWrites := make(chan *persistencespb.PartitionScaleState, 2)
|
||||
s.scaleDB.EXPECT().UpdateScaleState(gomock.Any(), gomock.Any()).
|
||||
Do(func(state *persistencespb.PartitionScaleState, _ bool) {
|
||||
dbWrites <- common.CloneProto(state)
|
||||
}).
|
||||
Return(nil).Times(2)
|
||||
|
||||
s.userData.EXPECT().SetPartitionScale(gomock.Any()).AnyTimes()
|
||||
|
||||
s.startManager(4, nil)
|
||||
|
||||
// First decision lands immediately (lastDecision is zero, no cooldown).
|
||||
s.sm.AddedTasks(1)
|
||||
in1 := waitRecv(s, inputs, "first decision never delivered")
|
||||
s.Equal(1, in1.NumTasks)
|
||||
waitRecv(s, dbWrites, "first db write missing")
|
||||
|
||||
// Within cooldown: another wakeup carrying 7 tasks. Scaler must NOT be
|
||||
// called, and tasks must accumulate (batch is only swapped when scaler runs).
|
||||
s.sm.AddedTasks(7)
|
||||
assertNoRecv(s, inputs, 30*time.Millisecond, "scaler called inside cooldown")
|
||||
|
||||
// Advance fake time past cooldown. Trigger another wakeup; the scaler
|
||||
// should now be called with the accumulated 8 tasks.
|
||||
s.timeSource.Advance(110 * time.Millisecond)
|
||||
s.sm.AddedTasks(1)
|
||||
in2 := waitRecv(s, inputs, "second decision never delivered")
|
||||
s.Equal(8, in2.NumTasks)
|
||||
w2 := waitRecv(s, dbWrites, "second db write missing")
|
||||
s.Equal(int32(4), w2.Target)
|
||||
}
|
||||
|
||||
// TestPrivateStatePropagation verifies that PrivateState produced by one
|
||||
// decision is fed back to the scaler on the next call (and persisted).
|
||||
func (s *ScaleManagerSuite) TestPrivateStatePropagation() {
|
||||
priv1 := protoutils.MarshalAny(s.T(), wrapperspb.String("after-decision-1"))
|
||||
priv2 := protoutils.MarshalAny(s.T(), wrapperspb.String("after-decision-2"))
|
||||
|
||||
inputs := make(chan PartitionScalerInput, 2)
|
||||
gomock.InOrder(
|
||||
s.scaler.EXPECT().OnTasks(gomock.Any()).
|
||||
Do(func(in PartitionScalerInput) { inputs <- in }).
|
||||
Return(PartitionScalerDecision{NewTarget: 2, PrivateState: priv1}),
|
||||
s.scaler.EXPECT().OnTasks(gomock.Any()).
|
||||
Do(func(in PartitionScalerInput) { inputs <- in }).
|
||||
Return(PartitionScalerDecision{NewTarget: 4, PrivateState: priv2}),
|
||||
)
|
||||
|
||||
dbWrites := make(chan *persistencespb.PartitionScaleState, 2)
|
||||
s.scaleDB.EXPECT().UpdateScaleState(gomock.Any(), gomock.Any()).
|
||||
Do(func(state *persistencespb.PartitionScaleState, _ bool) {
|
||||
dbWrites <- common.CloneProto(state)
|
||||
}).
|
||||
Return(nil).Times(2)
|
||||
|
||||
s.userData.EXPECT().SetPartitionScale(gomock.Any()).AnyTimes()
|
||||
|
||||
s.startManager(4, nil)
|
||||
|
||||
s.sm.AddedTasks(1)
|
||||
in1 := waitRecv(s, inputs, "first call missing")
|
||||
s.Nil(in1.PrivateState, "first call should have no private state")
|
||||
waitRecv(s, dbWrites, "first db write missing")
|
||||
|
||||
s.timeSource.Advance(110 * time.Millisecond) // past 100ms cooldown
|
||||
s.sm.AddedTasks(1)
|
||||
in2 := waitRecv(s, inputs, "second call missing")
|
||||
s.ProtoEqual(priv1, in2.PrivateState)
|
||||
w2 := waitRecv(s, dbWrites, "second db write missing")
|
||||
s.ProtoEqual(priv2, w2.PrivateScalerState)
|
||||
}
|
||||
|
||||
// TestDrainClearsBacklogBits verifies that partitions which report as fully
|
||||
// drained have their BacklogState bits cleared on the next periodic drain check.
|
||||
func (s *ScaleManagerSuite) TestDrainClearsBacklogBits() {
|
||||
s.settings.BackgroundInterval = 50 * time.Millisecond
|
||||
s.settings.DrainBufferTime = 0
|
||||
|
||||
initial := &persistencespb.PartitionScaleState{
|
||||
Target: 2,
|
||||
MaxTarget: 4,
|
||||
TargetVersion: 0, // fake clock starts at Unix zero
|
||||
BacklogState: bitSet(nil).set(0).set(1).set(2).set(3),
|
||||
}
|
||||
// scaleStateToInfo for the initial state has Read=4, Write=2.
|
||||
drainedResp := &matchingservice.DescribeTaskQueuePartitionResponse{
|
||||
ScaleInfo: &taskqueuespb.PartitionScaleInfo{Read: 4, Write: 2, Version: 0},
|
||||
VersionsInfoInternal: map[string]*taskqueuespb.TaskQueueVersionInfoInternal{
|
||||
"v1": {
|
||||
PhysicalTaskQueueInfo: &taskqueuespb.PhysicalTaskQueueInfo{
|
||||
InternalTaskQueueStatus: []*taskqueuespb.InternalTaskQueueStatus{
|
||||
{BacklogDrained: true},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
s.matching.EXPECT().DescribeTaskQueuePartition(gomock.Any(), gomock.Any()).
|
||||
Return(drainedResp, nil).AnyTimes()
|
||||
|
||||
// Timer-driven path also calls the scaler (with NumTasks=0). It returns
|
||||
// NoChange so no decision-driven DB write happens — only the drain write.
|
||||
s.scaler.EXPECT().OnTasks(gomock.Any()).
|
||||
Return(PartitionScalerDecision{NoChange: true}).AnyTimes()
|
||||
|
||||
dbWrites := make(chan *persistencespb.PartitionScaleState, 1)
|
||||
s.scaleDB.EXPECT().UpdateScaleState(gomock.Any(), gomock.Any()).
|
||||
Do(func(state *persistencespb.PartitionScaleState, _ bool) {
|
||||
dbWrites <- common.CloneProto(state)
|
||||
}).
|
||||
Return(nil)
|
||||
|
||||
// One ephemeral push from Start (0 → Read=4/Write=2), one from the drain (Read drops to 2).
|
||||
s.userData.EXPECT().SetPartitionScale(gomock.Any()).Times(2)
|
||||
|
||||
s.startManager(4, initial)
|
||||
s.fireBackgroundTimer()
|
||||
|
||||
state := waitRecv(s, dbWrites, "drain never wrote")
|
||||
s.Equal(int32(2), state.Target, "target should not change during drain")
|
||||
// Drained ids 2 and 3 should be cleared; ids 0 and 1 stay set (id < target).
|
||||
s.Equal(int32(2), bitSet(state.BacklogState).len())
|
||||
s.True(bitSet(state.BacklogState).get(0))
|
||||
s.True(bitSet(state.BacklogState).get(1))
|
||||
s.False(bitSet(state.BacklogState).get(2))
|
||||
s.False(bitSet(state.BacklogState).get(3))
|
||||
}
|
||||
|
||||
// TestNoDrainWithBacklog verifies that partitions still reporting backlog
|
||||
// (BacklogDrained=false) keep their bits set.
|
||||
func (s *ScaleManagerSuite) TestNoDrainWithBacklog() {
|
||||
s.settings.BackgroundInterval = 50 * time.Millisecond
|
||||
s.settings.DrainBufferTime = 0
|
||||
|
||||
initial := &persistencespb.PartitionScaleState{
|
||||
Target: 2,
|
||||
MaxTarget: 4,
|
||||
TargetVersion: 0,
|
||||
BacklogState: bitSet(nil).set(0).set(1).set(2).set(3),
|
||||
}
|
||||
notDrainedResp := &matchingservice.DescribeTaskQueuePartitionResponse{
|
||||
ScaleInfo: &taskqueuespb.PartitionScaleInfo{Read: 4, Write: 2, Version: 0},
|
||||
VersionsInfoInternal: map[string]*taskqueuespb.TaskQueueVersionInfoInternal{
|
||||
"v1": {
|
||||
PhysicalTaskQueueInfo: &taskqueuespb.PhysicalTaskQueueInfo{
|
||||
InternalTaskQueueStatus: []*taskqueuespb.InternalTaskQueueStatus{
|
||||
{BacklogDrained: false},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
s.matching.EXPECT().DescribeTaskQueuePartition(gomock.Any(), gomock.Any()).
|
||||
Return(notDrainedResp, nil).AnyTimes()
|
||||
|
||||
s.scaler.EXPECT().OnTasks(gomock.Any()).
|
||||
Return(PartitionScalerDecision{NoChange: true}).AnyTimes()
|
||||
|
||||
// Only the push on Start (0 → Read=4/Write=2) is expected.
|
||||
s.userData.EXPECT().SetPartitionScale(gomock.Any()).AnyTimes()
|
||||
|
||||
var dbWrites atomic.Int32
|
||||
s.scaleDB.EXPECT().UpdateScaleState(gomock.Any(), gomock.Any()).
|
||||
DoAndReturn(func(*persistencespb.PartitionScaleState, bool) error {
|
||||
dbWrites.Add(1)
|
||||
return nil
|
||||
}).AnyTimes()
|
||||
|
||||
s.startManager(4, initial)
|
||||
s.fireBackgroundTimer()
|
||||
|
||||
s.Require().Never(func() bool { return dbWrites.Load() > 0 },
|
||||
30*time.Millisecond, time.Millisecond, "drain wrote despite backlog")
|
||||
}
|
||||
|
||||
// TestDrainSkippedDuringBufferTime verifies that drain is not evaluated until
|
||||
// DrainBufferTime has passed since the last target change.
|
||||
func (s *ScaleManagerSuite) TestDrainSkippedDuringBufferTime() {
|
||||
s.settings.BackgroundInterval = 50 * time.Millisecond
|
||||
s.settings.DrainBufferTime = time.Hour // never elapses
|
||||
|
||||
initial := &persistencespb.PartitionScaleState{
|
||||
Target: 2,
|
||||
MaxTarget: 4,
|
||||
TargetVersion: 0,
|
||||
BacklogState: bitSet(nil).set(0).set(1).set(2).set(3),
|
||||
}
|
||||
s.matching.EXPECT().DescribeTaskQueuePartition(gomock.Any(), gomock.Any()).
|
||||
Return(&matchingservice.DescribeTaskQueuePartitionResponse{}, nil).AnyTimes()
|
||||
|
||||
s.scaler.EXPECT().OnTasks(gomock.Any()).
|
||||
Return(PartitionScalerDecision{NoChange: true}).AnyTimes()
|
||||
|
||||
s.userData.EXPECT().SetPartitionScale(gomock.Any()).AnyTimes()
|
||||
|
||||
var dbWrites atomic.Int32
|
||||
s.scaleDB.EXPECT().UpdateScaleState(gomock.Any(), gomock.Any()).
|
||||
DoAndReturn(func(*persistencespb.PartitionScaleState, bool) error {
|
||||
dbWrites.Add(1)
|
||||
return nil
|
||||
}).AnyTimes()
|
||||
|
||||
s.startManager(4, initial)
|
||||
s.fireBackgroundTimer()
|
||||
|
||||
s.Require().Never(func() bool { return dbWrites.Load() > 0 },
|
||||
30*time.Millisecond, time.Millisecond, "drain wrote inside DrainBufferTime")
|
||||
}
|
||||
|
||||
// TestDBWriteFailureKeepsState verifies that when persistence fails the
|
||||
// in-memory state and ephemeral data are not advanced. A subsequent successful
|
||||
// write should then update both.
|
||||
func (s *ScaleManagerSuite) TestDBWriteFailureKeepsState() {
|
||||
inputs := make(chan PartitionScalerInput, 2)
|
||||
gomock.InOrder(
|
||||
s.scaler.EXPECT().OnTasks(gomock.Any()).
|
||||
Do(func(in PartitionScalerInput) { inputs <- in }).
|
||||
Return(PartitionScalerDecision{NewTarget: 2}),
|
||||
s.scaler.EXPECT().OnTasks(gomock.Any()).
|
||||
Do(func(in PartitionScalerInput) { inputs <- in }).
|
||||
Return(PartitionScalerDecision{NewTarget: 3}),
|
||||
)
|
||||
|
||||
dbWrites := make(chan *persistencespb.PartitionScaleState, 1)
|
||||
gomock.InOrder(
|
||||
s.scaleDB.EXPECT().UpdateScaleState(gomock.Any(), gomock.Any()).
|
||||
Return(errors.New("boom")),
|
||||
s.scaleDB.EXPECT().UpdateScaleState(gomock.Any(), gomock.Any()).
|
||||
Do(func(state *persistencespb.PartitionScaleState, _ bool) {
|
||||
dbWrites <- common.CloneProto(state)
|
||||
}).
|
||||
Return(nil),
|
||||
)
|
||||
|
||||
// Only the successful write triggers an ephemeral push (first attempt is
|
||||
// dropped before setState).
|
||||
scaleInfos := make(chan *taskqueuespb.PartitionScaleInfo, 1)
|
||||
s.userData.EXPECT().SetPartitionScale(gomock.Any()).
|
||||
Do(func(info *taskqueuespb.PartitionScaleInfo) { scaleInfos <- info })
|
||||
|
||||
s.startManager(4, nil)
|
||||
|
||||
// First decision: scaler called, DB write fails. lastDecision is not set,
|
||||
// so cooldown is not engaged.
|
||||
s.sm.AddedTasks(1)
|
||||
waitRecv(s, inputs, "first decision missing")
|
||||
|
||||
// No ephemeral push yet; the failed write must not have advanced state.
|
||||
assertNoRecv(s, scaleInfos, 30*time.Millisecond, "ephemeral data pushed after failed write")
|
||||
|
||||
// Recovery: trigger another decision; this one persists.
|
||||
s.sm.AddedTasks(1)
|
||||
waitRecv(s, inputs, "second decision missing")
|
||||
state := waitRecv(s, dbWrites, "second db write missing")
|
||||
s.Equal(int32(3), state.Target, "second decision's target landed (first was dropped)")
|
||||
waitRecv(s, scaleInfos, "no ephemeral data push after recovery")
|
||||
}
|
||||
@@ -102,6 +102,8 @@ type (
|
||||
// rateLimitManager is used to manage the rate limit for task queues.
|
||||
rateLimitManager *rateLimitManager
|
||||
|
||||
scaleManager *scaleManager
|
||||
|
||||
// loadTime tracks when this partition manager was started, used to prevent
|
||||
// false positives in the no-recent-poller metric for newly loaded queues
|
||||
loadTime time.Time
|
||||
@@ -144,6 +146,32 @@ func newTaskQueuePartitionManager(
|
||||
}
|
||||
}
|
||||
|
||||
// create partition scaler + manager if root
|
||||
var scaleManager *scaleManager
|
||||
if partition.IsRoot() && e.partitionScalerFactory != nil {
|
||||
partitionScaler := e.partitionScalerFactory.New(
|
||||
ns.Name(),
|
||||
partition.TaskQueue().Name(),
|
||||
partition.TaskQueue().TaskType(),
|
||||
)
|
||||
if partitionScaler != nil {
|
||||
baseCtx := headers.SetCallerInfo(context.Background(), headers.NewBackgroundLowCallerInfo(ns.Name().String()))
|
||||
scaleManager = newScaleManager(
|
||||
baseCtx,
|
||||
partition,
|
||||
logger,
|
||||
metricsHandler,
|
||||
userDataManager,
|
||||
e.matchingRawClient,
|
||||
partitionScaler,
|
||||
e.timeSource,
|
||||
tqConfig.PartitionScaleManagerSettings,
|
||||
tqConfig.NumWritePartitions,
|
||||
tqConfig.BreakdownMetricsByTaskQueue,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pm := &taskQueuePartitionManagerImpl{
|
||||
engine: e,
|
||||
partition: partition,
|
||||
@@ -156,6 +184,7 @@ func newTaskQueuePartitionManager(
|
||||
versionedQueues: make(map[PhysicalTaskQueueVersion]physicalTaskQueueManager),
|
||||
userDataManager: userDataManager,
|
||||
rateLimitManager: rateLimitManager,
|
||||
scaleManager: scaleManager,
|
||||
defaultQueueFuture: future.NewFuture[physicalTaskQueueManager](),
|
||||
autoEnableRateLimiter: quotas.NewRateLimiter(1.0/60, 1),
|
||||
taskHooks: taskHooks,
|
||||
@@ -290,6 +319,7 @@ func (pm *taskQueuePartitionManagerImpl) Stop(unloadCause unloadCause) {
|
||||
if pm.cancelAutoEnableSub != nil {
|
||||
pm.cancelAutoEnableSub()
|
||||
}
|
||||
pm.scaleManager.Stop()
|
||||
|
||||
pm.versionedQueuesLock.Lock()
|
||||
for version, vq := range pm.versionedQueues {
|
||||
@@ -313,7 +343,13 @@ func (pm *taskQueuePartitionManagerImpl) Stop(unloadCause unloadCause) {
|
||||
pm.goroGroup.Cancel()
|
||||
}
|
||||
|
||||
func (pm *taskQueuePartitionManagerImpl) checkPartitionCounts(ctx context.Context, forWrite, forwarded bool) error {
|
||||
func (pm *taskQueuePartitionManagerImpl) StartScaleManager(scaleState *persistencespb.PartitionScaleState) {
|
||||
// Note that this must be called before defaultQueue is marked initialized!
|
||||
// Otherwise child partitions will see empty scale info in their first ephemeral data update.
|
||||
pm.scaleManager.Start(scaleState, pm.defaultQueue())
|
||||
}
|
||||
|
||||
func (pm *taskQueuePartitionManagerImpl) checkPartitionCounts(ctx context.Context, forWrite bool) error {
|
||||
normal, ok := pm.partition.(*tqid.NormalPartition)
|
||||
if !ok {
|
||||
return nil // only normal partitions do dynamic scaling
|
||||
@@ -392,6 +428,26 @@ func validatePartitionScaleDrift(
|
||||
return errPartitionCountsStale
|
||||
}
|
||||
|
||||
// signalPartitionScaler sends a signal to the partition scaler that a new task has arrived
|
||||
// (directly from history, not forwarded).
|
||||
func (pm *taskQueuePartitionManagerImpl) signalPartitionScaler() {
|
||||
if pm.scaleManager == nil {
|
||||
return // only run on root partition
|
||||
}
|
||||
scaleInfo := pm.userDataManager.PartitionScale()
|
||||
effectiveWrite := int(scaleInfo.GetWrite())
|
||||
// if no target is set yet, get effective count from dynamic config (matches client behavior)
|
||||
if effectiveWrite == 0 {
|
||||
effectiveWrite = max(1, pm.config.NumWritePartitions())
|
||||
}
|
||||
// we assume that tasks are balanced uniformly across partitions, so if the root has
|
||||
// seen 1 task then all have seen ~1 task, so the whole queue has seen 'effective'
|
||||
// tasks in total.
|
||||
// TODO(dp): this will change when we add non-uniform load balancing. we should eventually
|
||||
// aggregate real stats instead of assuming
|
||||
pm.scaleManager.AddedTasks(effectiveWrite)
|
||||
}
|
||||
|
||||
func (pm *taskQueuePartitionManagerImpl) sendPartitionCountTrailer(ctx context.Context) {
|
||||
// note this sends the trailer even if there is no scale info (i.e. dynamic partition
|
||||
// scaling is not enabled). that will instruct clients to fall back to dynamic config.
|
||||
@@ -401,7 +457,7 @@ func (pm *taskQueuePartitionManagerImpl) sendPartitionCountTrailer(ctx context.C
|
||||
Write: scaleInfo.GetWrite(),
|
||||
}.SetTrailer(ctx)
|
||||
if err != nil {
|
||||
// TODO: this is very noisy in unit tests, figure out how to log it only in non-test
|
||||
// TODO(dp): this is very noisy in unit tests, figure out how to log it only in non-test
|
||||
pm.throttledLogger.Debug("error setting partition count trailer", tag.Error(err))
|
||||
}
|
||||
}
|
||||
@@ -495,9 +551,12 @@ func (pm *taskQueuePartitionManagerImpl) AddTask(
|
||||
params addTaskParams,
|
||||
) (buildId string, syncMatched bool, err error) {
|
||||
defer pm.sendPartitionCountTrailer(ctx)
|
||||
if err := pm.checkPartitionCounts(ctx, true, params.forwardInfo != nil); err != nil {
|
||||
if err := pm.checkPartitionCounts(ctx, true); err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
if params.forwardInfo == nil {
|
||||
pm.signalPartitionScaler()
|
||||
}
|
||||
|
||||
var spoolQueue, syncMatchQueue physicalTaskQueueManager
|
||||
directive := params.taskInfo.GetVersionDirective()
|
||||
@@ -656,7 +715,7 @@ func (pm *taskQueuePartitionManagerImpl) PollTask(
|
||||
pollMetadata *pollMetadata,
|
||||
) (*internalTask, bool, error) {
|
||||
defer pm.sendPartitionCountTrailer(ctx)
|
||||
if err := pm.checkPartitionCounts(ctx, false, pollMetadata.forwardedFrom != ""); err != nil {
|
||||
if err := pm.checkPartitionCounts(ctx, false); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
@@ -935,11 +994,15 @@ func (pm *taskQueuePartitionManagerImpl) DispatchQueryTask(
|
||||
taskID string,
|
||||
request *matchingservice.QueryWorkflowRequest,
|
||||
) (*matchingservice.QueryWorkflowResponse, error) {
|
||||
// query counts as "write" for partition load balancing
|
||||
// TODO(dp): if this partition becomes invalid while the query is blocked, we should cancel the match
|
||||
defer pm.sendPartitionCountTrailer(ctx)
|
||||
if err := pm.checkPartitionCounts(ctx, true, request.ForwardInfo != nil); err != nil {
|
||||
// query counts as "write" for partition load balancing
|
||||
if err := pm.checkPartitionCounts(ctx, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if request.ForwardInfo == nil {
|
||||
pm.signalPartitionScaler()
|
||||
}
|
||||
|
||||
task := newInternalQueryTask(taskID, request)
|
||||
pm.config.setDefaultPriority(task)
|
||||
@@ -983,11 +1046,15 @@ func (pm *taskQueuePartitionManagerImpl) DispatchNexusTask(
|
||||
taskId string,
|
||||
request *matchingservice.DispatchNexusTaskRequest,
|
||||
) (*matchingservice.DispatchNexusTaskResponse, error) {
|
||||
// nexus counts as "write" for partition load balancing
|
||||
// TODO(dp): if this partition becomes invalid while the query is blocked, we should cancel the match
|
||||
defer pm.sendPartitionCountTrailer(ctx)
|
||||
if err := pm.checkPartitionCounts(ctx, true, request.ForwardInfo != nil); err != nil {
|
||||
// nexus counts as "write" for partition load balancing
|
||||
if err := pm.checkPartitionCounts(ctx, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if request.ForwardInfo == nil {
|
||||
pm.signalPartitionScaler()
|
||||
}
|
||||
|
||||
deadline, _ := ctx.Deadline() // If not set by user, our client will set a default.
|
||||
var opDeadline time.Time
|
||||
@@ -1374,6 +1441,7 @@ func (pm *taskQueuePartitionManagerImpl) describe(
|
||||
|
||||
return &matchingservice.DescribeTaskQueuePartitionResponse{
|
||||
VersionsInfoInternal: versionsInfo,
|
||||
ScaleInfo: pm.userDataManager.PartitionScale(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -1775,6 +1843,7 @@ func (pm *taskQueuePartitionManagerImpl) callerInfoContext(ctx context.Context)
|
||||
}
|
||||
|
||||
// ForceLoadAllChildPartitions force-loads known child (read) partitions in new goroutines.
|
||||
// TODO(dp): consider moving this into scaleManager.backgroundWork after auto-scaling is enabled everywhere.
|
||||
func (pm *taskQueuePartitionManagerImpl) ForceLoadAllChildPartitions() {
|
||||
if !pm.partition.IsRoot() {
|
||||
return
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:generate mockgen -package $GOPACKAGE -source $GOFILE -destination user_data_manager_mock.go
|
||||
|
||||
package matching
|
||||
|
||||
import (
|
||||
|
||||
180
service/matching/user_data_manager_mock.go
Normal file
180
service/matching/user_data_manager_mock.go
Normal file
@@ -0,0 +1,180 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: user_data_manager.go
|
||||
//
|
||||
// Generated by this command:
|
||||
//
|
||||
// mockgen -package matching -source user_data_manager.go -destination user_data_manager_mock.go
|
||||
//
|
||||
|
||||
// Package matching is a generated GoMock package.
|
||||
package matching
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
matchingservice "go.temporal.io/server/api/matchingservice/v1"
|
||||
persistence "go.temporal.io/server/api/persistence/v1"
|
||||
taskqueue "go.temporal.io/server/api/taskqueue/v1"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockuserDataManager is a mock of userDataManager interface.
|
||||
type MockuserDataManager struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockuserDataManagerMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockuserDataManagerMockRecorder is the mock recorder for MockuserDataManager.
|
||||
type MockuserDataManagerMockRecorder struct {
|
||||
mock *MockuserDataManager
|
||||
}
|
||||
|
||||
// NewMockuserDataManager creates a new mock instance.
|
||||
func NewMockuserDataManager(ctrl *gomock.Controller) *MockuserDataManager {
|
||||
mock := &MockuserDataManager{ctrl: ctrl}
|
||||
mock.recorder = &MockuserDataManagerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockuserDataManager) EXPECT() *MockuserDataManagerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// CheckTaskQueueUserDataPropagation mocks base method.
|
||||
func (m *MockuserDataManager) CheckTaskQueueUserDataPropagation(arg0 context.Context, arg1 int64, arg2, arg3 int) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CheckTaskQueueUserDataPropagation", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// CheckTaskQueueUserDataPropagation indicates an expected call of CheckTaskQueueUserDataPropagation.
|
||||
func (mr *MockuserDataManagerMockRecorder) CheckTaskQueueUserDataPropagation(arg0, arg1, arg2, arg3 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckTaskQueueUserDataPropagation", reflect.TypeOf((*MockuserDataManager)(nil).CheckTaskQueueUserDataPropagation), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// GetUserData mocks base method.
|
||||
func (m *MockuserDataManager) GetUserData() (*persistence.VersionedTaskQueueUserData, chan struct{}, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetUserData")
|
||||
ret0, _ := ret[0].(*persistence.VersionedTaskQueueUserData)
|
||||
ret1, _ := ret[1].(chan struct{})
|
||||
ret2, _ := ret[2].(error)
|
||||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// GetUserData indicates an expected call of GetUserData.
|
||||
func (mr *MockuserDataManagerMockRecorder) GetUserData() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserData", reflect.TypeOf((*MockuserDataManager)(nil).GetUserData))
|
||||
}
|
||||
|
||||
// HandleGetUserDataRequest mocks base method.
|
||||
func (m *MockuserDataManager) HandleGetUserDataRequest(ctx context.Context, req *matchingservice.GetTaskQueueUserDataRequest) (*matchingservice.GetTaskQueueUserDataResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HandleGetUserDataRequest", ctx, req)
|
||||
ret0, _ := ret[0].(*matchingservice.GetTaskQueueUserDataResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// HandleGetUserDataRequest indicates an expected call of HandleGetUserDataRequest.
|
||||
func (mr *MockuserDataManagerMockRecorder) HandleGetUserDataRequest(ctx, req any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleGetUserDataRequest", reflect.TypeOf((*MockuserDataManager)(nil).HandleGetUserDataRequest), ctx, req)
|
||||
}
|
||||
|
||||
// LocalBacklogPriorityChanged mocks base method.
|
||||
func (m *MockuserDataManager) LocalBacklogPriorityChanged(arg0 map[PhysicalTaskQueueVersion]int64) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "LocalBacklogPriorityChanged", arg0)
|
||||
}
|
||||
|
||||
// LocalBacklogPriorityChanged indicates an expected call of LocalBacklogPriorityChanged.
|
||||
func (mr *MockuserDataManagerMockRecorder) LocalBacklogPriorityChanged(arg0 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LocalBacklogPriorityChanged", reflect.TypeOf((*MockuserDataManager)(nil).LocalBacklogPriorityChanged), arg0)
|
||||
}
|
||||
|
||||
// PartitionScale mocks base method.
|
||||
func (m *MockuserDataManager) PartitionScale() *taskqueue.PartitionScaleInfo {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PartitionScale")
|
||||
ret0, _ := ret[0].(*taskqueue.PartitionScaleInfo)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// PartitionScale indicates an expected call of PartitionScale.
|
||||
func (mr *MockuserDataManagerMockRecorder) PartitionScale() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PartitionScale", reflect.TypeOf((*MockuserDataManager)(nil).PartitionScale))
|
||||
}
|
||||
|
||||
// SetPartitionScale mocks base method.
|
||||
func (m *MockuserDataManager) SetPartitionScale(arg0 *taskqueue.PartitionScaleInfo) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetPartitionScale", arg0)
|
||||
}
|
||||
|
||||
// SetPartitionScale indicates an expected call of SetPartitionScale.
|
||||
func (mr *MockuserDataManagerMockRecorder) SetPartitionScale(arg0 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetPartitionScale", reflect.TypeOf((*MockuserDataManager)(nil).SetPartitionScale), arg0)
|
||||
}
|
||||
|
||||
// Start mocks base method.
|
||||
func (m *MockuserDataManager) Start() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Start")
|
||||
}
|
||||
|
||||
// Start indicates an expected call of Start.
|
||||
func (mr *MockuserDataManagerMockRecorder) Start() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockuserDataManager)(nil).Start))
|
||||
}
|
||||
|
||||
// Stop mocks base method.
|
||||
func (m *MockuserDataManager) Stop() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Stop")
|
||||
}
|
||||
|
||||
// Stop indicates an expected call of Stop.
|
||||
func (mr *MockuserDataManagerMockRecorder) Stop() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockuserDataManager)(nil).Stop))
|
||||
}
|
||||
|
||||
// UpdateUserData mocks base method.
|
||||
func (m *MockuserDataManager) UpdateUserData(ctx context.Context, options UserDataUpdateOptions, updateFn UserDataUpdateFunc) (int64, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateUserData", ctx, options, updateFn)
|
||||
ret0, _ := ret[0].(int64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// UpdateUserData indicates an expected call of UpdateUserData.
|
||||
func (mr *MockuserDataManagerMockRecorder) UpdateUserData(ctx, options, updateFn any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserData", reflect.TypeOf((*MockuserDataManager)(nil).UpdateUserData), ctx, options, updateFn)
|
||||
}
|
||||
|
||||
// WaitUntilInitialized mocks base method.
|
||||
func (m *MockuserDataManager) WaitUntilInitialized(ctx context.Context) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "WaitUntilInitialized", ctx)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// WaitUntilInitialized indicates an expected call of WaitUntilInitialized.
|
||||
func (mr *MockuserDataManagerMockRecorder) WaitUntilInitialized(ctx any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilInitialized", reflect.TypeOf((*MockuserDataManager)(nil).WaitUntilInitialized), ctx)
|
||||
}
|
||||
Reference in New Issue
Block a user