package generic import ( "context" "fmt" "sig-pub/pkg/utils/collect" "sig-pub/pkg/utils/retry" "sig-pub/pkg/zlog" "time" "google.golang.org/grpc" ) type GrpcGenericClientFactory struct { scheme string defaultOpts []grpc.DialOption clientCache *collect.ConcurrentMap[string, *GrpcGenericClient] } func NewGpcGenericClientFactory(scheme string, defaultOpts ...grpc.DialOption) *GrpcGenericClientFactory { return &GrpcGenericClientFactory{ scheme: scheme, defaultOpts: defaultOpts, } } func (f *GrpcGenericClientFactory) Init() (err error) { f.clientCache = collect.NewConcurrentMap[string, *GrpcGenericClient](8, func(serviceName string) string { return serviceName }) return } func (f *GrpcGenericClientFactory) NewClient(ctx context.Context, serviceName string, opts ...grpc.DialOption) (client *GrpcGenericClient, err error) { addr := fmt.Sprintf("%s:///%s", f.scheme, serviceName) dialOpts := make([]grpc.DialOption, 0, len(f.defaultOpts)+len(opts)) dialOpts = append(dialOpts, f.defaultOpts...) dialOpts = append(dialOpts, opts...) conn, err := grpc.NewClient(addr, dialOpts...) if err != nil { return } client = NewGpcGenericClient(serviceName, conn) err = client.InitStub(ctx) return } func (f *GrpcGenericClientFactory) GetClient(ctx context.Context, serviceName string, opts ...grpc.DialOption) (client *GrpcGenericClient, err error) { // todo 优化 client, err, _ = f.clientCache.ComputeIfAbsentE(serviceName, func(serviceName string) (*GrpcGenericClient, error) { return f.NewClient(ctx, serviceName, opts...) }) return } // RefreshService 服务重新注册时可能有更改, 刷新旧的 grpc generic stub func (f *GrpcGenericClientFactory) RefreshService(serviceName string, passing bool) { zlog.Debugf("service status updated: %s, health=%v", serviceName, passing) if passing { service, ok := f.clientCache.Load(serviceName) if ok { go retry.DoWithFixDelay(10, 2*time.Second, func(_ uint32) (_ struct{}, err error) { ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() if err = service.InitStub(ctx); err != nil { zlog.Errorf("refresh service stub error: %s, %v", serviceName, err) } else { zlog.Debugf("refresh service stub success: %s", serviceName) } return }) } } }