package service import ( "fmt" "git.hlsq.asia/mmorpg/service-common/config" "git.hlsq.asia/mmorpg/service-common/discover" "git.hlsq.asia/mmorpg/service-common/log" "git.hlsq.asia/mmorpg/service-common/utils" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "google.golang.org/grpc" "google.golang.org/grpc/health" "google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/keepalive" "net" "sync" "time" ) type IService interface { Init(ready *sync.WaitGroup) SetReady() Close() } type Base struct { Target string ServiceName string SID int64 Serve *grpc.Server Cfg *config.GrpcConfig OnCustomGrpcServerOption func() []grpc.ServerOption OnInit func(serve *grpc.Server) OnClose func() wg *sync.WaitGroup healthcheck *health.Server } func (s *Base) Init(ready *sync.WaitGroup) { s.wg = &sync.WaitGroup{} s.wg.Add(1) s.SID = utils.SnowflakeInstance().Generate().Int64() go func() { defer s.wg.Done() defer s.OnClose() defer discover.UnRegisterGrpcServer(s.SID) // 监听端口 lis, err := net.Listen("tcp", fmt.Sprintf(":%d", s.Cfg.Port)) if err != nil { log.Errorf("%v ListenPort err: %v", s.Target, err) return } options := []grpc.ServerOption{ grpc.ChainUnaryInterceptor( s.RecoveryInterceptor, s.LoggingInterceptor, ), grpc.StatsHandler(otelgrpc.NewServerHandler()), grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{ MinTime: 20 * time.Second, PermitWithoutStream: true, }), } options = append(options, s.OnCustomGrpcServerOption()...) s.Serve = grpc.NewServer(options...) s.OnInit(s.Serve) // 健康检查 s.healthcheck = health.NewServer() s.healthcheck.SetServingStatus("", grpc_health_v1.HealthCheckResponse_NOT_SERVING) grpc_health_v1.RegisterHealthServer(s.Serve, s.healthcheck) // 服务注册 if err = discover.RegisterGrpcServer(s.Target, s.SID, fmt.Sprintf("%v:%d", s.Cfg.Address, s.Cfg.Port), s.Cfg.TTL); err != nil { log.Errorf("%v RegisterGrpcServer err: %v", s.Target, err) return } // 准备好了 ready.Done() if err = s.Serve.Serve(lis); err != nil { log.Errorf("%v Serve err: %v", s.Target, err) return } log.Infof("%v server stop.", s.Target) }() } func (s *Base) SetReady() { if s.healthcheck != nil { s.healthcheck.SetServingStatus("", grpc_health_v1.HealthCheckResponse_SERVING) } } func (s *Base) Close() { if s.healthcheck != nil { s.healthcheck.SetServingStatus("", grpc_health_v1.HealthCheckResponse_NOT_SERVING) } if s.Serve != nil { s.Serve.GracefulStop() s.wg.Wait() } }