gitee.com/h79/goutils@v1.22.10/rpc/client.go (about)

     1  package rpc
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"gitee.com/h79/goutils/alarm"
     7  	"gitee.com/h79/goutils/common/logger"
     8  	"gitee.com/h79/goutils/common/result"
     9  	"google.golang.org/grpc"
    10  	"google.golang.org/grpc/credentials/insecure"
    11  	"google.golang.org/grpc/health/grpc_health_v1"
    12  	"sync"
    13  	"time"
    14  )
    15  
    16  func NewClient(addr string, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
    17  	logger.D("rpc", "NewClient, addr= %s", addr)
    18  	var dialOpts []grpc.DialOption
    19  	if len(opts) <= 0 {
    20  		dialOpts = append(dialOpts, grpc.WithTransportCredentials(insecure.NewCredentials()))
    21  	} else {
    22  		dialOpts = append(dialOpts, opts...)
    23  	}
    24  	conn, err := grpc.Dial(addr, dialOpts...)
    25  	if err != nil {
    26  		return nil, result.Errorf(result.ErrClientConnectInternal, "did not connect failure, err= %v", err).Log()
    27  	}
    28  	return conn, nil
    29  }
    30  
    31  func Close(client *grpc.ClientConn) {
    32  	if client != nil {
    33  		_ = client.Close()
    34  	}
    35  }
    36  
    37  type Client struct {
    38  	Config
    39  	health HealthClient
    40  	conn   *grpc.ClientConn
    41  	rm     sync.Mutex
    42  }
    43  
    44  func (cli *Client) CreateConnect(opts ...grpc.DialOption) (*grpc.ClientConn, error) {
    45  	cli.rm.Lock()
    46  	defer cli.rm.Unlock()
    47  	err := cli.connect(opts...)
    48  	return cli.conn, err
    49  }
    50  
    51  func (cli *Client) connect(opts ...grpc.DialOption) error {
    52  	if cli.conn != nil {
    53  		return nil
    54  	}
    55  	conn, err := NewClient(cli.Server, opts...)
    56  	if err != nil {
    57  		return err
    58  	}
    59  	cli.conn = conn
    60  	return nil
    61  }
    62  
    63  func (cli *Client) Close() {
    64  	cli.close(cli.conn)
    65  }
    66  
    67  func (cli *Client) close(conn *grpc.ClientConn) {
    68  	var c = conn
    69  	cli.rm.Lock()
    70  	if conn == cli.conn {
    71  		c = cli.conn
    72  		cli.conn = nil
    73  	}
    74  	cli.rm.Unlock()
    75  	Close(c)
    76  }
    77  
    78  func (cli *Client) CheckHealth() (int, error) {
    79  	start := time.Now()
    80  	conn, err := cli.CreateConnect()
    81  	if err != nil {
    82  		return 0, err
    83  	}
    84  	// Set up a connection to the server.
    85  	if conn == nil {
    86  		return int(grpc_health_v1.HealthCheckResponse_UNKNOWN), result.RErrNil
    87  	}
    88  
    89  	rsp, err := cli.health.Check(conn, cli.Service, cli.Timeout)
    90  
    91  	if err != nil {
    92  		const method = "Check"
    93  		return rsp, cli.HandlerError(conn, err, start, method)
    94  	}
    95  	return rsp, nil
    96  }
    97  
    98  func (cli *Client) WatchHealth() (grpc_health_v1.Health_WatchClient, error) {
    99  	start := time.Now()
   100  	conn, err := cli.CreateConnect()
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	// Set up a connection to the server.
   105  	if conn == nil {
   106  		return nil, result.RErrNil
   107  	}
   108  
   109  	rsp, err := cli.health.Watch(conn, cli.Service, cli.Timeout)
   110  
   111  	if err != nil {
   112  		const method = "Watch"
   113  		return nil, cli.HandlerError(conn, err, start, method)
   114  	}
   115  	return rsp, nil
   116  }
   117  
   118  // HandlerError "State":"IDLE","Status":"rpc error: code = Unknown desc = rpc error: code = DeadlineExceeded desc = context deadline exceeded"}
   119  func (cli *Client) HandlerError(conn *grpc.ClientConn, err error, start time.Time, method string) error {
   120  	st := WithStatus(err)
   121  	if st != nil {
   122  		logger.E("rpc", "HandlerError connState= %s, status= %s", conn.GetState().String(), st.String())
   123  		if IsNeedAlarm(st) {
   124  			cli.close(conn)
   125  			cli.Alarm(method, time.Now().Sub(start), err)
   126  		}
   127  		if IsDeadlineExceeded(st) {
   128  			return result.ErrCode(result.ErrDeadlineExceeded).WithError(err)
   129  		}
   130  	}
   131  	return err
   132  }
   133  
   134  func (cli *Client) Alarm(method string, latency time.Duration, err error) {
   135  	alarm.Fatal(context.Background(), -1, "rpc", cli.Title, fmt.Sprintf("method= '%s',url= '%s',latency= '%v'", method, cli.Server, latency), err)
   136  }