update
This commit is contained in:
154
mygrpc/grpcc/client.go
Normal file
154
mygrpc/grpcc/client.go
Normal file
@@ -0,0 +1,154 @@
|
||||
package grpcc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"git.makemake.in/kzkzzzz/mycommon/myconf"
|
||||
"git.makemake.in/kzkzzzz/mycommon/mygrpc"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/keepalive"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ClientConf struct {
|
||||
useDefaultBufferCfg bool
|
||||
conf *myconf.Config
|
||||
grpcOpts []grpc.DialOption
|
||||
unaryMiddlewares []grpc.UnaryClientInterceptor
|
||||
}
|
||||
|
||||
type Opt func(*ClientConf)
|
||||
|
||||
func UseDefaultBufferCfg(v bool) Opt {
|
||||
return func(c *ClientConf) {
|
||||
c.useDefaultBufferCfg = v
|
||||
}
|
||||
}
|
||||
|
||||
func WithConf(v *myconf.Config) Opt {
|
||||
return func(c *ClientConf) {
|
||||
c.conf = v
|
||||
}
|
||||
}
|
||||
|
||||
func WithGrpcOpts(v ...grpc.DialOption) Opt {
|
||||
return func(c *ClientConf) {
|
||||
c.grpcOpts = v
|
||||
}
|
||||
}
|
||||
|
||||
func WithUnaryMiddlewares(v ...grpc.UnaryClientInterceptor) Opt {
|
||||
return func(c *ClientConf) {
|
||||
c.unaryMiddlewares = append(c.unaryMiddlewares, v...)
|
||||
}
|
||||
}
|
||||
|
||||
func MustNew(grpcUrl string, opts ...Opt) *grpc.ClientConn {
|
||||
client, err := New(grpcUrl, opts...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
func New(grpcUrl string, opts ...Opt) (*grpc.ClientConn, error) {
|
||||
log.Printf("new grpc client url: %s", grpcUrl)
|
||||
|
||||
c := &ClientConf{
|
||||
useDefaultBufferCfg: true,
|
||||
unaryMiddlewares: []grpc.UnaryClientInterceptor{WrapRequestError()}, // 默认加上错误包装
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(c)
|
||||
}
|
||||
|
||||
dialOpts := []grpc.DialOption{
|
||||
grpc.WithKeepaliveParams(keepalive.ClientParameters{
|
||||
Time: time.Second * 20, // 如果没有activity,则每隔N s发送一个ping包
|
||||
Timeout: time.Second * 5, // 如果ping ack N s之内未返回则认为连接已断开
|
||||
PermitWithoutStream: true, // 如果没有active的stream,是否允许发送ping
|
||||
}),
|
||||
// 参考 https://github.com/grpc/grpc-go/tree/master/examples/features/load_balancing 设置轮训策略
|
||||
grpc.WithDefaultServiceConfig(`{"loadBalancingConfig": [{"round_robin":{}}]}`), // This sets the initial balancing policy.
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
}
|
||||
|
||||
// 使用默认的buffer调整配置
|
||||
if c.useDefaultBufferCfg {
|
||||
dialOpts = append(dialOpts,
|
||||
grpc.WithInitialWindowSize(mygrpc.DefaultWindowSize),
|
||||
grpc.WithInitialConnWindowSize(mygrpc.DefaultWindowSize),
|
||||
|
||||
grpc.WithReadBufferSize(mygrpc.DefaultReadBufferSize),
|
||||
grpc.WithWriteBufferSize(mygrpc.DefaultWriteBufferSize),
|
||||
|
||||
grpc.WithUnaryInterceptor(WrapRequestError()),
|
||||
)
|
||||
}
|
||||
|
||||
if len(c.unaryMiddlewares) > 0 {
|
||||
grpc.WithChainUnaryInterceptor(c.unaryMiddlewares...)
|
||||
}
|
||||
|
||||
if len(c.grpcOpts) > 0 {
|
||||
dialOpts = append(dialOpts, c.grpcOpts...)
|
||||
}
|
||||
|
||||
conn, err := grpc.NewClient(
|
||||
grpcUrl,
|
||||
dialOpts...,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func WrapRequestError() grpc.UnaryClientInterceptor {
|
||||
return func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
|
||||
// 提取服务名称
|
||||
var serviceName string
|
||||
if md, ok := metadata.FromOutgoingContext(ctx); ok {
|
||||
if v := md.Get(mygrpc.HeaderServiceName); len(v) > 0 {
|
||||
serviceName = v[0]
|
||||
}
|
||||
}
|
||||
|
||||
err := invoker(ctx, method, req, reply, cc, opts...)
|
||||
if err != nil {
|
||||
|
||||
if serviceName != "" {
|
||||
return fmt.Errorf("request grpc err: [%s - %s] %s", serviceName, method, err)
|
||||
}
|
||||
|
||||
return fmt.Errorf("request grpc err: [%s] %s", method, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Timeout 客户端超时
|
||||
func Timeout(timeout time.Duration) grpc.UnaryClientInterceptor {
|
||||
return func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
|
||||
tCtx, cancel := context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
|
||||
err := invoker(tCtx, method, req, reply, cc, opts...)
|
||||
|
||||
if v, ok := status.FromError(err); ok && v.Code() == codes.DeadlineExceeded {
|
||||
//return status.Errorf(grpcserver.Timeout, "call %s timeout %s", method, timeout)
|
||||
return mygrpc.GrpcClientTimeout("request timeout: %s", timeout)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user