github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/master/workerrpc/rawgrpc.go (about) 1 // Copyright 2019 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package workerrpc 15 16 import ( 17 "context" 18 "time" 19 20 toolutils "github.com/pingcap/tidb-tools/pkg/utils" 21 "github.com/pingcap/tiflow/dm/config/security" 22 "github.com/pingcap/tiflow/dm/pb" 23 "github.com/pingcap/tiflow/dm/pkg/terror" 24 "go.uber.org/atomic" 25 "google.golang.org/grpc" 26 "google.golang.org/grpc/backoff" 27 ) 28 29 // GRPCClient stores raw grpc connection and worker client. 30 type GRPCClient struct { 31 conn *grpc.ClientConn 32 client pb.WorkerClient 33 closed atomic.Bool 34 } 35 36 // NewGRPCClientWrap initializes a new grpc client from given grpc connection and worker client. 37 func NewGRPCClientWrap(conn *grpc.ClientConn, client pb.WorkerClient) (*GRPCClient, error) { 38 return &GRPCClient{ 39 conn: conn, 40 client: client, 41 }, nil 42 } 43 44 // NewGRPCClient initializes a new grpc client from worker address. 45 func NewGRPCClient(addr string, securityCfg security.Security) (*GRPCClient, error) { 46 tls, err := toolutils.NewTLS(securityCfg.SSLCA, securityCfg.SSLCert, securityCfg.SSLKey, addr, securityCfg.CertAllowedCN) 47 if err != nil { 48 return nil, terror.ErrMasterGRPCCreateConn.Delegate(err) 49 } 50 51 conn, err := grpc.Dial(addr, tls.ToGRPCDialOption(), 52 grpc.WithConnectParams(grpc.ConnectParams{ 53 Backoff: backoff.Config{ 54 BaseDelay: 100 * time.Millisecond, 55 Multiplier: 1.6, // Default 56 Jitter: 0.2, // Default 57 MaxDelay: 3 * time.Second, 58 }, 59 MinConnectTimeout: 3 * time.Second, 60 })) 61 if err != nil { 62 return nil, terror.ErrMasterGRPCCreateConn.Delegate(err) 63 } 64 return NewGRPCClientWrap(conn, pb.NewWorkerClient(conn)) 65 } 66 67 // SendRequest implements Client.SendRequest. 68 func (c *GRPCClient) SendRequest(ctx context.Context, req *Request, timeout time.Duration) (*Response, error) { 69 if c.closed.Load() { 70 return nil, terror.ErrMasterGRPCSendOnCloseConn.Generate() 71 } 72 if req.IsStreamAPI() { 73 // call stream API and returns a grpc stream client 74 return callRPC(ctx, c.client, req) 75 } 76 // call normal grpc request with a timeout 77 ctx1, cancel := context.WithTimeout(ctx, timeout) 78 defer cancel() 79 return callRPC(ctx1, c.client, req) 80 } 81 82 // Close implements Client.Close. 83 func (c *GRPCClient) Close() error { 84 defer func() { 85 c.closed.CAS(false, true) 86 c.conn = nil 87 }() 88 if c.conn == nil { 89 return nil 90 } 91 if err := c.conn.Close(); err != nil { 92 return terror.ErrMasterGRPCClientClose.Delegate(err) 93 } 94 return nil 95 } 96 97 // Closed returns whether this grpc conn is closed. only used for test now. 98 func (c *GRPCClient) Closed() bool { 99 return c.closed.Load() 100 } 101 102 func callRPC(ctx context.Context, client pb.WorkerClient, req *Request) (*Response, error) { 103 resp := &Response{} 104 resp.Type = req.Type 105 var err error 106 switch req.Type { 107 case CmdQueryStatus: 108 resp.QueryStatus, err = client.QueryStatus(ctx, req.QueryStatus) 109 case CmdPurgeRelay: 110 resp.PurgeRelay, err = client.PurgeRelay(ctx, req.PurgeRelay) 111 case CmdOperateSchema: 112 resp.OperateSchema, err = client.OperateSchema(ctx, req.OperateSchema) 113 case CmdOperateV1Meta: 114 resp.OperateV1Meta, err = client.OperateV1Meta(ctx, req.OperateV1Meta) 115 case CmdHandleError: 116 resp.HandleError, err = client.HandleError(ctx, req.HandleError) 117 case CmdGetWorkerCfg: 118 resp.GetWorkerCfg, err = client.GetWorkerCfg(ctx, req.GetWorkerCfg) 119 case CmdCheckSubtasksCanUpdate: 120 resp.CheckSubtasksCanUpdate, err = client.CheckSubtasksCanUpdate(ctx, req.CheckSubtasksCanUpdate) 121 case CmdGetValidationStatus: 122 resp.GetValidationStatus, err = client.GetWorkerValidatorStatus(ctx, req.GetValidationStatus) 123 case CmdGetValidationError: 124 resp.GetValidationError, err = client.GetValidatorError(ctx, req.GetValidationError) 125 case CmdOperateValidationError: 126 resp.OperateValidationError, err = client.OperateValidatorError(ctx, req.OperateValidationError) 127 case CmdUpdateValidation: 128 resp.UpdateValidation, err = client.UpdateValidator(ctx, req.UpdateValidation) 129 default: 130 return nil, terror.ErrMasterGRPCInvalidReqType.Generate(req.Type) 131 } 132 if err != nil { 133 return nil, terror.ErrMasterGRPCRequestError.Delegate(err) 134 } 135 return resp, nil 136 }