diff --git a/client/clientBean.go b/client/clientBean.go index d2f919a8639..329d678402b 100644 --- a/client/clientBean.go +++ b/client/clientBean.go @@ -33,6 +33,7 @@ import ( "go.temporal.io/api/serviceerror" "go.temporal.io/api/workflowservice/v1" + "google.golang.org/grpc" "go.temporal.io/server/api/adminservice/v1" "go.temporal.io/server/api/historyservice/v1" @@ -48,14 +49,16 @@ type ( // Bean is a collection of clients Bean interface { GetHistoryClient() historyservice.HistoryServiceClient - SetHistoryClient(client historyservice.HistoryServiceClient) GetMatchingClient(namespaceIDToName NamespaceIDToNameFunc) (matchingservice.MatchingServiceClient, error) - SetMatchingClient(client matchingservice.MatchingServiceClient) GetFrontendClient() workflowservice.WorkflowServiceClient - SetFrontendClient(client workflowservice.WorkflowServiceClient) - GetRemoteAdminClient(cluster string) (adminservice.AdminServiceClient, error) - SetRemoteAdminClient(cluster string, client adminservice.AdminServiceClient) - GetRemoteFrontendClient(cluster string) (workflowservice.WorkflowServiceClient, error) + GetRemoteAdminClient(string) (adminservice.AdminServiceClient, error) + SetRemoteAdminClient(string, adminservice.AdminServiceClient) + GetRemoteFrontendClient(string) (grpc.ClientConnInterface, workflowservice.WorkflowServiceClient, error) + } + + frontendClient struct { + connection grpc.ClientConnInterface + workflowservice.WorkflowServiceClient } clientBeanImpl struct { @@ -68,7 +71,7 @@ type ( adminClientsLock sync.RWMutex adminClients map[string]adminservice.AdminServiceClient frontendClientsLock sync.RWMutex - frontendClients map[string]workflowservice.WorkflowServiceClient + frontendClients map[string]frontendClient } ) @@ -81,7 +84,7 @@ func NewClientBean(factory Factory, clusterMetadata cluster.Metadata) (Bean, err } adminClients := map[string]adminservice.AdminServiceClient{} - frontendClients := map[string]workflowservice.WorkflowServiceClient{} + frontendClients := map[string]frontendClient{} currentClusterName := clusterMetadata.GetCurrentClusterName() // Init local cluster client with membership info @@ -92,7 +95,7 @@ func NewClientBean(factory Factory, clusterMetadata cluster.Metadata) (Bean, err if err != nil { return nil, err } - frontendClient, err := factory.NewLocalFrontendClientWithTimeout( + conn, client, err := factory.NewLocalFrontendClientWithTimeout( frontend.DefaultTimeout, frontend.DefaultLongPollTimeout, ) @@ -100,7 +103,10 @@ func NewClientBean(factory Factory, clusterMetadata cluster.Metadata) (Bean, err return nil, err } adminClients[currentClusterName] = adminClient - frontendClients[currentClusterName] = frontendClient + frontendClients[currentClusterName] = frontendClient{ + connection: conn, + WorkflowServiceClient: client, + } for clusterName, info := range clusterMetadata.GetAllClusterInfo() { if !info.Enabled || clusterName == currentClusterName { @@ -111,13 +117,16 @@ func NewClientBean(factory Factory, clusterMetadata cluster.Metadata) (Bean, err admin.DefaultTimeout, admin.DefaultLargeTimeout, ) - frontendClient = factory.NewRemoteFrontendClientWithTimeout( + conn, client = factory.NewRemoteFrontendClientWithTimeout( info.RPCAddress, frontend.DefaultTimeout, frontend.DefaultLongPollTimeout, ) adminClients[clusterName] = adminClient - frontendClients[clusterName] = frontendClient + frontendClients[clusterName] = frontendClient{ + connection: conn, + WorkflowServiceClient: client, + } } bean := &clientBeanImpl{ @@ -154,12 +163,6 @@ func (h *clientBeanImpl) GetHistoryClient() historyservice.HistoryServiceClient return h.historyClient } -func (h *clientBeanImpl) SetHistoryClient( - client historyservice.HistoryServiceClient, -) { - h.historyClient = client -} - func (h *clientBeanImpl) GetMatchingClient(namespaceIDToName NamespaceIDToNameFunc) (matchingservice.MatchingServiceClient, error) { if client := h.matchingClient.Load(); client != nil { return client.(matchingservice.MatchingServiceClient), nil @@ -167,51 +170,42 @@ func (h *clientBeanImpl) GetMatchingClient(namespaceIDToName NamespaceIDToNameFu return h.lazyInitMatchingClient(namespaceIDToName) } -func (h *clientBeanImpl) SetMatchingClient( - client matchingservice.MatchingServiceClient, -) { - h.matchingClient.Store(client) -} - func (h *clientBeanImpl) GetFrontendClient() workflowservice.WorkflowServiceClient { return h.frontendClients[h.clusterMetadata.GetCurrentClusterName()] } -func (h *clientBeanImpl) SetFrontendClient( - client workflowservice.WorkflowServiceClient, -) { - h.frontendClients[h.clusterMetadata.GetCurrentClusterName()] = client -} - func (h *clientBeanImpl) GetRemoteAdminClient(cluster string) (adminservice.AdminServiceClient, error) { h.adminClientsLock.RLock() client, ok := h.adminClients[cluster] h.adminClientsLock.RUnlock() + if ok { + return client, nil + } - if !ok { - clusterInfo, clusterFound := h.clusterMetadata.GetAllClusterInfo()[cluster] - if !clusterFound { - return nil, &serviceerror.NotFound{ - Message: fmt.Sprintf( - "Unknown cluster name: %v with given cluster information map: %v.", - cluster, - clusterInfo, - ), - } + clusterInfo, clusterFound := h.clusterMetadata.GetAllClusterInfo()[cluster] + if !clusterFound { + return nil, &serviceerror.NotFound{ + Message: fmt.Sprintf( + "Unknown cluster name: %v with given cluster information map: %v.", + cluster, + clusterInfo, + ), } + } - h.adminClientsLock.Lock() - defer h.adminClientsLock.Unlock() - client, ok = h.adminClients[cluster] - if !ok { - client = h.factory.NewRemoteAdminClientWithTimeout( - clusterInfo.RPCAddress, - admin.DefaultTimeout, - admin.DefaultLargeTimeout, - ) - h.setRemoteAdminClientLocked(cluster, client) - } + h.adminClientsLock.Lock() + defer h.adminClientsLock.Unlock() + client, ok = h.adminClients[cluster] + if ok { + return client, nil } + + client = h.factory.NewRemoteAdminClientWithTimeout( + clusterInfo.RPCAddress, + admin.DefaultTimeout, + admin.DefaultLargeTimeout, + ) + h.adminClients[cluster] = client return client, nil } @@ -222,46 +216,47 @@ func (h *clientBeanImpl) SetRemoteAdminClient( h.adminClientsLock.Lock() defer h.adminClientsLock.Unlock() - h.setRemoteAdminClientLocked(cluster, client) + h.adminClients[cluster] = client } -func (h *clientBeanImpl) GetRemoteFrontendClient(cluster string) (workflowservice.WorkflowServiceClient, error) { +func (h *clientBeanImpl) GetRemoteFrontendClient(clusterName string) (grpc.ClientConnInterface, workflowservice.WorkflowServiceClient, error) { h.frontendClientsLock.RLock() - client, ok := h.frontendClients[cluster] + client, ok := h.frontendClients[clusterName] h.frontendClientsLock.RUnlock() + if ok { + return client.connection, client, nil + } - if !ok { - clusterInfo, clusterFound := h.clusterMetadata.GetAllClusterInfo()[cluster] - if !clusterFound { - return nil, &serviceerror.NotFound{ - Message: fmt.Sprintf( - "Unknown cluster name: %v with given cluster information map: %v.", - cluster, - clusterInfo, - ), - } + clusterInfo, clusterFound := h.clusterMetadata.GetAllClusterInfo()[clusterName] + if !clusterFound { + return nil, nil, &serviceerror.NotFound{ + Message: fmt.Sprintf( + "Unknown clusterName name: %v with given clusterName information map: %v.", + clusterName, + clusterInfo, + ), } + } - h.frontendClientsLock.Lock() - defer h.frontendClientsLock.Unlock() - client, ok = h.frontendClients[cluster] - if !ok { - client = h.factory.NewRemoteFrontendClientWithTimeout( - clusterInfo.RPCAddress, - frontend.DefaultTimeout, - frontend.DefaultLongPollTimeout, - ) - h.setRemoteFrontendClientLocked(cluster, client) - } + h.frontendClientsLock.Lock() + defer h.frontendClientsLock.Unlock() + + client, ok = h.frontendClients[clusterName] + if ok { + return client.connection, client, nil } - return client, nil -} -func (h *clientBeanImpl) setRemoteFrontendClientLocked( - cluster string, - client workflowservice.WorkflowServiceClient, -) { - h.frontendClients[cluster] = client + conn, fClient := h.factory.NewRemoteFrontendClientWithTimeout( + clusterInfo.RPCAddress, + frontend.DefaultTimeout, + frontend.DefaultLongPollTimeout, + ) + client = frontendClient{ + connection: conn, + WorkflowServiceClient: fClient, + } + h.frontendClients[clusterName] = client + return client.connection, client, nil } func (h *clientBeanImpl) setRemoteAdminClientLocked( diff --git a/client/clientBean_mock.go b/client/clientBean_mock.go index 84b7e7411f3..010865edeb7 100644 --- a/client/clientBean_mock.go +++ b/client/clientBean_mock.go @@ -36,6 +36,7 @@ import ( v10 "go.temporal.io/server/api/adminservice/v1" v11 "go.temporal.io/server/api/historyservice/v1" v12 "go.temporal.io/server/api/matchingservice/v1" + grpc "google.golang.org/grpc" ) // MockBean is a mock of Bean interface. @@ -105,79 +106,44 @@ func (mr *MockBeanMockRecorder) GetMatchingClient(namespaceIDToName interface{}) } // GetRemoteAdminClient mocks base method. -func (m *MockBean) GetRemoteAdminClient(cluster string) (v10.AdminServiceClient, error) { +func (m *MockBean) GetRemoteAdminClient(arg0 string) (v10.AdminServiceClient, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetRemoteAdminClient", cluster) + ret := m.ctrl.Call(m, "GetRemoteAdminClient", arg0) ret0, _ := ret[0].(v10.AdminServiceClient) ret1, _ := ret[1].(error) return ret0, ret1 } // GetRemoteAdminClient indicates an expected call of GetRemoteAdminClient. -func (mr *MockBeanMockRecorder) GetRemoteAdminClient(cluster interface{}) *gomock.Call { +func (mr *MockBeanMockRecorder) GetRemoteAdminClient(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRemoteAdminClient", reflect.TypeOf((*MockBean)(nil).GetRemoteAdminClient), cluster) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRemoteAdminClient", reflect.TypeOf((*MockBean)(nil).GetRemoteAdminClient), arg0) } // GetRemoteFrontendClient mocks base method. -func (m *MockBean) GetRemoteFrontendClient(cluster string) (v1.WorkflowServiceClient, error) { +func (m *MockBean) GetRemoteFrontendClient(arg0 string) (grpc.ClientConnInterface, v1.WorkflowServiceClient, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetRemoteFrontendClient", cluster) - ret0, _ := ret[0].(v1.WorkflowServiceClient) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "GetRemoteFrontendClient", arg0) + ret0, _ := ret[0].(grpc.ClientConnInterface) + ret1, _ := ret[1].(v1.WorkflowServiceClient) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 } // GetRemoteFrontendClient indicates an expected call of GetRemoteFrontendClient. -func (mr *MockBeanMockRecorder) GetRemoteFrontendClient(cluster interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRemoteFrontendClient", reflect.TypeOf((*MockBean)(nil).GetRemoteFrontendClient), cluster) -} - -// SetFrontendClient mocks base method. -func (m *MockBean) SetFrontendClient(client v1.WorkflowServiceClient) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetFrontendClient", client) -} - -// SetFrontendClient indicates an expected call of SetFrontendClient. -func (mr *MockBeanMockRecorder) SetFrontendClient(client interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFrontendClient", reflect.TypeOf((*MockBean)(nil).SetFrontendClient), client) -} - -// SetHistoryClient mocks base method. -func (m *MockBean) SetHistoryClient(client v11.HistoryServiceClient) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetHistoryClient", client) -} - -// SetHistoryClient indicates an expected call of SetHistoryClient. -func (mr *MockBeanMockRecorder) SetHistoryClient(client interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHistoryClient", reflect.TypeOf((*MockBean)(nil).SetHistoryClient), client) -} - -// SetMatchingClient mocks base method. -func (m *MockBean) SetMatchingClient(client v12.MatchingServiceClient) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetMatchingClient", client) -} - -// SetMatchingClient indicates an expected call of SetMatchingClient. -func (mr *MockBeanMockRecorder) SetMatchingClient(client interface{}) *gomock.Call { +func (mr *MockBeanMockRecorder) GetRemoteFrontendClient(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetMatchingClient", reflect.TypeOf((*MockBean)(nil).SetMatchingClient), client) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRemoteFrontendClient", reflect.TypeOf((*MockBean)(nil).GetRemoteFrontendClient), arg0) } // SetRemoteAdminClient mocks base method. -func (m *MockBean) SetRemoteAdminClient(cluster string, client v10.AdminServiceClient) { +func (m *MockBean) SetRemoteAdminClient(arg0 string, arg1 v10.AdminServiceClient) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetRemoteAdminClient", cluster, client) + m.ctrl.Call(m, "SetRemoteAdminClient", arg0, arg1) } // SetRemoteAdminClient indicates an expected call of SetRemoteAdminClient. -func (mr *MockBeanMockRecorder) SetRemoteAdminClient(cluster, client interface{}) *gomock.Call { +func (mr *MockBeanMockRecorder) SetRemoteAdminClient(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRemoteAdminClient", reflect.TypeOf((*MockBean)(nil).SetRemoteAdminClient), cluster, client) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRemoteAdminClient", reflect.TypeOf((*MockBean)(nil).SetRemoteAdminClient), arg0, arg1) } diff --git a/client/clientFactory_mock.go b/client/clientFactory_mock.go index 68fdf3ebcf9..6b379758c20 100644 --- a/client/clientFactory_mock.go +++ b/client/clientFactory_mock.go @@ -42,6 +42,7 @@ import ( log "go.temporal.io/server/common/log" membership "go.temporal.io/server/common/membership" metrics "go.temporal.io/server/common/metrics" + grpc "google.golang.org/grpc" ) // MockFactory is a mock of Factory interface. @@ -98,12 +99,13 @@ func (mr *MockFactoryMockRecorder) NewLocalAdminClientWithTimeout(timeout, large } // NewLocalFrontendClientWithTimeout mocks base method. -func (m *MockFactory) NewLocalFrontendClientWithTimeout(timeout, longPollTimeout time.Duration) (v1.WorkflowServiceClient, error) { +func (m *MockFactory) NewLocalFrontendClientWithTimeout(timeout, longPollTimeout time.Duration) (grpc.ClientConnInterface, v1.WorkflowServiceClient, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "NewLocalFrontendClientWithTimeout", timeout, longPollTimeout) - ret0, _ := ret[0].(v1.WorkflowServiceClient) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret0, _ := ret[0].(grpc.ClientConnInterface) + ret1, _ := ret[1].(v1.WorkflowServiceClient) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 } // NewLocalFrontendClientWithTimeout indicates an expected call of NewLocalFrontendClientWithTimeout. @@ -142,11 +144,12 @@ func (mr *MockFactoryMockRecorder) NewRemoteAdminClientWithTimeout(rpcAddress, t } // NewRemoteFrontendClientWithTimeout mocks base method. -func (m *MockFactory) NewRemoteFrontendClientWithTimeout(rpcAddress string, timeout, longPollTimeout time.Duration) v1.WorkflowServiceClient { +func (m *MockFactory) NewRemoteFrontendClientWithTimeout(rpcAddress string, timeout, longPollTimeout time.Duration) (grpc.ClientConnInterface, v1.WorkflowServiceClient) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "NewRemoteFrontendClientWithTimeout", rpcAddress, timeout, longPollTimeout) - ret0, _ := ret[0].(v1.WorkflowServiceClient) - return ret0 + ret0, _ := ret[0].(grpc.ClientConnInterface) + ret1, _ := ret[1].(v1.WorkflowServiceClient) + return ret0, ret1 } // NewRemoteFrontendClientWithTimeout indicates an expected call of NewRemoteFrontendClientWithTimeout. diff --git a/client/clientfactory.go b/client/clientfactory.go index 187e6d03f82..81a71c68014 100644 --- a/client/clientfactory.go +++ b/client/clientfactory.go @@ -30,6 +30,7 @@ import ( "time" "go.temporal.io/api/workflowservice/v1" + "google.golang.org/grpc" "go.temporal.io/server/api/adminservice/v1" "go.temporal.io/server/api/historyservice/v1" @@ -52,8 +53,8 @@ type ( Factory interface { NewHistoryClientWithTimeout(timeout time.Duration) (historyservice.HistoryServiceClient, error) NewMatchingClientWithTimeout(namespaceIDToName NamespaceIDToNameFunc, timeout time.Duration, longPollTimeout time.Duration) (matchingservice.MatchingServiceClient, error) - NewRemoteFrontendClientWithTimeout(rpcAddress string, timeout time.Duration, longPollTimeout time.Duration) workflowservice.WorkflowServiceClient - NewLocalFrontendClientWithTimeout(timeout time.Duration, longPollTimeout time.Duration) (workflowservice.WorkflowServiceClient, error) + NewRemoteFrontendClientWithTimeout(rpcAddress string, timeout time.Duration, longPollTimeout time.Duration) (grpc.ClientConnInterface, workflowservice.WorkflowServiceClient) + NewLocalFrontendClientWithTimeout(timeout time.Duration, longPollTimeout time.Duration) (grpc.ClientConnInterface, workflowservice.WorkflowServiceClient, error) NewRemoteAdminClientWithTimeout(rpcAddress string, timeout time.Duration, largeTimeout time.Duration) adminservice.AdminServiceClient NewLocalAdminClientWithTimeout(timeout time.Duration, largeTimeout time.Duration) (adminservice.AdminServiceClient, error) } @@ -170,19 +171,19 @@ func (cf *rpcClientFactory) NewRemoteFrontendClientWithTimeout( rpcAddress string, timeout time.Duration, longPollTimeout time.Duration, -) workflowservice.WorkflowServiceClient { +) (grpc.ClientConnInterface, workflowservice.WorkflowServiceClient) { connection := cf.rpcFactory.CreateRemoteFrontendGRPCConnection(rpcAddress) client := workflowservice.NewWorkflowServiceClient(connection) - return cf.newFrontendClient(client, timeout, longPollTimeout) + return connection, cf.newFrontendClient(client, timeout, longPollTimeout) } func (cf *rpcClientFactory) NewLocalFrontendClientWithTimeout( timeout time.Duration, longPollTimeout time.Duration, -) (workflowservice.WorkflowServiceClient, error) { +) (grpc.ClientConnInterface, workflowservice.WorkflowServiceClient, error) { connection := cf.rpcFactory.CreateLocalFrontendGRPCConnection() client := workflowservice.NewWorkflowServiceClient(connection) - return cf.newFrontendClient(client, timeout, longPollTimeout), nil + return connection, cf.newFrontendClient(client, timeout, longPollTimeout), nil } func (cf *rpcClientFactory) NewRemoteAdminClientWithTimeout( diff --git a/common/metrics/metric_defs.go b/common/metrics/metric_defs.go index 0a68768e38a..f9b7a2c447a 100644 --- a/common/metrics/metric_defs.go +++ b/common/metrics/metric_defs.go @@ -198,117 +198,6 @@ const ( // AdminDeleteWorkflowExecutionScope is the metric scope for admin.AdminDeleteWorkflowExecution AdminDeleteWorkflowExecutionScope = "AdminDeleteWorkflowExecution" - // DCRedirectionDeleteWorkflowExecutionScope tracks RPC calls for dc redirection - DCRedirectionDeleteWorkflowExecutionScope = "DCRedirectionDeleteWorkflowExecution" - // DCRedirectionDeprecateNamespaceScope tracks RPC calls for dc redirection - DCRedirectionDeprecateNamespaceScope = "DCRedirectionDeprecateNamespace" - // DCRedirectionDescribeNamespaceScope tracks RPC calls for dc redirection - DCRedirectionDescribeNamespaceScope = "DCRedirectionDescribeNamespace" - // DCRedirectionDescribeTaskQueueScope tracks RPC calls for dc redirection - DCRedirectionDescribeTaskQueueScope = "DCRedirectionDescribeTaskQueue" - // DCRedirectionDescribeWorkflowExecutionScope tracks RPC calls for dc redirection - DCRedirectionDescribeWorkflowExecutionScope = "DCRedirectionDescribeWorkflowExecution" - // DCRedirectionGetWorkflowExecutionHistoryScope tracks RPC calls for dc redirection - DCRedirectionGetWorkflowExecutionHistoryScope = "DCRedirectionGetWorkflowExecutionHistory" - // DCRedirectionGetWorkflowExecutionHistoryReverseScope tracks RPC calls for dc redirection - DCRedirectionGetWorkflowExecutionHistoryReverseScope = "DCRedirectionGetWorkflowExecutionHistoryReverse" - // DCRedirectionGetWorkflowExecutionRawHistoryScope tracks RPC calls for dc redirection - DCRedirectionGetWorkflowExecutionRawHistoryScope = "DCRedirectionGetWorkflowExecutionRawHistory" - // DCRedirectionPollForWorkflowExecutionRawHistoryScope tracks RPC calls for dc redirection - DCRedirectionPollForWorkflowExecutionRawHistoryScope = "DCRedirectionPollForWorkflowExecutionRawHistory" - // DCRedirectionListArchivedWorkflowExecutionsScope tracks RPC calls for dc redirection - DCRedirectionListArchivedWorkflowExecutionsScope = "DCRedirectionListArchivedWorkflowExecutions" - // DCRedirectionListClosedWorkflowExecutionsScope tracks RPC calls for dc redirection - DCRedirectionListClosedWorkflowExecutionsScope = "DCRedirectionListClosedWorkflowExecutions" - // DCRedirectionListNamespacesScope tracks RPC calls for dc redirection - DCRedirectionListNamespacesScope = "DCRedirectionListNamespaces" - // DCRedirectionListOpenWorkflowExecutionsScope tracks RPC calls for dc redirection - DCRedirectionListOpenWorkflowExecutionsScope = "DCRedirectionListOpenWorkflowExecutions" - // DCRedirectionListWorkflowExecutionsScope tracks RPC calls for dc redirection - DCRedirectionListWorkflowExecutionsScope = "DCRedirectionListWorkflowExecutions" - // DCRedirectionScanWorkflowExecutionsScope tracks RPC calls for dc redirection - DCRedirectionScanWorkflowExecutionsScope = "DCRedirectionScanWorkflowExecutions" - // DCRedirectionCountWorkflowExecutionsScope tracks RPC calls for dc redirection - DCRedirectionCountWorkflowExecutionsScope = "DCRedirectionCountWorkflowExecutions" - // DCRedirectionGetSearchAttributesScope tracks RPC calls for dc redirection - DCRedirectionGetSearchAttributesScope = "DCRedirectionGetSearchAttributes" - // DCRedirectionPollActivityTaskQueueScope tracks RPC calls for dc redirection - DCRedirectionPollActivityTaskQueueScope = "DCRedirectionPollActivityTaskQueue" - // DCRedirectionPollWorkflowTaskQueueScope tracks RPC calls for dc redirection - DCRedirectionPollWorkflowTaskQueueScope = "DCRedirectionPollWorkflowTaskQueue" - // DCRedirectionQueryWorkflowScope tracks RPC calls for dc redirection - DCRedirectionQueryWorkflowScope = "DCRedirectionQueryWorkflow" - // DCRedirectionRecordActivityTaskHeartbeatScope tracks RPC calls for dc redirection - DCRedirectionRecordActivityTaskHeartbeatScope = "DCRedirectionRecordActivityTaskHeartbeat" - // DCRedirectionRecordActivityTaskHeartbeatByIdScope tracks RPC calls for dc redirection - DCRedirectionRecordActivityTaskHeartbeatByIdScope = "DCRedirectionRecordActivityTaskHeartbeatById" - // DCRedirectionRegisterNamespaceScope tracks RPC calls for dc redirection - DCRedirectionRegisterNamespaceScope = "DCRedirectionRegisterNamespace" - // DCRedirectionRequestCancelWorkflowExecutionScope tracks RPC calls for dc redirection - DCRedirectionRequestCancelWorkflowExecutionScope = "DCRedirectionRequestCancelWorkflowExecution" - // DCRedirectionResetStickyTaskQueueScope tracks RPC calls for dc redirection - DCRedirectionResetStickyTaskQueueScope = "DCRedirectionResetStickyTaskQueue" - // DCRedirectionResetWorkflowExecutionScope tracks RPC calls for dc redirection - DCRedirectionResetWorkflowExecutionScope = "DCRedirectionResetWorkflowExecution" - // DCRedirectionRespondActivityTaskCanceledScope tracks RPC calls for dc redirection - DCRedirectionRespondActivityTaskCanceledScope = "DCRedirectionRespondActivityTaskCanceled" - // DCRedirectionRespondActivityTaskCanceledByIdScope tracks RPC calls for dc redirection - DCRedirectionRespondActivityTaskCanceledByIdScope = "DCRedirectionRespondActivityTaskCanceledById" - // DCRedirectionRespondActivityTaskCompletedScope tracks RPC calls for dc redirection - DCRedirectionRespondActivityTaskCompletedScope = "DCRedirectionRespondActivityTaskCompleted" - // DCRedirectionRespondActivityTaskCompletedByIdScope tracks RPC calls for dc redirection - DCRedirectionRespondActivityTaskCompletedByIdScope = "DCRedirectionRespondActivityTaskCompletedById" - // DCRedirectionRespondActivityTaskFailedScope tracks RPC calls for dc redirection - DCRedirectionRespondActivityTaskFailedScope = "DCRedirectionRespondActivityTaskFailed" - // DCRedirectionRespondActivityTaskFailedByIdScope tracks RPC calls for dc redirection - DCRedirectionRespondActivityTaskFailedByIdScope = "DCRedirectionRespondActivityTaskFailedById" - // DCRedirectionRespondWorkflowTaskCompletedScope tracks RPC calls for dc redirection - DCRedirectionRespondWorkflowTaskCompletedScope = "DCRedirectionRespondWorkflowTaskCompleted" - // DCRedirectionRespondWorkflowTaskFailedScope tracks RPC calls for dc redirection - DCRedirectionRespondWorkflowTaskFailedScope = "DCRedirectionRespondWorkflowTaskFailed" - // DCRedirectionRespondQueryTaskCompletedScope tracks RPC calls for dc redirection - DCRedirectionRespondQueryTaskCompletedScope = "DCRedirectionRespondQueryTaskCompleted" - // DCRedirectionSignalWithStartWorkflowExecutionScope tracks RPC calls for dc redirection - DCRedirectionSignalWithStartWorkflowExecutionScope = "DCRedirectionSignalWithStartWorkflowExecution" - // DCRedirectionSignalWorkflowExecutionScope tracks RPC calls for dc redirection - DCRedirectionSignalWorkflowExecutionScope = "DCRedirectionSignalWorkflowExecution" - // DCRedirectionStartWorkflowExecutionScope tracks RPC calls for dc redirection - DCRedirectionStartWorkflowExecutionScope = "DCRedirectionStartWorkflowExecution" - // DCRedirectionTerminateWorkflowExecutionScope tracks RPC calls for dc redirection - DCRedirectionTerminateWorkflowExecutionScope = "DCRedirectionTerminateWorkflowExecution" - // DCRedirectionUpdateNamespaceScope tracks RPC calls for dc redirection - DCRedirectionUpdateNamespaceScope = "DCRedirectionUpdateNamespace" - // DCRedirectionListTaskQueuePartitionsScope tracks RPC calls for dc redirection - DCRedirectionListTaskQueuePartitionsScope = "DCRedirectionListTaskQueuePartitions" - // DCRedirectionCreateScheduleScope tracks RPC calls for dc redirection - DCRedirectionCreateScheduleScope = "DCRedirectionCreateSchedule" - // DCRedirectionDescribeScheduleScope tracks RPC calls for dc redirection - DCRedirectionDescribeScheduleScope = "DCRedirectionDescribeSchedule" - // DCRedirectionUpdateScheduleScope tracks RPC calls for dc redirection - DCRedirectionUpdateScheduleScope = "DCRedirectionUpdateSchedule" - // DCRedirectionPatchScheduleScope tracks RPC calls for dc redirection - DCRedirectionPatchScheduleScope = "DCRedirectionPatchSchedule" - // DCRedirectionListScheduleMatchingTimesScope tracks RPC calls for dc redirection - DCRedirectionListScheduleMatchingTimesScope = "DCRedirectionListScheduleMatchingTimes" - // DCRedirectionDeleteScheduleScope tracks RPC calls for dc redirection - DCRedirectionDeleteScheduleScope = "DCRedirectionDeleteSchedule" - // DCRedirectionListSchedulesScope tracks RPC calls for dc redirection - DCRedirectionListSchedulesScope = "DCRedirectionListSchedules" - // DCRedirectionUpdateWorkerBuildIdOrderingScope tracks RPC calls for dc redirection - DCRedirectionUpdateWorkerBuildIdOrderingScope = "DCRedirectionUpdateWorkerBuildIdOrdering" - // DCRedirectionGetWorkerBuildIdOrderingScope tracks RPC calls for dc redirection - DCRedirectionGetWorkerBuildIdOrderingScope = "DCRedirectionGetWorkerBuildIdOrdering" - // DCRedirectionUpdateWorkflowExecutionScope tracks RPC calls for dc redirection - DCRedirectionUpdateWorkflowExecutionScope = "DCRedirectionUpdateWorkflowExecution" - // DCRedirectionDescribeBatchOperationScope tracks RPC calls for dc redirection - DCRedirectionDescribeBatchOperationScope = "DCRedirectionDescribeBatchOperation" - // DCRedirectionListBatchOperationsScope tracks RPC calls for dc redirection - DCRedirectionListBatchOperationsScope = "DCRedirectionListBatchOperations" - // DCRedirectionStartBatchOperationScope tracks RPC calls for dc redirection - DCRedirectionStartBatchOperationScope = "DCRedirectionStartBatchOperation" - // DCRedirectionStopBatchOperationScope tracks RPC calls for dc redirection - DCRedirectionStopBatchOperationScope = "DCRedirectionStopBatchOperation" - // OperatorAddSearchAttributesScope is the metric scope for operator.AddSearchAttributes OperatorAddSearchAttributesScope // OperatorRemoveSearchAttributesScope is the metric scope for operator.RemoveSearchAttributes diff --git a/common/resourcetest/resourceTest.go b/common/resourcetest/resourceTest.go index 488e82fcec8..04f5c71250f 100644 --- a/common/resourcetest/resourceTest.go +++ b/common/resourcetest/resourceTest.go @@ -137,7 +137,7 @@ func NewTest( clientBean.EXPECT().GetMatchingClient(gomock.Any()).Return(matchingClient, nil).AnyTimes() clientBean.EXPECT().GetHistoryClient().Return(historyClient).AnyTimes() clientBean.EXPECT().GetRemoteAdminClient(gomock.Any()).Return(remoteAdminClient, nil).AnyTimes() - clientBean.EXPECT().GetRemoteFrontendClient(gomock.Any()).Return(remoteFrontendClient, nil).AnyTimes() + clientBean.EXPECT().GetRemoteFrontendClient(gomock.Any()).Return(nil, remoteFrontendClient, nil).AnyTimes() clientFactory := client.NewMockFactory(controller) metadataMgr := persistence.NewMockMetadataManager(controller) diff --git a/common/rpc/interceptor/api_name.go b/common/rpc/interceptor/api_name.go index d3627dcd835..ba422613839 100644 --- a/common/rpc/interceptor/api_name.go +++ b/common/rpc/interceptor/api_name.go @@ -26,9 +26,9 @@ package interceptor import "strings" -func splitMethodName( +func SplitMethodName( fullMethodName string, -) (string, string) { +) (_ string, _ string) { fullMethodName = strings.TrimPrefix(fullMethodName, "/") // remove leading slash if i := strings.Index(fullMethodName, "/"); i >= 0 { return fullMethodName[:i], fullMethodName[i+1:] diff --git a/common/rpc/interceptor/caller_info.go b/common/rpc/interceptor/caller_info.go index a53946f9f2b..bc98762bb5f 100644 --- a/common/rpc/interceptor/caller_info.go +++ b/common/rpc/interceptor/caller_info.go @@ -27,9 +27,10 @@ package interceptor import ( "context" + "google.golang.org/grpc" + "go.temporal.io/server/common/headers" "go.temporal.io/server/common/namespace" - "google.golang.org/grpc" ) type ( @@ -67,7 +68,7 @@ func (i *CallerInfoInterceptor) Intercept( } if callerInfo.CallerType == headers.CallerTypeAPI && callerInfo.CallOrigin == "" { - _, method := splitMethodName(info.FullMethod) + _, method := SplitMethodName(info.FullMethod) callerInfo.CallOrigin = method updateInfo = true } diff --git a/common/rpc/interceptor/namespace_count_limit.go b/common/rpc/interceptor/namespace_count_limit.go index e82e086aab9..a1b90c07c2f 100644 --- a/common/rpc/interceptor/namespace_count_limit.go +++ b/common/rpc/interceptor/namespace_count_limit.go @@ -78,7 +78,7 @@ func (ni *NamespaceCountLimitInterceptor) Intercept( info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, ) (interface{}, error) { - _, methodName := splitMethodName(info.FullMethod) + _, methodName := SplitMethodName(info.FullMethod) // token will default to 0 token := ni.tokens[methodName] if token != 0 { diff --git a/common/rpc/interceptor/namespace_logger.go b/common/rpc/interceptor/namespace_logger.go index 454097f1338..152b87b9cbc 100644 --- a/common/rpc/interceptor/namespace_logger.go +++ b/common/rpc/interceptor/namespace_logger.go @@ -62,7 +62,7 @@ func (nli *NamespaceLogInterceptor) Intercept( ) (interface{}, error) { if nli.logger != nil { - _, methodName := splitMethodName(info.FullMethod) + _, methodName := SplitMethodName(info.FullMethod) namespace := GetNamespace(nli.namespaceRegistry, req) tlsInfo := authorization.TLSInfoFormContext(ctx) var serverName string diff --git a/common/rpc/interceptor/namespace_rate_limit.go b/common/rpc/interceptor/namespace_rate_limit.go index 5cbfb5387bd..645eed11342 100644 --- a/common/rpc/interceptor/namespace_rate_limit.go +++ b/common/rpc/interceptor/namespace_rate_limit.go @@ -72,7 +72,7 @@ func (ni *NamespaceRateLimitInterceptor) Intercept( info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, ) (interface{}, error) { - _, methodName := splitMethodName(info.FullMethod) + _, methodName := SplitMethodName(info.FullMethod) token, ok := ni.tokens[methodName] if !ok { token = NamespaceRateLimitDefaultToken diff --git a/common/rpc/interceptor/namespace_validator.go b/common/rpc/interceptor/namespace_validator.go index 7f69fd8cb08..85569fe7b57 100644 --- a/common/rpc/interceptor/namespace_validator.go +++ b/common/rpc/interceptor/namespace_validator.go @@ -248,7 +248,7 @@ func (ni *NamespaceValidatorInterceptor) checkNamespaceState(namespaceEntry *nam return nil } - _, methodName := splitMethodName(fullMethod) + _, methodName := SplitMethodName(fullMethod) allowedStates, allowedStatesDefined := allowedNamespaceStates[methodName] if !allowedStatesDefined { @@ -272,7 +272,7 @@ func (ni *NamespaceValidatorInterceptor) checkReplicationState(namespaceEntry *n return nil } - _, methodName := splitMethodName(fullMethod) + _, methodName := SplitMethodName(fullMethod) if _, ok := allowedMethodsDuringHandover[methodName]; ok { return nil diff --git a/common/rpc/interceptor/rate_limit.go b/common/rpc/interceptor/rate_limit.go index 7f385bf8b4f..b548738dd10 100644 --- a/common/rpc/interceptor/rate_limit.go +++ b/common/rpc/interceptor/rate_limit.go @@ -68,7 +68,7 @@ func (i *RateLimitInterceptor) Intercept( info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, ) (interface{}, error) { - _, methodName := splitMethodName(info.FullMethod) + _, methodName := SplitMethodName(info.FullMethod) token, ok := i.tokens[methodName] if !ok { token = RateLimitDefaultToken diff --git a/common/rpc/interceptor/telemetry.go b/common/rpc/interceptor/telemetry.go index 89da4b52a99..c34ed0824f7 100644 --- a/common/rpc/interceptor/telemetry.go +++ b/common/rpc/interceptor/telemetry.go @@ -136,7 +136,7 @@ func (ti *TelemetryInterceptor) Intercept( info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, ) (interface{}, error) { - _, methodName := splitMethodName(info.FullMethod) + _, methodName := SplitMethodName(info.FullMethod) metricsHandler, logTags := ti.metricsHandlerLogTags(req, info.FullMethod, methodName) ctx = context.WithValue(ctx, metricsCtxKey, metricsHandler) diff --git a/service/frontend/dcRedirectionHandler.go b/service/frontend/dcRedirectionHandler.go deleted file mode 100644 index 2d1711e1eb7..00000000000 --- a/service/frontend/dcRedirectionHandler.go +++ /dev/null @@ -1,1960 +0,0 @@ -// The MIT License -// -// Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. -// -// Copyright (c) 2020 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package frontend - -import ( - "context" - "time" - - "go.temporal.io/api/workflowservice/v1" - - "go.temporal.io/server/client" - "go.temporal.io/server/common" - "go.temporal.io/server/common/clock" - "go.temporal.io/server/common/cluster" - "go.temporal.io/server/common/config" - "go.temporal.io/server/common/log" - "go.temporal.io/server/common/metrics" - "go.temporal.io/server/common/namespace" -) - -var _ Handler = (*DCRedirectionHandlerImpl)(nil) - -type ( - // DCRedirectionHandlerImpl is simple wrapper over frontend service, doing redirection based on policy - DCRedirectionHandlerImpl struct { - currentClusterName string - config *Config - redirectionPolicy DCRedirectionPolicy - tokenSerializer common.TaskTokenSerializer - frontendHandler Handler - logger log.Logger - clientBean client.Bean - metricsHandler metrics.Handler - timeSource clock.TimeSource - } -) - -// NewDCRedirectionHandler creates a thrift handler for the temporal service, frontend -func NewDCRedirectionHandler( - wfHandler Handler, - policy config.DCRedirectionPolicy, - logger log.Logger, - clientBean client.Bean, - metricsHandler metrics.Handler, - timeSource clock.TimeSource, - namespaceRegistry namespace.Registry, - clusterMetadata cluster.Metadata, -) *DCRedirectionHandlerImpl { - dcRedirectionPolicy := RedirectionPolicyGenerator( - clusterMetadata, - wfHandler.GetConfig(), - namespaceRegistry, - policy, - ) - - return &DCRedirectionHandlerImpl{ - currentClusterName: clusterMetadata.GetCurrentClusterName(), - config: wfHandler.GetConfig(), - redirectionPolicy: dcRedirectionPolicy, - tokenSerializer: common.NewProtoTaskTokenSerializer(), - frontendHandler: wfHandler, - logger: logger, - clientBean: clientBean, - metricsHandler: metricsHandler, - timeSource: timeSource, - } -} - -// Start starts the handler -func (handler *DCRedirectionHandlerImpl) Start() { - handler.frontendHandler.Start() -} - -// Stop stops the handler -func (handler *DCRedirectionHandlerImpl) Stop() { - handler.frontendHandler.Stop() -} - -// GetConfig return config -func (handler *DCRedirectionHandlerImpl) GetConfig() *Config { - return handler.frontendHandler.GetConfig() -} - -// Namespace APIs, namespace APIs does not require redirection - -// DeprecateNamespace API call -func (handler *DCRedirectionHandlerImpl) DeprecateNamespace( - ctx context.Context, - request *workflowservice.DeprecateNamespaceRequest, -) (resp *workflowservice.DeprecateNamespaceResponse, retError error) { - - var cluster = handler.currentClusterName - - scope, startTime := handler.beforeCall(metrics.DCRedirectionDeprecateNamespaceScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - return handler.frontendHandler.DeprecateNamespace(ctx, request) -} - -// DescribeNamespace API call -func (handler *DCRedirectionHandlerImpl) DescribeNamespace( - ctx context.Context, - request *workflowservice.DescribeNamespaceRequest, -) (resp *workflowservice.DescribeNamespaceResponse, retError error) { - - var cluster = handler.currentClusterName - - scope, startTime := handler.beforeCall(metrics.DCRedirectionDescribeNamespaceScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - return handler.frontendHandler.DescribeNamespace(ctx, request) -} - -// ListNamespaces API call -func (handler *DCRedirectionHandlerImpl) ListNamespaces( - ctx context.Context, - request *workflowservice.ListNamespacesRequest, -) (resp *workflowservice.ListNamespacesResponse, retError error) { - - var cluster = handler.currentClusterName - - scope, startTime := handler.beforeCall(metrics.DCRedirectionListNamespacesScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - return handler.frontendHandler.ListNamespaces(ctx, request) -} - -// RegisterNamespace API call -func (handler *DCRedirectionHandlerImpl) RegisterNamespace( - ctx context.Context, - request *workflowservice.RegisterNamespaceRequest, -) (resp *workflowservice.RegisterNamespaceResponse, retError error) { - - var cluster = handler.currentClusterName - - scope, startTime := handler.beforeCall(metrics.DCRedirectionRegisterNamespaceScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - return handler.frontendHandler.RegisterNamespace(ctx, request) -} - -// UpdateNamespace API call -func (handler *DCRedirectionHandlerImpl) UpdateNamespace( - ctx context.Context, - request *workflowservice.UpdateNamespaceRequest, -) (resp *workflowservice.UpdateNamespaceResponse, retError error) { - - var cluster = handler.currentClusterName - - scope, startTime := handler.beforeCall(metrics.DCRedirectionUpdateNamespaceScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - return handler.frontendHandler.UpdateNamespace(ctx, request) -} - -// Other APIs - -// DescribeTaskQueue API call -func (handler *DCRedirectionHandlerImpl) DescribeTaskQueue( - ctx context.Context, - request *workflowservice.DescribeTaskQueueRequest, -) (resp *workflowservice.DescribeTaskQueueResponse, retError error) { - - var apiName = "DescribeTaskQueue" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionDescribeTaskQueueScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.DescribeTaskQueue(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.DescribeTaskQueue(ctx, request) - } - return err - }) - - return resp, err -} - -// DescribeWorkflowExecution API call -func (handler *DCRedirectionHandlerImpl) DescribeWorkflowExecution( - ctx context.Context, - request *workflowservice.DescribeWorkflowExecutionRequest, -) (resp *workflowservice.DescribeWorkflowExecutionResponse, retError error) { - - var apiName = "DescribeWorkflowExecution" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionDescribeWorkflowExecutionScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.DescribeWorkflowExecution(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.DescribeWorkflowExecution(ctx, request) - } - return err - }) - - return resp, err -} - -// GetWorkflowExecutionHistory API call -func (handler *DCRedirectionHandlerImpl) GetWorkflowExecutionHistory( - ctx context.Context, - request *workflowservice.GetWorkflowExecutionHistoryRequest, -) (resp *workflowservice.GetWorkflowExecutionHistoryResponse, retError error) { - - var apiName = "GetWorkflowExecutionHistory" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionGetWorkflowExecutionHistoryScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.GetWorkflowExecutionHistory(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.GetWorkflowExecutionHistory(ctx, request) - } - return err - }) - - return resp, err -} - -// GetWorkflowExecutionHistoryReverse API call -func (handler *DCRedirectionHandlerImpl) GetWorkflowExecutionHistoryReverse( - ctx context.Context, - request *workflowservice.GetWorkflowExecutionHistoryReverseRequest, -) (resp *workflowservice.GetWorkflowExecutionHistoryReverseResponse, retError error) { - - var apiName = "GetWorkflowExecutionHistoryReverse" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionGetWorkflowExecutionHistoryReverseScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.GetWorkflowExecutionHistoryReverse(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.GetWorkflowExecutionHistoryReverse(ctx, request) - } - return err - }) - - return resp, err -} - -// ListArchivedWorkflowExecutions API call -func (handler *DCRedirectionHandlerImpl) ListArchivedWorkflowExecutions( - ctx context.Context, - request *workflowservice.ListArchivedWorkflowExecutionsRequest, -) (resp *workflowservice.ListArchivedWorkflowExecutionsResponse, retError error) { - - var apiName = "ListArchivedWorkflowExecutions" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionListArchivedWorkflowExecutionsScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.ListArchivedWorkflowExecutions(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.ListArchivedWorkflowExecutions(ctx, request) - } - return err - }) - - return resp, err -} - -// ListClosedWorkflowExecutions API call -func (handler *DCRedirectionHandlerImpl) ListClosedWorkflowExecutions( - ctx context.Context, - request *workflowservice.ListClosedWorkflowExecutionsRequest, -) (resp *workflowservice.ListClosedWorkflowExecutionsResponse, retError error) { - - var apiName = "ListClosedWorkflowExecutions" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionListClosedWorkflowExecutionsScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.ListClosedWorkflowExecutions(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.ListClosedWorkflowExecutions(ctx, request) - } - return err - }) - - return resp, err -} - -// ListOpenWorkflowExecutions API call -func (handler *DCRedirectionHandlerImpl) ListOpenWorkflowExecutions( - ctx context.Context, - request *workflowservice.ListOpenWorkflowExecutionsRequest, -) (resp *workflowservice.ListOpenWorkflowExecutionsResponse, retError error) { - - var apiName = "ListOpenWorkflowExecutions" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionListOpenWorkflowExecutionsScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.ListOpenWorkflowExecutions(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.ListOpenWorkflowExecutions(ctx, request) - } - return err - }) - - return resp, err -} - -// ListWorkflowExecutions API call -func (handler *DCRedirectionHandlerImpl) ListWorkflowExecutions( - ctx context.Context, - request *workflowservice.ListWorkflowExecutionsRequest, -) (resp *workflowservice.ListWorkflowExecutionsResponse, retError error) { - - var apiName = "ListWorkflowExecutions" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionListWorkflowExecutionsScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.ListWorkflowExecutions(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.ListWorkflowExecutions(ctx, request) - } - return err - }) - - return resp, err -} - -// ScanWorkflowExecutions API call -func (handler *DCRedirectionHandlerImpl) ScanWorkflowExecutions( - ctx context.Context, - request *workflowservice.ScanWorkflowExecutionsRequest, -) (resp *workflowservice.ScanWorkflowExecutionsResponse, retError error) { - - var apiName = "ScanWorkflowExecutions" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionScanWorkflowExecutionsScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.ScanWorkflowExecutions(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.ScanWorkflowExecutions(ctx, request) - } - return err - }) - - return resp, err -} - -// CountWorkflowExecutions API call -func (handler *DCRedirectionHandlerImpl) CountWorkflowExecutions( - ctx context.Context, - request *workflowservice.CountWorkflowExecutionsRequest, -) (resp *workflowservice.CountWorkflowExecutionsResponse, retError error) { - - var apiName = "CountWorkflowExecutions" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionCountWorkflowExecutionsScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.CountWorkflowExecutions(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.CountWorkflowExecutions(ctx, request) - } - return err - }) - - return resp, err -} - -// GetSearchAttributes API call -func (handler *DCRedirectionHandlerImpl) GetSearchAttributes( - ctx context.Context, - request *workflowservice.GetSearchAttributesRequest, -) (resp *workflowservice.GetSearchAttributesResponse, retError error) { - - var cluster = handler.currentClusterName - - scope, startTime := handler.beforeCall(metrics.DCRedirectionGetSearchAttributesScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - return handler.frontendHandler.GetSearchAttributes(ctx, request) -} - -// PollActivityTaskQueue API call -func (handler *DCRedirectionHandlerImpl) PollActivityTaskQueue( - ctx context.Context, - request *workflowservice.PollActivityTaskQueueRequest, -) (resp *workflowservice.PollActivityTaskQueueResponse, retError error) { - - var apiName = "PollActivityTaskQueue" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionPollActivityTaskQueueScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.PollActivityTaskQueue(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.PollActivityTaskQueue(ctx, request) - } - return err - }) - - return resp, err -} - -// PollWorkflowTaskQueue API call -func (handler *DCRedirectionHandlerImpl) PollWorkflowTaskQueue( - ctx context.Context, - request *workflowservice.PollWorkflowTaskQueueRequest, -) (resp *workflowservice.PollWorkflowTaskQueueResponse, retError error) { - - var apiName = "PollWorkflowTaskQueue" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionPollWorkflowTaskQueueScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.PollWorkflowTaskQueue(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.PollWorkflowTaskQueue(ctx, request) - } - return err - }) - return resp, err -} - -// QueryWorkflow API call -func (handler *DCRedirectionHandlerImpl) QueryWorkflow( - ctx context.Context, - request *workflowservice.QueryWorkflowRequest, -) (resp *workflowservice.QueryWorkflowResponse, retError error) { - - var apiName = "QueryWorkflow" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionQueryWorkflowScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.QueryWorkflow(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.QueryWorkflow(ctx, request) - } - return err - }) - - return resp, err -} - -// RecordActivityTaskHeartbeat API call -func (handler *DCRedirectionHandlerImpl) RecordActivityTaskHeartbeat( - ctx context.Context, - request *workflowservice.RecordActivityTaskHeartbeatRequest, -) (resp *workflowservice.RecordActivityTaskHeartbeatResponse, retError error) { - - var apiName = "RecordActivityTaskHeartbeat" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionRecordActivityTaskHeartbeatScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - token, err := handler.tokenSerializer.Deserialize(request.TaskToken) - if err != nil { - return nil, err - } - - err = handler.redirectionPolicy.WithNamespaceIDRedirect(ctx, namespace.ID(token.GetNamespaceId()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.RecordActivityTaskHeartbeat(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.RecordActivityTaskHeartbeat(ctx, request) - } - return err - }) - - return resp, err -} - -// RecordActivityTaskHeartbeatById API call -func (handler *DCRedirectionHandlerImpl) RecordActivityTaskHeartbeatById( - ctx context.Context, - request *workflowservice.RecordActivityTaskHeartbeatByIdRequest, -) (resp *workflowservice.RecordActivityTaskHeartbeatByIdResponse, retError error) { - - var apiName = "RecordActivityTaskHeartbeatById" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionRecordActivityTaskHeartbeatByIdScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.RecordActivityTaskHeartbeatById(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.RecordActivityTaskHeartbeatById(ctx, request) - } - return err - }) - - return resp, err -} - -// RequestCancelWorkflowExecution API call -func (handler *DCRedirectionHandlerImpl) RequestCancelWorkflowExecution( - ctx context.Context, - request *workflowservice.RequestCancelWorkflowExecutionRequest, -) (resp *workflowservice.RequestCancelWorkflowExecutionResponse, retError error) { - - var apiName = "RequestCancelWorkflowExecution" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionRequestCancelWorkflowExecutionScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.RequestCancelWorkflowExecution(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.RequestCancelWorkflowExecution(ctx, request) - } - return err - }) - - return resp, err -} - -// ResetStickyTaskQueue API call -func (handler *DCRedirectionHandlerImpl) ResetStickyTaskQueue( - ctx context.Context, - request *workflowservice.ResetStickyTaskQueueRequest, -) (resp *workflowservice.ResetStickyTaskQueueResponse, retError error) { - - var apiName = "ResetStickyTaskQueue" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionResetStickyTaskQueueScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.ResetStickyTaskQueue(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.ResetStickyTaskQueue(ctx, request) - } - return err - }) - - return resp, err -} - -// ResetWorkflowExecution API call -func (handler *DCRedirectionHandlerImpl) ResetWorkflowExecution( - ctx context.Context, - request *workflowservice.ResetWorkflowExecutionRequest, -) (resp *workflowservice.ResetWorkflowExecutionResponse, retError error) { - - var apiName = "ResetWorkflowExecution" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionResetWorkflowExecutionScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.ResetWorkflowExecution(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.ResetWorkflowExecution(ctx, request) - } - return err - }) - - return resp, err -} - -// RespondActivityTaskCanceled API call -func (handler *DCRedirectionHandlerImpl) RespondActivityTaskCanceled( - ctx context.Context, - request *workflowservice.RespondActivityTaskCanceledRequest, -) (resp *workflowservice.RespondActivityTaskCanceledResponse, retError error) { - - var apiName = "RespondActivityTaskCanceled" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionRespondActivityTaskCanceledScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - token, err := handler.tokenSerializer.Deserialize(request.TaskToken) - if err != nil { - return resp, err - } - - err = handler.redirectionPolicy.WithNamespaceIDRedirect(ctx, namespace.ID(token.GetNamespaceId()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.RespondActivityTaskCanceled(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.RespondActivityTaskCanceled(ctx, request) - } - return err - }) - - return resp, err -} - -// RespondActivityTaskCanceledById API call -func (handler *DCRedirectionHandlerImpl) RespondActivityTaskCanceledById( - ctx context.Context, - request *workflowservice.RespondActivityTaskCanceledByIdRequest, -) (resp *workflowservice.RespondActivityTaskCanceledByIdResponse, retError error) { - - var apiName = "RespondActivityTaskCanceledById" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionRespondActivityTaskCanceledByIdScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.RespondActivityTaskCanceledById(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.RespondActivityTaskCanceledById(ctx, request) - } - return err - }) - - return resp, err -} - -// RespondActivityTaskCompleted API call -func (handler *DCRedirectionHandlerImpl) RespondActivityTaskCompleted( - ctx context.Context, - request *workflowservice.RespondActivityTaskCompletedRequest, -) (resp *workflowservice.RespondActivityTaskCompletedResponse, retError error) { - - var apiName = "RespondActivityTaskCompleted" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionRespondActivityTaskCompletedScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - token, err := handler.tokenSerializer.Deserialize(request.TaskToken) - if err != nil { - return resp, err - } - - err = handler.redirectionPolicy.WithNamespaceIDRedirect(ctx, namespace.ID(token.GetNamespaceId()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.RespondActivityTaskCompleted(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.RespondActivityTaskCompleted(ctx, request) - } - return err - }) - - return resp, err -} - -// RespondActivityTaskCompletedById API call -func (handler *DCRedirectionHandlerImpl) RespondActivityTaskCompletedById( - ctx context.Context, - request *workflowservice.RespondActivityTaskCompletedByIdRequest, -) (resp *workflowservice.RespondActivityTaskCompletedByIdResponse, retError error) { - - var apiName = "RespondActivityTaskCompletedById" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionRespondActivityTaskCompletedByIdScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.RespondActivityTaskCompletedById(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.RespondActivityTaskCompletedById(ctx, request) - } - return err - }) - - return resp, err -} - -// RespondActivityTaskFailed API call -func (handler *DCRedirectionHandlerImpl) RespondActivityTaskFailed( - ctx context.Context, - request *workflowservice.RespondActivityTaskFailedRequest, -) (resp *workflowservice.RespondActivityTaskFailedResponse, retError error) { - - var apiName = "RespondActivityTaskFailed" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionRespondActivityTaskFailedScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - token, err := handler.tokenSerializer.Deserialize(request.TaskToken) - if err != nil { - return resp, err - } - - err = handler.redirectionPolicy.WithNamespaceIDRedirect(ctx, namespace.ID(token.GetNamespaceId()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.RespondActivityTaskFailed(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.RespondActivityTaskFailed(ctx, request) - } - return err - }) - - return resp, err -} - -// RespondActivityTaskFailedById API call -func (handler *DCRedirectionHandlerImpl) RespondActivityTaskFailedById( - ctx context.Context, - request *workflowservice.RespondActivityTaskFailedByIdRequest, -) (resp *workflowservice.RespondActivityTaskFailedByIdResponse, retError error) { - - var apiName = "RespondActivityTaskFailedById" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionRespondActivityTaskFailedByIdScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.RespondActivityTaskFailedById(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.RespondActivityTaskFailedById(ctx, request) - } - return err - }) - - return resp, err -} - -// RespondWorkflowTaskCompleted API call -func (handler *DCRedirectionHandlerImpl) RespondWorkflowTaskCompleted( - ctx context.Context, - request *workflowservice.RespondWorkflowTaskCompletedRequest, -) (resp *workflowservice.RespondWorkflowTaskCompletedResponse, retError error) { - - var apiName = "RespondWorkflowTaskCompleted" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionRespondWorkflowTaskCompletedScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - token, err := handler.tokenSerializer.Deserialize(request.TaskToken) - if err != nil { - return nil, err - } - - err = handler.redirectionPolicy.WithNamespaceIDRedirect(ctx, namespace.ID(token.GetNamespaceId()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.RespondWorkflowTaskCompleted(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.RespondWorkflowTaskCompleted(ctx, request) - } - return err - }) - - return resp, err -} - -// RespondWorkflowTaskFailed API call -func (handler *DCRedirectionHandlerImpl) RespondWorkflowTaskFailed( - ctx context.Context, - request *workflowservice.RespondWorkflowTaskFailedRequest, -) (resp *workflowservice.RespondWorkflowTaskFailedResponse, retError error) { - - var apiName = "RespondWorkflowTaskFailed" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionRespondWorkflowTaskFailedScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - token, err := handler.tokenSerializer.Deserialize(request.TaskToken) - if err != nil { - return resp, err - } - - err = handler.redirectionPolicy.WithNamespaceIDRedirect(ctx, namespace.ID(token.GetNamespaceId()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.RespondWorkflowTaskFailed(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.RespondWorkflowTaskFailed(ctx, request) - } - return err - }) - - return resp, err -} - -// RespondQueryTaskCompleted API call -func (handler *DCRedirectionHandlerImpl) RespondQueryTaskCompleted( - ctx context.Context, - request *workflowservice.RespondQueryTaskCompletedRequest, -) (resp *workflowservice.RespondQueryTaskCompletedResponse, retError error) { - - var apiName = "RespondQueryTaskCompleted" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionRespondQueryTaskCompletedScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - token, err := handler.tokenSerializer.DeserializeQueryTaskToken(request.TaskToken) - if err != nil { - return resp, err - } - - err = handler.redirectionPolicy.WithNamespaceIDRedirect(ctx, namespace.ID(token.GetNamespaceId()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.RespondQueryTaskCompleted(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.RespondQueryTaskCompleted(ctx, request) - } - return err - }) - - return resp, err -} - -// SignalWithStartWorkflowExecution API call -func (handler *DCRedirectionHandlerImpl) SignalWithStartWorkflowExecution( - ctx context.Context, - request *workflowservice.SignalWithStartWorkflowExecutionRequest, -) (resp *workflowservice.SignalWithStartWorkflowExecutionResponse, retError error) { - - var apiName = "SignalWithStartWorkflowExecution" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionSignalWithStartWorkflowExecutionScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.SignalWithStartWorkflowExecution(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.SignalWithStartWorkflowExecution(ctx, request) - } - return err - }) - - return resp, err -} - -// SignalWorkflowExecution API call -func (handler *DCRedirectionHandlerImpl) SignalWorkflowExecution( - ctx context.Context, - request *workflowservice.SignalWorkflowExecutionRequest, -) (resp *workflowservice.SignalWorkflowExecutionResponse, retError error) { - - var apiName = "SignalWorkflowExecution" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionSignalWorkflowExecutionScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.SignalWorkflowExecution(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.SignalWorkflowExecution(ctx, request) - } - return err - }) - return resp, err -} - -// StartWorkflowExecution API call -func (handler *DCRedirectionHandlerImpl) StartWorkflowExecution( - ctx context.Context, - request *workflowservice.StartWorkflowExecutionRequest, -) (resp *workflowservice.StartWorkflowExecutionResponse, retError error) { - - var apiName = "StartWorkflowExecution" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionStartWorkflowExecutionScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.StartWorkflowExecution(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.StartWorkflowExecution(ctx, request) - } - return err - }) - - return resp, err -} - -// TerminateWorkflowExecution API call -func (handler *DCRedirectionHandlerImpl) TerminateWorkflowExecution( - ctx context.Context, - request *workflowservice.TerminateWorkflowExecutionRequest, -) (resp *workflowservice.TerminateWorkflowExecutionResponse, retError error) { - - var apiName = "TerminateWorkflowExecution" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionTerminateWorkflowExecutionScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.TerminateWorkflowExecution(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.TerminateWorkflowExecution(ctx, request) - } - return err - }) - - return resp, err -} - -// TerminateWorkflowExecution API call -func (handler *DCRedirectionHandlerImpl) DeleteWorkflowExecution( - ctx context.Context, - request *workflowservice.DeleteWorkflowExecutionRequest, -) (resp *workflowservice.DeleteWorkflowExecutionResponse, retError error) { - - var apiName = "DeleteWorkflowExecution" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionDeleteWorkflowExecutionScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.DeleteWorkflowExecution(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.DeleteWorkflowExecution(ctx, request) - } - return err - }) - - return resp, err -} - -// ListTaskQueuePartitions API call -func (handler *DCRedirectionHandlerImpl) ListTaskQueuePartitions( - ctx context.Context, - request *workflowservice.ListTaskQueuePartitionsRequest, -) (resp *workflowservice.ListTaskQueuePartitionsResponse, retError error) { - - var apiName = "ListTaskQueuePartitions" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionListTaskQueuePartitionsScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.ListTaskQueuePartitions(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.ListTaskQueuePartitions(ctx, request) - } - return err - }) - - return resp, err -} - -// GetClusterInfo API call -func (handler *DCRedirectionHandlerImpl) GetClusterInfo( - ctx context.Context, - request *workflowservice.GetClusterInfoRequest, -) (*workflowservice.GetClusterInfoResponse, error) { - return handler.frontendHandler.GetClusterInfo(ctx, request) -} - -// GetSystemInfo API call -func (handler *DCRedirectionHandlerImpl) GetSystemInfo( - ctx context.Context, - request *workflowservice.GetSystemInfoRequest, -) (*workflowservice.GetSystemInfoResponse, error) { - return handler.frontendHandler.GetSystemInfo(ctx, request) -} - -// CreateSchedule API call -func (handler *DCRedirectionHandlerImpl) CreateSchedule( - ctx context.Context, - request *workflowservice.CreateScheduleRequest, -) (resp *workflowservice.CreateScheduleResponse, retError error) { - var apiName = "CreateSchedule" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionCreateScheduleScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.CreateSchedule(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.CreateSchedule(ctx, request) - } - return err - }) - - return resp, err -} - -// DescribeSchedule API call -func (handler *DCRedirectionHandlerImpl) DescribeSchedule( - ctx context.Context, - request *workflowservice.DescribeScheduleRequest, -) (resp *workflowservice.DescribeScheduleResponse, retError error) { - var apiName = "DescribeSchedule" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionDescribeScheduleScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.DescribeSchedule(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.DescribeSchedule(ctx, request) - } - return err - }) - - return resp, err -} - -// UpdateSchedule API call -func (handler *DCRedirectionHandlerImpl) UpdateSchedule( - ctx context.Context, - request *workflowservice.UpdateScheduleRequest, -) (resp *workflowservice.UpdateScheduleResponse, retError error) { - var apiName = "UpdateSchedule" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionUpdateScheduleScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.UpdateSchedule(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.UpdateSchedule(ctx, request) - } - return err - }) - - return resp, err -} - -// PatchSchedule API call -func (handler *DCRedirectionHandlerImpl) PatchSchedule( - ctx context.Context, - request *workflowservice.PatchScheduleRequest, -) (resp *workflowservice.PatchScheduleResponse, retError error) { - var apiName = "PatchSchedule" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionPatchScheduleScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.PatchSchedule(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.PatchSchedule(ctx, request) - } - return err - }) - - return resp, err -} - -// ListScheduleMatchingTimes API call -func (handler *DCRedirectionHandlerImpl) ListScheduleMatchingTimes( - ctx context.Context, - request *workflowservice.ListScheduleMatchingTimesRequest, -) (resp *workflowservice.ListScheduleMatchingTimesResponse, retError error) { - var apiName = "ListScheduleMatchingTimes" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionListScheduleMatchingTimesScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.ListScheduleMatchingTimes(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.ListScheduleMatchingTimes(ctx, request) - } - return err - }) - - return resp, err -} - -// DeleteSchedule API call -func (handler *DCRedirectionHandlerImpl) DeleteSchedule( - ctx context.Context, - request *workflowservice.DeleteScheduleRequest, -) (resp *workflowservice.DeleteScheduleResponse, retError error) { - var apiName = "DeleteSchedule" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionDeleteScheduleScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.DeleteSchedule(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.DeleteSchedule(ctx, request) - } - return err - }) - - return resp, err -} - -// ListSchedules API call -func (handler *DCRedirectionHandlerImpl) ListSchedules( - ctx context.Context, - request *workflowservice.ListSchedulesRequest, -) (resp *workflowservice.ListSchedulesResponse, retError error) { - var apiName = "ListSchedules" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionListSchedulesScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.ListSchedules(ctx, request) - default: - var remoteClient workflowservice.WorkflowServiceClient - remoteClient, err = handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.ListSchedules(ctx, request) - } - return err - }) - - return resp, err -} - -// UpdateWorkerBuildIdOrdering API call -func (handler *DCRedirectionHandlerImpl) UpdateWorkerBuildIdOrdering( - ctx context.Context, - request *workflowservice.UpdateWorkerBuildIdOrderingRequest, -) (resp *workflowservice.UpdateWorkerBuildIdOrderingResponse, retError error) { - const apiName = "UpdateWorkerBuildIdOrdering" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionUpdateWorkerBuildIdOrderingScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - - if targetDC == handler.currentClusterName { - resp, err = handler.frontendHandler.UpdateWorkerBuildIdOrdering(ctx, request) - return err - } else { - remoteClient, err := handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.UpdateWorkerBuildIdOrdering(ctx, request) - return err - } - }) - - return resp, err -} - -// GetWorkerBuildIdOrdering API call -func (handler *DCRedirectionHandlerImpl) GetWorkerBuildIdOrdering( - ctx context.Context, - request *workflowservice.GetWorkerBuildIdOrderingRequest, -) (resp *workflowservice.GetWorkerBuildIdOrderingResponse, retError error) { - var apiName = "GetWorkerBuildIdOrdering" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionGetWorkerBuildIdOrderingScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.GetWorkerBuildIdOrdering(ctx, request) - return err - default: - remoteClient, err := handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.GetWorkerBuildIdOrdering(ctx, request) - return err - } - }) - - return resp, err -} - -// UpdateWorkflowExecution API call -func (handler *DCRedirectionHandlerImpl) UpdateWorkflowExecution( - ctx context.Context, - request *workflowservice.UpdateWorkflowExecutionRequest, -) (resp *workflowservice.UpdateWorkflowExecutionResponse, retError error) { - var ( - err error - cluster string - ) - - scope, startTime := handler.beforeCall(metrics.DCRedirectionUpdateWorkflowExecutionScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), "UpdateWorkflowExecution", func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.UpdateWorkflowExecution(ctx, request) - return err - default: - remoteClient, err := handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.UpdateWorkflowExecution(ctx, request) - return err - } - }) - - return resp, err -} - -func (handler *DCRedirectionHandlerImpl) StartBatchOperation( - ctx context.Context, - request *workflowservice.StartBatchOperationRequest, -) (resp *workflowservice.StartBatchOperationResponse, retError error) { - var apiName = "StartBatchOperation" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionStartBatchOperationScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.StartBatchOperation(ctx, request) - return err - default: - remoteClient, err := handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.StartBatchOperation(ctx, request) - return err - } - }) - - return resp, err -} - -func (handler *DCRedirectionHandlerImpl) StopBatchOperation( - ctx context.Context, - request *workflowservice.StopBatchOperationRequest, -) (resp *workflowservice.StopBatchOperationResponse, retError error) { - var apiName = "StopBatchOperation" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionStopBatchOperationScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.StopBatchOperation(ctx, request) - return err - default: - remoteClient, err := handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.StopBatchOperation(ctx, request) - return err - } - }) - - return resp, err -} - -func (handler *DCRedirectionHandlerImpl) DescribeBatchOperation( - ctx context.Context, - request *workflowservice.DescribeBatchOperationRequest, -) (resp *workflowservice.DescribeBatchOperationResponse, retError error) { - var apiName = "DescribeBatchOperation" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionDescribeBatchOperationScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.DescribeBatchOperation(ctx, request) - return err - default: - remoteClient, err := handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.DescribeBatchOperation(ctx, request) - return err - } - }) - - return resp, err -} - -func (handler *DCRedirectionHandlerImpl) ListBatchOperations( - ctx context.Context, - request *workflowservice.ListBatchOperationsRequest, -) (resp *workflowservice.ListBatchOperationsResponse, retError error) { - var apiName = "ListBatchOperations" - var err error - var cluster string - - scope, startTime := handler.beforeCall(metrics.DCRedirectionListBatchOperationsScope) - defer func() { - handler.afterCall(scope, startTime, cluster, retError) - }() - - defer log.CapturePanic(handler.logger, &retError) - - err = handler.redirectionPolicy.WithNamespaceRedirect(ctx, namespace.Name(request.GetNamespace()), apiName, func(targetDC string) error { - cluster = targetDC - switch { - case targetDC == handler.currentClusterName: - resp, err = handler.frontendHandler.ListBatchOperations(ctx, request) - return err - default: - remoteClient, err := handler.clientBean.GetRemoteFrontendClient(targetDC) - if err != nil { - return err - } - resp, err = remoteClient.ListBatchOperations(ctx, request) - return err - } - }) - - return resp, err -} - -func (handler *DCRedirectionHandlerImpl) beforeCall( - operation string, -) (metrics.Handler, time.Time) { - - return handler.metricsHandler.WithTags(metrics.OperationTag(operation), metrics.ServiceRoleTag(metrics.DCRedirectionRoleTagValue)), handler.timeSource.Now() -} - -func (handler *DCRedirectionHandlerImpl) afterCall( - metricsHandler metrics.Handler, - startTime time.Time, - cluster string, - retError error, -) { - metricsHandler = metricsHandler.WithTags(metrics.TargetClusterTag(cluster)) - metricsHandler.Counter(metrics.ClientRedirectionRequests.GetMetricName()).Record(1) - metricsHandler.Timer(metrics.ClientRedirectionLatency.GetMetricName()).Record(handler.timeSource.Now().Sub(startTime)) - if retError != nil { - metricsHandler.Counter(metrics.ClientRedirectionFailures.GetMetricName()).Record(1) - } -} diff --git a/service/frontend/dcRedirectionHandler_test.go b/service/frontend/dcRedirectionHandler_test.go deleted file mode 100644 index cda07eb9470..00000000000 --- a/service/frontend/dcRedirectionHandler_test.go +++ /dev/null @@ -1,914 +0,0 @@ -// The MIT License -// -// Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. -// -// Copyright (c) 2020 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package frontend - -import ( - "context" - "testing" - - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - taskqueuepb "go.temporal.io/api/taskqueue/v1" - "go.temporal.io/api/workflowservice/v1" - "go.temporal.io/api/workflowservicemock/v1" - "google.golang.org/grpc/health" - - tokenspb "go.temporal.io/server/api/token/v1" - "go.temporal.io/server/common/clock" - "go.temporal.io/server/common/cluster" - "go.temporal.io/server/common/config" - "go.temporal.io/server/common/dynamicconfig" - "go.temporal.io/server/common/metrics" - "go.temporal.io/server/common/namespace" - "go.temporal.io/server/common/persistence/visibility/manager" - "go.temporal.io/server/common/resourcetest" -) - -type ( - dcRedirectionHandlerSuite struct { - suite.Suite - *require.Assertions - - controller *gomock.Controller - mockResource *resourcetest.Test - mockFrontendHandler *workflowservicemock.MockWorkflowServiceServer - mockRemoteFrontendClient *workflowservicemock.MockWorkflowServiceClient - mockClusterMetadata *cluster.MockMetadata - mockVisibilityMgr *manager.MockVisibilityManager - - mockDCRedirectionPolicy *MockDCRedirectionPolicy - - namespace namespace.Name - namespaceID namespace.ID - currentClusterName string - alternativeClusterName string - config *Config - - handler *DCRedirectionHandlerImpl - } - - testServerHandler struct { - *workflowservicemock.MockWorkflowServiceServer - } -) - -func newTestServerHandler(mockHandler *workflowservicemock.MockWorkflowServiceServer) Handler { - return &testServerHandler{mockHandler} -} - -func TestDCRedirectionHandlerSuite(t *testing.T) { - s := new(dcRedirectionHandlerSuite) - suite.Run(t, s) -} - -func (s *dcRedirectionHandlerSuite) SetupSuite() { -} - -func (s *dcRedirectionHandlerSuite) TearDownSuite() { -} - -func (s *dcRedirectionHandlerSuite) SetupTest() { - s.Assertions = require.New(s.T()) - - s.namespace = "some random namespace name" - s.namespaceID = "deadbeef-0123-4567-aaaa-bcdef0123456" - s.currentClusterName = cluster.TestCurrentClusterName - s.alternativeClusterName = cluster.TestAlternativeClusterName - - s.controller = gomock.NewController(s.T()) - - s.mockDCRedirectionPolicy = NewMockDCRedirectionPolicy(s.controller) - s.mockResource = resourcetest.NewTest(s.controller, metrics.Frontend) - s.mockClusterMetadata = s.mockResource.ClusterMetadata - s.mockRemoteFrontendClient = s.mockResource.RemoteFrontendClient - s.mockVisibilityMgr = s.mockResource.VisibilityManager - - s.mockClusterMetadata.EXPECT().GetCurrentClusterName().Return(s.currentClusterName).AnyTimes() - s.mockClusterMetadata.EXPECT().IsGlobalNamespaceEnabled().Return(true).AnyTimes() - - s.mockVisibilityMgr.EXPECT().GetIndexName().Return("").AnyTimes() - s.config = NewConfig(dynamicconfig.NewCollection(dynamicconfig.NewNoopClient(), s.mockResource.GetLogger()), 0, false) - - frontendHandlerGRPC := NewWorkflowHandler( - s.config, - nil, - s.mockResource.GetVisibilityManager(), - s.mockResource.GetLogger(), - s.mockResource.GetThrottledLogger(), - s.mockResource.GetExecutionManager(), - s.mockResource.GetClusterMetadataManager(), - s.mockResource.GetMetadataManager(), - s.mockResource.GetHistoryClient(), - s.mockResource.GetMatchingClient(), - s.mockResource.GetArchiverProvider(), - s.mockResource.GetPayloadSerializer(), - s.mockResource.GetNamespaceRegistry(), - s.mockResource.GetSearchAttributesMapperProvider(), - s.mockResource.GetSearchAttributesProvider(), - s.mockResource.GetClusterMetadata(), - s.mockResource.GetArchivalMetadata(), - health.NewServer(), - clock.NewRealTimeSource(), - ) - - s.mockFrontendHandler = workflowservicemock.NewMockWorkflowServiceServer(s.controller) - s.handler = NewDCRedirectionHandler( - frontendHandlerGRPC, - config.DCRedirectionPolicy{}, - s.mockResource.Logger, - s.mockResource.GetClientBean(), - s.mockResource.GetMetricsHandler(), - s.mockResource.GetTimeSource(), - s.mockResource.GetNamespaceRegistry(), - s.mockResource.GetClusterMetadata(), - ) - - s.handler.frontendHandler = newTestServerHandler(s.mockFrontendHandler) - s.handler.redirectionPolicy = s.mockDCRedirectionPolicy -} - -func (s *dcRedirectionHandlerSuite) TearDownTest() { - s.controller.Finish() -} - -func (s *dcRedirectionHandlerSuite) TestDescribeTaskQueue() { - apiName := "DescribeTaskQueue" - - req := &workflowservice.DescribeTaskQueueRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().DescribeTaskQueue(gomock.Any(), req).Return(&workflowservice.DescribeTaskQueueResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().DescribeTaskQueue(gomock.Any(), req).Return(&workflowservice.DescribeTaskQueueResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.DescribeTaskQueue(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.DescribeTaskQueueResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestDescribeWorkflowExecution() { - apiName := "DescribeWorkflowExecution" - - req := &workflowservice.DescribeWorkflowExecutionRequest{ - Namespace: s.namespace.String(), - } - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().DescribeWorkflowExecution(gomock.Any(), req).Return(&workflowservice.DescribeWorkflowExecutionResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().DescribeWorkflowExecution(gomock.Any(), req).Return(&workflowservice.DescribeWorkflowExecutionResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.DescribeWorkflowExecution(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.DescribeWorkflowExecutionResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestGetWorkflowExecutionHistory() { - apiName := "GetWorkflowExecutionHistory" - - req := &workflowservice.GetWorkflowExecutionHistoryRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().GetWorkflowExecutionHistory(gomock.Any(), req).Return(&workflowservice.GetWorkflowExecutionHistoryResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().GetWorkflowExecutionHistory(gomock.Any(), req).Return(&workflowservice.GetWorkflowExecutionHistoryResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.GetWorkflowExecutionHistory(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.GetWorkflowExecutionHistoryResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestListArchivedWorkflowExecutions() { - apiName := "ListArchivedWorkflowExecutions" - - req := &workflowservice.ListArchivedWorkflowExecutionsRequest{ - Namespace: s.namespace.String(), - } - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().ListArchivedWorkflowExecutions(gomock.Any(), req).Return(&workflowservice.ListArchivedWorkflowExecutionsResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().ListArchivedWorkflowExecutions(gomock.Any(), req).Return(&workflowservice.ListArchivedWorkflowExecutionsResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.ListArchivedWorkflowExecutions(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.ListArchivedWorkflowExecutionsResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestListClosedWorkflowExecutions() { - apiName := "ListClosedWorkflowExecutions" - - req := &workflowservice.ListClosedWorkflowExecutionsRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().ListClosedWorkflowExecutions(gomock.Any(), req).Return(&workflowservice.ListClosedWorkflowExecutionsResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().ListClosedWorkflowExecutions(gomock.Any(), req).Return(&workflowservice.ListClosedWorkflowExecutionsResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.ListClosedWorkflowExecutions(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.ListClosedWorkflowExecutionsResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestListOpenWorkflowExecutions() { - apiName := "ListOpenWorkflowExecutions" - - req := &workflowservice.ListOpenWorkflowExecutionsRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().ListOpenWorkflowExecutions(gomock.Any(), req).Return(&workflowservice.ListOpenWorkflowExecutionsResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().ListOpenWorkflowExecutions(gomock.Any(), req).Return(&workflowservice.ListOpenWorkflowExecutionsResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.ListOpenWorkflowExecutions(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.ListOpenWorkflowExecutionsResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestListWorkflowExecutions() { - apiName := "ListWorkflowExecutions" - - req := &workflowservice.ListWorkflowExecutionsRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().ListWorkflowExecutions(gomock.Any(), req).Return(&workflowservice.ListWorkflowExecutionsResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().ListWorkflowExecutions(gomock.Any(), req).Return(&workflowservice.ListWorkflowExecutionsResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.ListWorkflowExecutions(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.ListWorkflowExecutionsResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestScanWorkflowExecutions() { - apiName := "ScanWorkflowExecutions" - - req := &workflowservice.ScanWorkflowExecutionsRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().ScanWorkflowExecutions(gomock.Any(), req).Return(&workflowservice.ScanWorkflowExecutionsResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().ScanWorkflowExecutions(gomock.Any(), req).Return(&workflowservice.ScanWorkflowExecutionsResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.ScanWorkflowExecutions(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.ScanWorkflowExecutionsResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestCountWorkflowExecutions() { - apiName := "CountWorkflowExecutions" - - req := &workflowservice.CountWorkflowExecutionsRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().CountWorkflowExecutions(gomock.Any(), req).Return(&workflowservice.CountWorkflowExecutionsResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().CountWorkflowExecutions(gomock.Any(), req).Return(&workflowservice.CountWorkflowExecutionsResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.CountWorkflowExecutions(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.CountWorkflowExecutionsResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestPollActivityTaskQueue() { - apiName := "PollActivityTaskQueue" - - req := &workflowservice.PollActivityTaskQueueRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().PollActivityTaskQueue(gomock.Any(), req).Return(&workflowservice.PollActivityTaskQueueResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().PollActivityTaskQueue(gomock.Any(), req).Return(&workflowservice.PollActivityTaskQueueResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.PollActivityTaskQueue(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.PollActivityTaskQueueResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestPollWorkflowTaskQueue() { - apiName := "PollWorkflowTaskQueue" - - req := &workflowservice.PollWorkflowTaskQueueRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().PollWorkflowTaskQueue(gomock.Any(), req).Return(&workflowservice.PollWorkflowTaskQueueResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().PollWorkflowTaskQueue(gomock.Any(), req).Return(&workflowservice.PollWorkflowTaskQueueResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.PollWorkflowTaskQueue(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.PollWorkflowTaskQueueResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestQueryWorkflow() { - apiName := "QueryWorkflow" - - req := &workflowservice.QueryWorkflowRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().QueryWorkflow(gomock.Any(), req).Return(&workflowservice.QueryWorkflowResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().QueryWorkflow(gomock.Any(), req).Return(&workflowservice.QueryWorkflowResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.QueryWorkflow(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.QueryWorkflowResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestRecordActivityTaskHeartbeat() { - apiName := "RecordActivityTaskHeartbeat" - - taskToken, err := s.handler.tokenSerializer.Serialize(&tokenspb.Task{ - Attempt: 1, - NamespaceId: s.namespaceID.String(), - }) - s.NoError(err) - req := &workflowservice.RecordActivityTaskHeartbeatRequest{ - TaskToken: taskToken, - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceIDRedirect(gomock.Any(), s.namespaceID, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.ID, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().RecordActivityTaskHeartbeat(gomock.Any(), req).Return(&workflowservice.RecordActivityTaskHeartbeatResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().RecordActivityTaskHeartbeat(gomock.Any(), req).Return(&workflowservice.RecordActivityTaskHeartbeatResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.RecordActivityTaskHeartbeat(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.RecordActivityTaskHeartbeatResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestRecordActivityTaskHeartbeatById() { - apiName := "RecordActivityTaskHeartbeatById" - - req := &workflowservice.RecordActivityTaskHeartbeatByIdRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().RecordActivityTaskHeartbeatById(gomock.Any(), req).Return(&workflowservice.RecordActivityTaskHeartbeatByIdResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().RecordActivityTaskHeartbeatById(gomock.Any(), req).Return(&workflowservice.RecordActivityTaskHeartbeatByIdResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.RecordActivityTaskHeartbeatById(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.RecordActivityTaskHeartbeatByIdResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestRequestCancelWorkflowExecution() { - apiName := "RequestCancelWorkflowExecution" - - req := &workflowservice.RequestCancelWorkflowExecutionRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().RequestCancelWorkflowExecution(gomock.Any(), req).Return(&workflowservice.RequestCancelWorkflowExecutionResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().RequestCancelWorkflowExecution(gomock.Any(), req).Return(&workflowservice.RequestCancelWorkflowExecutionResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.RequestCancelWorkflowExecution(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.RequestCancelWorkflowExecutionResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestResetStickyTaskQueue() { - apiName := "ResetStickyTaskQueue" - - req := &workflowservice.ResetStickyTaskQueueRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().ResetStickyTaskQueue(gomock.Any(), req).Return(&workflowservice.ResetStickyTaskQueueResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().ResetStickyTaskQueue(gomock.Any(), req).Return(&workflowservice.ResetStickyTaskQueueResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.ResetStickyTaskQueue(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.ResetStickyTaskQueueResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestResetWorkflowExecution() { - apiName := "ResetWorkflowExecution" - - req := &workflowservice.ResetWorkflowExecutionRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().ResetWorkflowExecution(gomock.Any(), req).Return(&workflowservice.ResetWorkflowExecutionResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().ResetWorkflowExecution(gomock.Any(), req).Return(&workflowservice.ResetWorkflowExecutionResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.ResetWorkflowExecution(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.ResetWorkflowExecutionResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestRespondActivityTaskCanceled() { - apiName := "RespondActivityTaskCanceled" - - token, err := s.handler.tokenSerializer.Serialize(&tokenspb.Task{ - Attempt: 1, - NamespaceId: s.namespaceID.String(), - }) - s.NoError(err) - req := &workflowservice.RespondActivityTaskCanceledRequest{ - TaskToken: token, - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceIDRedirect(gomock.Any(), s.namespaceID, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.ID, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().RespondActivityTaskCanceled(gomock.Any(), req).Return(&workflowservice.RespondActivityTaskCanceledResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().RespondActivityTaskCanceled(gomock.Any(), req).Return(&workflowservice.RespondActivityTaskCanceledResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.RespondActivityTaskCanceled(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.RespondActivityTaskCanceledResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestRespondActivityTaskCanceledById() { - apiName := "RespondActivityTaskCanceledById" - - req := &workflowservice.RespondActivityTaskCanceledByIdRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().RespondActivityTaskCanceledById(gomock.Any(), req).Return(&workflowservice.RespondActivityTaskCanceledByIdResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().RespondActivityTaskCanceledById(gomock.Any(), req).Return(&workflowservice.RespondActivityTaskCanceledByIdResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.RespondActivityTaskCanceledById(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.RespondActivityTaskCanceledByIdResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestRespondActivityTaskCompleted() { - apiName := "RespondActivityTaskCompleted" - - taskToken, err := s.handler.tokenSerializer.Serialize(&tokenspb.Task{ - Attempt: 1, - NamespaceId: s.namespaceID.String(), - }) - s.NoError(err) - req := &workflowservice.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceIDRedirect(gomock.Any(), s.namespaceID, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.ID, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().RespondActivityTaskCompleted(gomock.Any(), req).Return(&workflowservice.RespondActivityTaskCompletedResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().RespondActivityTaskCompleted(gomock.Any(), req).Return(&workflowservice.RespondActivityTaskCompletedResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.RespondActivityTaskCompleted(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.RespondActivityTaskCompletedResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestRespondActivityTaskCompletedById() { - apiName := "RespondActivityTaskCompletedById" - - req := &workflowservice.RespondActivityTaskCompletedByIdRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().RespondActivityTaskCompletedById(gomock.Any(), req).Return(&workflowservice.RespondActivityTaskCompletedByIdResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().RespondActivityTaskCompletedById(gomock.Any(), req).Return(&workflowservice.RespondActivityTaskCompletedByIdResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.RespondActivityTaskCompletedById(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.RespondActivityTaskCompletedByIdResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestRespondActivityTaskFailed() { - apiName := "RespondActivityTaskFailed" - - taskToken, err := s.handler.tokenSerializer.Serialize(&tokenspb.Task{ - Attempt: 1, - NamespaceId: s.namespaceID.String(), - }) - s.NoError(err) - req := &workflowservice.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceIDRedirect(gomock.Any(), s.namespaceID, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.ID, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().RespondActivityTaskFailed(gomock.Any(), req).Return(&workflowservice.RespondActivityTaskFailedResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().RespondActivityTaskFailed(gomock.Any(), req).Return(&workflowservice.RespondActivityTaskFailedResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.RespondActivityTaskFailed(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.RespondActivityTaskFailedResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestRespondActivityTaskFailedById() { - apiName := "RespondActivityTaskFailedById" - - req := &workflowservice.RespondActivityTaskFailedByIdRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().RespondActivityTaskFailedById(gomock.Any(), req).Return(&workflowservice.RespondActivityTaskFailedByIdResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().RespondActivityTaskFailedById(gomock.Any(), req).Return(&workflowservice.RespondActivityTaskFailedByIdResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.RespondActivityTaskFailedById(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.RespondActivityTaskFailedByIdResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestRespondWorkflowTaskCompleted() { - apiName := "RespondWorkflowTaskCompleted" - - taskToken, err := s.handler.tokenSerializer.Serialize(&tokenspb.Task{ - Attempt: 1, - NamespaceId: s.namespaceID.String(), - }) - s.NoError(err) - req := &workflowservice.RespondWorkflowTaskCompletedRequest{ - TaskToken: taskToken, - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceIDRedirect(gomock.Any(), s.namespaceID, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.ID, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().RespondWorkflowTaskCompleted(gomock.Any(), req).Return(&workflowservice.RespondWorkflowTaskCompletedResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().RespondWorkflowTaskCompleted(gomock.Any(), req).Return(&workflowservice.RespondWorkflowTaskCompletedResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.RespondWorkflowTaskCompleted(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.RespondWorkflowTaskCompletedResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestRespondWorkflowTaskFailed() { - apiName := "RespondWorkflowTaskFailed" - - token, err := s.handler.tokenSerializer.Serialize(&tokenspb.Task{ - Attempt: 1, - NamespaceId: s.namespaceID.String(), - }) - s.NoError(err) - req := &workflowservice.RespondWorkflowTaskFailedRequest{ - TaskToken: token, - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceIDRedirect(gomock.Any(), s.namespaceID, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.ID, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().RespondWorkflowTaskFailed(gomock.Any(), req).Return(&workflowservice.RespondWorkflowTaskFailedResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().RespondWorkflowTaskFailed(gomock.Any(), req).Return(&workflowservice.RespondWorkflowTaskFailedResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.RespondWorkflowTaskFailed(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.RespondWorkflowTaskFailedResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestRespondQueryTaskCompleted() { - apiName := "RespondQueryTaskCompleted" - - taskToken, err := s.handler.tokenSerializer.SerializeQueryTaskToken(&tokenspb.QueryTask{ - NamespaceId: s.namespaceID.String(), - }) - s.NoError(err) - req := &workflowservice.RespondQueryTaskCompletedRequest{ - TaskToken: taskToken, - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceIDRedirect(gomock.Any(), s.namespaceID, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.ID, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().RespondQueryTaskCompleted(gomock.Any(), req).Return(&workflowservice.RespondQueryTaskCompletedResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().RespondQueryTaskCompleted(gomock.Any(), req).Return(&workflowservice.RespondQueryTaskCompletedResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.RespondQueryTaskCompleted(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.RespondQueryTaskCompletedResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestSignalWithStartWorkflowExecution() { - apiName := "SignalWithStartWorkflowExecution" - - req := &workflowservice.SignalWithStartWorkflowExecutionRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().SignalWithStartWorkflowExecution(gomock.Any(), req).Return(&workflowservice.SignalWithStartWorkflowExecutionResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().SignalWithStartWorkflowExecution(gomock.Any(), req).Return(&workflowservice.SignalWithStartWorkflowExecutionResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.SignalWithStartWorkflowExecution(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.SignalWithStartWorkflowExecutionResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestSignalWorkflowExecution() { - apiName := "SignalWorkflowExecution" - - req := &workflowservice.SignalWorkflowExecutionRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().SignalWorkflowExecution(gomock.Any(), req).Return(&workflowservice.SignalWorkflowExecutionResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().SignalWorkflowExecution(gomock.Any(), req).Return(&workflowservice.SignalWorkflowExecutionResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.SignalWorkflowExecution(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.SignalWorkflowExecutionResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestStartWorkflowExecution() { - apiName := "StartWorkflowExecution" - - req := &workflowservice.StartWorkflowExecutionRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().StartWorkflowExecution(gomock.Any(), req).Return(&workflowservice.StartWorkflowExecutionResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().StartWorkflowExecution(gomock.Any(), req).Return(&workflowservice.StartWorkflowExecutionResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.StartWorkflowExecution(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.StartWorkflowExecutionResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestTerminateWorkflowExecution() { - apiName := "TerminateWorkflowExecution" - - req := &workflowservice.TerminateWorkflowExecutionRequest{ - Namespace: s.namespace.String(), - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().TerminateWorkflowExecution(gomock.Any(), req).Return(&workflowservice.TerminateWorkflowExecutionResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().TerminateWorkflowExecution(gomock.Any(), req).Return(&workflowservice.TerminateWorkflowExecutionResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.TerminateWorkflowExecution(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.TerminateWorkflowExecutionResponse{}, resp) -} - -func (s *dcRedirectionHandlerSuite) TestListTaskQueuePartitions() { - apiName := "ListTaskQueuePartitions" - - req := &workflowservice.ListTaskQueuePartitionsRequest{ - Namespace: s.namespace.String(), - TaskQueue: &taskqueuepb.TaskQueue{ - Name: "test_tesk_list", - Kind: 0, - }, - } - - s.mockDCRedirectionPolicy.EXPECT().WithNamespaceRedirect(gomock.Any(), s.namespace, apiName, gomock.Any()).DoAndReturn( - func(ctx context.Context, namespace namespace.Name, apiName string, callFn func(string) error) error { - s.mockFrontendHandler.EXPECT().ListTaskQueuePartitions(gomock.Any(), req).Return(&workflowservice.ListTaskQueuePartitionsResponse{}, nil) - err := callFn(s.currentClusterName) - s.NoError(err) - s.mockRemoteFrontendClient.EXPECT().ListTaskQueuePartitions(gomock.Any(), req).Return(&workflowservice.ListTaskQueuePartitionsResponse{}, nil) - err = callFn(s.alternativeClusterName) - s.NoError(err) - return nil - }) - - resp, err := s.handler.ListTaskQueuePartitions(context.Background(), req) - s.NoError(err) - s.Equal(&workflowservice.ListTaskQueuePartitionsResponse{}, resp) -} - -func (serverHandler *testServerHandler) Start() { -} - -func (serverHandler *testServerHandler) Stop() { -} - -func (serverHandler *testServerHandler) GetConfig() *Config { - return nil -} diff --git a/service/frontend/fx.go b/service/frontend/fx.go index f6251c0f5bf..30a21c34de7 100644 --- a/service/frontend/fx.go +++ b/service/frontend/fx.go @@ -75,6 +75,7 @@ var Module = fx.Options( fx.Provide(dynamicconfig.NewCollection), fx.Provide(ConfigProvider), fx.Provide(NamespaceLogInterceptorProvider), + fx.Provide(RedirectionInterceptorProvider), fx.Provide(TelemetryInterceptorProvider), fx.Provide(RetryableInterceptorProvider), fx.Provide(RateLimitInterceptorProvider), @@ -137,6 +138,7 @@ func GrpcServerOptionsProvider( namespaceRateLimiterInterceptor *interceptor.NamespaceRateLimitInterceptor, namespaceCountLimiterInterceptor *interceptor.NamespaceCountLimitInterceptor, namespaceValidatorInterceptor *interceptor.NamespaceValidatorInterceptor, + redirectionInterceptor *RedirectionInterceptor, telemetryInterceptor *interceptor.TelemetryInterceptor, retryableInterceptor *interceptor.RetryableInterceptor, rateLimitInterceptor *interceptor.RateLimitInterceptor, @@ -180,6 +182,7 @@ func GrpcServerOptionsProvider( namespaceLogInterceptor.Intercept, // TODO: Deprecate this with a outer custom interceptor grpc.UnaryServerInterceptor(traceInterceptor), metrics.NewServerMetricsContextInjectorInterceptor(), + redirectionInterceptor.Intercept, telemetryInterceptor.Intercept, authorization.NewAuthorizationInterceptor( claimMapper, @@ -241,6 +244,28 @@ func RetryableInterceptorProvider() *interceptor.RetryableInterceptor { ) } +func RedirectionInterceptorProvider( + configuration *Config, + namespaceCache namespace.Registry, + policy config.DCRedirectionPolicy, + logger log.Logger, + clientBean client.Bean, + metricsHandler metrics.Handler, + timeSource clock.TimeSource, + clusterMetadata cluster.Metadata, +) *RedirectionInterceptor { + return NewRedirectionInterceptor( + configuration, + namespaceCache, + policy, + logger, + clientBean, + metricsHandler, + timeSource, + clusterMetadata, + ) +} + func TelemetryInterceptorProvider( logger log.Logger, metricsHandler metrics.Handler, @@ -414,7 +439,7 @@ func ServiceResolverProvider( func AdminHandlerProvider( persistenceConfig *config.Persistence, - config *Config, + configuration *Config, replicatorNamespaceReplicationQueue FEReplicatorNamespaceReplicationQueue, esClient esclient.Client, visibilityMrg manager.VisibilityManager, @@ -442,7 +467,7 @@ func AdminHandlerProvider( ) *AdminHandler { args := NewAdminHandlerArgs{ persistenceConfig, - config, + configuration, namespaceReplicationQueue, replicatorNamespaceReplicationQueue, esClient, @@ -472,7 +497,7 @@ func AdminHandlerProvider( } func OperatorHandlerProvider( - config *Config, + configuration *Config, esClient esclient.Client, logger log.SnTaggedLogger, sdkClientFactory sdk.ClientFactory, @@ -488,7 +513,7 @@ func OperatorHandlerProvider( clientFactory client.Factory, ) *OperatorHandlerImpl { args := NewOperatorHandlerImplArgs{ - config, + configuration, esClient, logger, sdkClientFactory, @@ -552,8 +577,7 @@ func HandlerProvider( healthServer, timeSource, ) - handler := NewDCRedirectionHandler(wfHandler, dcRedirectionPolicy, logger, clientBean, metricsHandler, timeSource, namespaceRegistry, clusterMetadata) - return handler + return wfHandler } func ServiceLifetimeHooks( diff --git a/service/frontend/operator_handler.go b/service/frontend/operator_handler.go index 830ef9c4e1d..f8a88aa687c 100644 --- a/service/frontend/operator_handler.go +++ b/service/frontend/operator_handler.go @@ -251,7 +251,7 @@ func (h *OperatorHandlerImpl) addSearchAttributesSQL( request *operatorservice.AddSearchAttributesRequest, currentSearchAttributes searchattribute.NameTypeMap, ) error { - client, err := h.clientFactory.NewLocalFrontendClientWithTimeout( + _, client, err := h.clientFactory.NewLocalFrontendClientWithTimeout( frontend.DefaultTimeout, frontend.DefaultLongPollTimeout, ) @@ -371,7 +371,7 @@ func (h *OperatorHandlerImpl) removeSearchAttributesSQL( ctx context.Context, request *operatorservice.RemoveSearchAttributesRequest, ) error { - client, err := h.clientFactory.NewLocalFrontendClientWithTimeout( + _, client, err := h.clientFactory.NewLocalFrontendClientWithTimeout( frontend.DefaultTimeout, frontend.DefaultLongPollTimeout, ) diff --git a/service/frontend/redirection_interceptor.go b/service/frontend/redirection_interceptor.go new file mode 100644 index 00000000000..87d37b1951c --- /dev/null +++ b/service/frontend/redirection_interceptor.go @@ -0,0 +1,254 @@ +// The MIT License +// +// Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. +// +// Copyright (c) 2020 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package frontend + +import ( + "context" + "fmt" + "time" + + "go.temporal.io/api/workflowservice/v1" + "google.golang.org/grpc" + + "go.temporal.io/server/client" + "go.temporal.io/server/common/clock" + "go.temporal.io/server/common/cluster" + "go.temporal.io/server/common/config" + "go.temporal.io/server/common/log" + "go.temporal.io/server/common/metrics" + "go.temporal.io/server/common/namespace" + "go.temporal.io/server/common/rpc/interceptor" +) + +var ( + dcRedirectionMetricsPrefix = "DCRedirection" + + localAPIResults = map[string]respAllocFn{ + // Namespace APIs, namespace APIs does not require redirection + "DeprecateNamespace": func() interface{} { return new(workflowservice.DeprecateNamespaceResponse) }, + "DescribeNamespace": func() interface{} { return new(workflowservice.DescribeNamespaceResponse) }, + "ListNamespaces": func() interface{} { return new(workflowservice.ListNamespacesResponse) }, + "RegisterNamespace": func() interface{} { return new(workflowservice.RegisterNamespaceResponse) }, + "UpdateNamespace": func() interface{} { return new(workflowservice.UpdateNamespaceResponse) }, + + // Cluster info APIs, Cluster info APIs does not require redirection + "GetSearchAttributes": func() interface{} { return new(workflowservice.GetSearchAttributesResponse) }, + "GetClusterInfo": func() interface{} { return new(workflowservice.GetClusterInfoResponse) }, + "GetSystemInfo": func() interface{} { return new(workflowservice.GetSystemInfoResponse) }, + } + + globalAPIResults = map[string]respAllocFn{ + "DescribeTaskQueue": func() interface{} { return new(workflowservice.DescribeTaskQueueResponse) }, + "DescribeWorkflowExecution": func() interface{} { return new(workflowservice.DescribeWorkflowExecutionResponse) }, + "GetWorkflowExecutionHistory": func() interface{} { return new(workflowservice.GetWorkflowExecutionHistoryResponse) }, + "GetWorkflowExecutionHistoryReverse": func() interface{} { return new(workflowservice.GetWorkflowExecutionHistoryReverseResponse) }, + "ListArchivedWorkflowExecutions": func() interface{} { return new(workflowservice.ListArchivedWorkflowExecutionsResponse) }, + "ListClosedWorkflowExecutions": func() interface{} { return new(workflowservice.ListClosedWorkflowExecutionsResponse) }, + "ListOpenWorkflowExecutions": func() interface{} { return new(workflowservice.ListOpenWorkflowExecutionsResponse) }, + "ListWorkflowExecutions": func() interface{} { return new(workflowservice.ListWorkflowExecutionsResponse) }, + "ScanWorkflowExecutions": func() interface{} { return new(workflowservice.ScanWorkflowExecutionsResponse) }, + "CountWorkflowExecutions": func() interface{} { return new(workflowservice.CountWorkflowExecutionsResponse) }, + "PollActivityTaskQueue": func() interface{} { return new(workflowservice.PollActivityTaskQueueResponse) }, + "PollWorkflowTaskQueue": func() interface{} { return new(workflowservice.PollWorkflowTaskQueueResponse) }, + "QueryWorkflow": func() interface{} { return new(workflowservice.QueryWorkflowResponse) }, + "RecordActivityTaskHeartbeat": func() interface{} { return new(workflowservice.RecordActivityTaskHeartbeatResponse) }, + "RecordActivityTaskHeartbeatById": func() interface{} { return new(workflowservice.RecordActivityTaskHeartbeatByIdResponse) }, + "RequestCancelWorkflowExecution": func() interface{} { return new(workflowservice.RequestCancelWorkflowExecutionResponse) }, + "ResetStickyTaskQueue": func() interface{} { return new(workflowservice.ResetStickyTaskQueueResponse) }, + "ResetWorkflowExecution": func() interface{} { return new(workflowservice.ResetWorkflowExecutionResponse) }, + "RespondActivityTaskCanceled": func() interface{} { return new(workflowservice.RespondActivityTaskCanceledResponse) }, + "RespondActivityTaskCanceledById": func() interface{} { return new(workflowservice.RespondActivityTaskCanceledByIdResponse) }, + "RespondActivityTaskCompleted": func() interface{} { return new(workflowservice.RespondActivityTaskCompletedResponse) }, + "RespondActivityTaskCompletedById": func() interface{} { return new(workflowservice.RespondActivityTaskCompletedByIdResponse) }, + "RespondActivityTaskFailed": func() interface{} { return new(workflowservice.RespondActivityTaskFailedResponse) }, + "RespondActivityTaskFailedById": func() interface{} { return new(workflowservice.RespondActivityTaskFailedByIdResponse) }, + "RespondWorkflowTaskCompleted": func() interface{} { return new(workflowservice.RespondWorkflowTaskCompletedResponse) }, + "RespondWorkflowTaskFailed": func() interface{} { return new(workflowservice.RespondWorkflowTaskFailedResponse) }, + "RespondQueryTaskCompleted": func() interface{} { return new(workflowservice.RespondQueryTaskCompletedResponse) }, + "SignalWithStartWorkflowExecution": func() interface{} { return new(workflowservice.SignalWithStartWorkflowExecutionResponse) }, + "SignalWorkflowExecution": func() interface{} { return new(workflowservice.SignalWorkflowExecutionResponse) }, + "StartWorkflowExecution": func() interface{} { return new(workflowservice.StartWorkflowExecutionResponse) }, + "UpdateWorkflowExecution": func() interface{} { return new(workflowservice.UpdateWorkflowExecutionResponse) }, + "TerminateWorkflowExecution": func() interface{} { return new(workflowservice.TerminateWorkflowExecutionResponse) }, + "DeleteWorkflowExecution": func() interface{} { return new(workflowservice.DeleteWorkflowExecutionResponse) }, + "ListTaskQueuePartitions": func() interface{} { return new(workflowservice.ListTaskQueuePartitionsResponse) }, + + "CreateSchedule": func() interface{} { return new(workflowservice.CreateScheduleResponse) }, + "DescribeSchedule": func() interface{} { return new(workflowservice.DescribeScheduleResponse) }, + "UpdateSchedule": func() interface{} { return new(workflowservice.UpdateScheduleResponse) }, + "PatchSchedule": func() interface{} { return new(workflowservice.PatchScheduleResponse) }, + "DeleteSchedule": func() interface{} { return new(workflowservice.DeleteScheduleResponse) }, + "ListSchedules": func() interface{} { return new(workflowservice.ListSchedulesResponse) }, + "ListScheduleMatchingTimes": func() interface{} { return new(workflowservice.ListScheduleMatchingTimesResponse) }, + "UpdateWorkerBuildIdOrdering": func() interface{} { return new(workflowservice.UpdateWorkerBuildIdOrderingResponse) }, + "GetWorkerBuildIdOrdering": func() interface{} { return new(workflowservice.GetWorkerBuildIdOrderingResponse) }, + + "StartBatchOperation": func() interface{} { return new(workflowservice.StartBatchOperationResponse) }, + "StopBatchOperation": func() interface{} { return new(workflowservice.StopBatchOperationResponse) }, + "DescribeBatchOperation": func() interface{} { return new(workflowservice.DescribeBatchOperationResponse) }, + "ListBatchOperations": func() interface{} { return new(workflowservice.ListBatchOperationsResponse) }, + } +) + +type ( + respAllocFn func() interface{} + + // RedirectionInterceptor is simple wrapper over frontend service, doing redirection based on policy + RedirectionInterceptor struct { + currentClusterName string + config *Config + namespaceCache namespace.Registry + redirectionPolicy DCRedirectionPolicy + logger log.Logger + clientBean client.Bean + metricsHandler metrics.Handler + timeSource clock.TimeSource + } +) + +// NewRedirectionInterceptor creates DC redirection interceptor +func NewRedirectionInterceptor( + configuration *Config, + namespaceCache namespace.Registry, + policy config.DCRedirectionPolicy, + logger log.Logger, + clientBean client.Bean, + metricsHandler metrics.Handler, + timeSource clock.TimeSource, + clusterMetadata cluster.Metadata, +) *RedirectionInterceptor { + dcRedirectionPolicy := RedirectionPolicyGenerator( + clusterMetadata, + configuration, + namespaceCache, + policy, + ) + + return &RedirectionInterceptor{ + currentClusterName: clusterMetadata.GetCurrentClusterName(), + config: configuration, + redirectionPolicy: dcRedirectionPolicy, + namespaceCache: namespaceCache, + logger: logger, + clientBean: clientBean, + metricsHandler: metricsHandler, + timeSource: timeSource, + } +} + +var _ grpc.UnaryServerInterceptor = (*RedirectionInterceptor)(nil).Intercept + +func (i *RedirectionInterceptor) Intercept( + ctx context.Context, + req interface{}, + info *grpc.UnaryServerInfo, + handler grpc.UnaryHandler, +) (_ interface{}, retError error) { + defer log.CapturePanic(i.logger, &retError) + + _, methodName := interceptor.SplitMethodName(info.FullMethod) + if _, ok := localAPIResults[methodName]; ok { + return i.handleLocalAPIInvocation(ctx, req, handler, methodName) + } + if respAllocFn, ok := globalAPIResults[methodName]; ok { + namespaceName := interceptor.GetNamespace(i.namespaceCache, req) + return i.handleRedirectAPIInvocation(ctx, req, info, handler, methodName, respAllocFn, namespaceName) + } + + // this should not happen, log warn and move on + i.logger.Warn(fmt.Sprintf("RedirectionInterceptor encountered unknown API: %v", methodName)) + return handler(ctx, req) +} + +func (i *RedirectionInterceptor) handleLocalAPIInvocation( + ctx context.Context, + req interface{}, + handler grpc.UnaryHandler, + methodName string, +) (_ interface{}, retError error) { + scope, startTime := i.beforeCall(dcRedirectionMetricsPrefix + methodName) + defer func() { + i.afterCall(scope, startTime, i.currentClusterName, retError) + }() + return handler(ctx, req) +} + +func (i *RedirectionInterceptor) handleRedirectAPIInvocation( + ctx context.Context, + req interface{}, + info *grpc.UnaryServerInfo, + handler grpc.UnaryHandler, + methodName string, + respAllocFn func() interface{}, + namespaceName namespace.Name, +) (_ interface{}, retError error) { + var resp interface{} + var clusterName string + var err error + + scope, startTime := i.beforeCall(dcRedirectionMetricsPrefix + methodName) + defer func() { + i.afterCall(scope, startTime, clusterName, retError) + }() + + err = i.redirectionPolicy.WithNamespaceRedirect(ctx, namespaceName, methodName, func(targetDC string) error { + clusterName = targetDC + if targetDC == i.currentClusterName { + resp, err = handler(ctx, req) + } else { + remoteClient, _, err := i.clientBean.GetRemoteFrontendClient(targetDC) + if err != nil { + return err + } + resp = respAllocFn() + err = remoteClient.Invoke(ctx, info.FullMethod, req, resp) + if err != nil { + return err + } + } + return err + }) + return resp, err +} + +func (i *RedirectionInterceptor) beforeCall( + operation string, +) (metrics.Handler, time.Time) { + return i.metricsHandler.WithTags(metrics.OperationTag(operation), metrics.ServiceRoleTag(metrics.DCRedirectionRoleTagValue)), i.timeSource.Now() +} + +func (i *RedirectionInterceptor) afterCall( + metricsHandler metrics.Handler, + startTime time.Time, + clusterName string, + retError error, +) { + metricsHandler = metricsHandler.WithTags(metrics.TargetClusterTag(clusterName)) + metricsHandler.Counter(metrics.ClientRedirectionRequests.GetMetricName()).Record(1) + metricsHandler.Timer(metrics.ClientRedirectionLatency.GetMetricName()).Record(i.timeSource.Now().Sub(startTime)) + if retError != nil { + metricsHandler.Counter(metrics.ClientRedirectionFailures.GetMetricName()).Record(1) + } +} diff --git a/service/frontend/redirection_interceptor_test.go b/service/frontend/redirection_interceptor_test.go new file mode 100644 index 00000000000..ad2e1378730 --- /dev/null +++ b/service/frontend/redirection_interceptor_test.go @@ -0,0 +1,332 @@ +// The MIT License +// +// Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. +// +// Copyright (c) 2020 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package frontend + +import ( + "context" + "reflect" + "testing" + + "github.com/golang/mock/gomock" + "github.com/google/uuid" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "go.temporal.io/api/workflowservice/v1" + "google.golang.org/grpc" + + persistencespb "go.temporal.io/server/api/persistence/v1" + "go.temporal.io/server/client" + "go.temporal.io/server/common/clock" + "go.temporal.io/server/common/cluster" + "go.temporal.io/server/common/config" + "go.temporal.io/server/common/dynamicconfig" + "go.temporal.io/server/common/log" + "go.temporal.io/server/common/metrics" + "go.temporal.io/server/common/namespace" + "go.temporal.io/server/common/primitives/timestamp" +) + +type ( + redirectionInterceptorSuite struct { + suite.Suite + *require.Assertions + + controller *gomock.Controller + namespaceCache *namespace.MockRegistry + clientBean *client.MockBean + clusterMetadata *cluster.MockMetadata + + redirector *RedirectionInterceptor + } +) + +func TestRedirectionInterceptorSuite(t *testing.T) { + s := new(redirectionInterceptorSuite) + suite.Run(t, s) +} + +func (s *redirectionInterceptorSuite) SetupSuite() { +} + +func (s *redirectionInterceptorSuite) TearDownSuite() { +} + +func (s *redirectionInterceptorSuite) SetupTest() { + s.Assertions = require.New(s.T()) + s.controller = gomock.NewController(s.T()) + s.namespaceCache = namespace.NewMockRegistry(s.controller) + s.clientBean = client.NewMockBean(s.controller) + s.clusterMetadata = cluster.NewMockMetadata(s.controller) + + s.clusterMetadata.EXPECT().GetCurrentClusterName().Return(cluster.TestCurrentClusterName).AnyTimes() + + s.redirector = NewRedirectionInterceptor( + NewConfig( + dynamicconfig.NewNoopCollection(), + 1, + false, + ), + s.namespaceCache, + config.DCRedirectionPolicy{ + Policy: DCRedirectionPolicyAllAPIsForwarding, + }, + log.NewNoopLogger(), + s.clientBean, + metrics.NoopMetricsHandler, + clock.NewRealTimeSource(), + s.clusterMetadata, + ) +} + +func (s *redirectionInterceptorSuite) TearDownTest() { + s.controller.Finish() +} + +func (s *redirectionInterceptorSuite) TestLocalAPI() { + apis := make(map[string]struct{}) + for api := range localAPIResults { + apis[api] = struct{}{} + } + s.Equal(map[string]struct{}{ + "DeprecateNamespace": {}, + "DescribeNamespace": {}, + "ListNamespaces": {}, + "RegisterNamespace": {}, + "UpdateNamespace": {}, + + "GetSearchAttributes": {}, + "GetClusterInfo": {}, + "GetSystemInfo": {}, + }, apis) +} + +func (s *redirectionInterceptorSuite) TestGlobalAPI() { + apis := make(map[string]struct{}) + for api := range globalAPIResults { + apis[api] = struct{}{} + } + s.Equal(map[string]struct{}{ + "DescribeTaskQueue": {}, + "DescribeWorkflowExecution": {}, + "GetWorkflowExecutionHistory": {}, + "GetWorkflowExecutionHistoryReverse": {}, + "ListArchivedWorkflowExecutions": {}, + "ListClosedWorkflowExecutions": {}, + "ListOpenWorkflowExecutions": {}, + "ListWorkflowExecutions": {}, + "ScanWorkflowExecutions": {}, + "CountWorkflowExecutions": {}, + "PollActivityTaskQueue": {}, + "PollWorkflowTaskQueue": {}, + "QueryWorkflow": {}, + "RecordActivityTaskHeartbeat": {}, + "RecordActivityTaskHeartbeatById": {}, + "RequestCancelWorkflowExecution": {}, + "ResetStickyTaskQueue": {}, + "ResetWorkflowExecution": {}, + "RespondActivityTaskCanceled": {}, + "RespondActivityTaskCanceledById": {}, + "RespondActivityTaskCompleted": {}, + "RespondActivityTaskCompletedById": {}, + "RespondActivityTaskFailed": {}, + "RespondActivityTaskFailedById": {}, + "RespondWorkflowTaskCompleted": {}, + "RespondWorkflowTaskFailed": {}, + "RespondQueryTaskCompleted": {}, + "SignalWithStartWorkflowExecution": {}, + "SignalWorkflowExecution": {}, + "StartWorkflowExecution": {}, + "UpdateWorkflowExecution": {}, + "TerminateWorkflowExecution": {}, + "DeleteWorkflowExecution": {}, + "ListTaskQueuePartitions": {}, + + "CreateSchedule": {}, + "DescribeSchedule": {}, + "UpdateSchedule": {}, + "PatchSchedule": {}, + "DeleteSchedule": {}, + "ListSchedules": {}, + "ListScheduleMatchingTimes": {}, + "UpdateWorkerBuildIdOrdering": {}, + "GetWorkerBuildIdOrdering": {}, + + "StartBatchOperation": {}, + "StopBatchOperation": {}, + "DescribeBatchOperation": {}, + "ListBatchOperations": {}, + }, apis) +} + +func (s *redirectionInterceptorSuite) TestAPIResultMapping() { + var service workflowservice.WorkflowServiceServer + t := reflect.TypeOf(&service).Elem() + expectedAPIs := make(map[string]interface{}, t.NumMethod()) + for i := 0; i < t.NumMethod(); i++ { + expectedAPIs[t.Method(i).Name] = t.Method(i).Type.Out(0) + } + + actualAPIs := make(map[string]interface{}) + for api, respAllocFn := range localAPIResults { + actualAPIs[api] = reflect.TypeOf(respAllocFn()) + } + for api, respAllocFn := range globalAPIResults { + actualAPIs[api] = reflect.TypeOf(respAllocFn()) + } + s.Equal(expectedAPIs, actualAPIs) +} + +func (s *redirectionInterceptorSuite) TestHandleLocalAPIInvocation() { + ctx := context.Background() + req := &workflowservice.RegisterNamespaceRequest{} + functionInvoked := false + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + functionInvoked = true + return &workflowservice.RegisterNamespaceResponse{}, nil + } + methodName := "RegisterNamespace" + + resp, err := s.redirector.handleLocalAPIInvocation( + ctx, + req, + handler, + methodName, + ) + s.NoError(err) + s.IsType(&workflowservice.RegisterNamespaceResponse{}, resp) + s.True(functionInvoked) +} + +func (s *redirectionInterceptorSuite) TestHandleGlobalAPIInvocation_Local() { + ctx := context.Background() + req := &workflowservice.SignalWithStartWorkflowExecutionRequest{} + info := &grpc.UnaryServerInfo{} + functionInvoked := false + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + functionInvoked = true + return &workflowservice.SignalWithStartWorkflowExecutionResponse{}, nil + } + namespaceName := namespace.Name("(╯°Д°)╯ ┻━┻") + namespaceEntry := namespace.NewGlobalNamespaceForTest( + &persistencespb.NamespaceInfo{Id: uuid.NewString(), Name: namespaceName.String()}, + &persistencespb.NamespaceConfig{Retention: timestamp.DurationFromDays(1)}, + &persistencespb.NamespaceReplicationConfig{ + ActiveClusterName: cluster.TestCurrentClusterName, + Clusters: []string{ + cluster.TestCurrentClusterName, + cluster.TestAlternativeClusterName, + }, + }, + 1, + ) + s.namespaceCache.EXPECT().GetNamespace(namespaceName).Return(namespaceEntry, nil).AnyTimes() + methodName := "SignalWithStartWorkflowExecution" + + resp, err := s.redirector.handleRedirectAPIInvocation( + ctx, + req, + info, + handler, + methodName, + globalAPIResults[methodName], + namespaceName, + ) + s.NoError(err) + s.IsType(&workflowservice.SignalWithStartWorkflowExecutionResponse{}, resp) + s.True(functionInvoked) +} + +func (s *redirectionInterceptorSuite) TestHandleLocalAPIInvocation_Redirect() { + ctx := context.Background() + req := &workflowservice.SignalWithStartWorkflowExecutionRequest{} + info := &grpc.UnaryServerInfo{ + FullMethod: "/temporal.api.workflowservice.v1.WorkflowService/SignalWithStartWorkflowExecution", + } + namespaceName := namespace.Name("(╯°Д°)╯ ┻━┻") + namespaceEntry := namespace.NewGlobalNamespaceForTest( + &persistencespb.NamespaceInfo{Id: uuid.NewString(), Name: namespaceName.String()}, + &persistencespb.NamespaceConfig{Retention: timestamp.DurationFromDays(1)}, + &persistencespb.NamespaceReplicationConfig{ + ActiveClusterName: cluster.TestAlternativeClusterName, + Clusters: []string{ + cluster.TestCurrentClusterName, + cluster.TestAlternativeClusterName, + }, + }, + 1, + ) + s.namespaceCache.EXPECT().GetNamespace(namespaceName).Return(namespaceEntry, nil).AnyTimes() + methodName := "SignalWithStartWorkflowExecution" + + grpcConn := &mockClientConnInterface{ + Suite: &s.Suite, + targetMethod: info.FullMethod, + targetResponse: &workflowservice.SignalWithStartWorkflowExecutionResponse{}, + } + s.clientBean.EXPECT().GetRemoteFrontendClient(cluster.TestAlternativeClusterName).Return(grpcConn, nil, nil).Times(1) + + resp, err := s.redirector.handleRedirectAPIInvocation( + ctx, + req, + info, + nil, + methodName, + globalAPIResults[methodName], + namespaceName, + ) + s.NoError(err) + s.IsType(&workflowservice.SignalWithStartWorkflowExecutionResponse{}, resp) +} + +type ( + mockClientConnInterface struct { + *suite.Suite + targetMethod string + targetResponse interface{} + } +) + +var _ grpc.ClientConnInterface = (*mockClientConnInterface)(nil) + +func (s *mockClientConnInterface) Invoke( + _ context.Context, + method string, + _ interface{}, + reply interface{}, + _ ...grpc.CallOption, +) error { + s.Equal(s.targetMethod, method) + s.Equal(s.targetResponse, reply) + return nil +} + +func (s *mockClientConnInterface) NewStream( + _ context.Context, + _ *grpc.StreamDesc, + _ string, + _ ...grpc.CallOption, +) (grpc.ClientStream, error) { + panic("implement me") +} diff --git a/service/worker/parentclosepolicy/workflow.go b/service/worker/parentclosepolicy/workflow.go index c89b8d6e47c..5b280d6b4a6 100644 --- a/service/worker/parentclosepolicy/workflow.go +++ b/service/worker/parentclosepolicy/workflow.go @@ -198,7 +198,7 @@ func signalRemoteCluster( numWorkflows int, ) error { for cluster, executions := range remoteExecutions { - remoteClient, err := clientBean.GetRemoteFrontendClient(cluster) + _, remoteClient, err := clientBean.GetRemoteFrontendClient(cluster) if err != nil { return err } diff --git a/service/worker/parentclosepolicy/workflow_test.go b/service/worker/parentclosepolicy/workflow_test.go index 804ccdb7aa2..fc090738966 100644 --- a/service/worker/parentclosepolicy/workflow_test.go +++ b/service/worker/parentclosepolicy/workflow_test.go @@ -28,7 +28,7 @@ import ( "context" "testing" - gomock "github.com/golang/mock/gomock" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" commonpb "go.temporal.io/api/common/v1" @@ -77,7 +77,7 @@ func (s *parentClosePolicyWorkflowSuite) SetupTest() { s.mockRemoteClient = workflowservicemock.NewMockWorkflowServiceClient(s.controller) s.mockClientBean.EXPECT().GetHistoryClient().Return(s.mockHistoryClient).AnyTimes() - s.mockClientBean.EXPECT().GetRemoteFrontendClient(gomock.Any()).Return(s.mockRemoteClient, nil).AnyTimes() + s.mockClientBean.EXPECT().GetRemoteFrontendClient(gomock.Any()).Return(nil, s.mockRemoteClient, nil).AnyTimes() s.processor = &Processor{ metricsHandler: metrics.NoopMetricsHandler,