deploy
This commit is contained in:
parent
507445f84a
commit
c9f50403b9
@ -4,6 +4,15 @@ app:
|
|||||||
http_addr: ":8080"
|
http_addr: ":8080"
|
||||||
shutdown_timeout: 10s
|
shutdown_timeout: 10s
|
||||||
|
|
||||||
|
registry:
|
||||||
|
enabled: false
|
||||||
|
provider: ""
|
||||||
|
endpoint: ""
|
||||||
|
service_name: "chatappgateway"
|
||||||
|
instance_id: ""
|
||||||
|
register_timeout: 3s
|
||||||
|
deregister_timeout: 5s
|
||||||
|
|
||||||
# /ready 会使用这些 gRPC 依赖做接流量前检查。
|
# /ready 会使用这些 gRPC 依赖做接流量前检查。
|
||||||
grpc:
|
grpc:
|
||||||
user:
|
user:
|
||||||
|
|||||||
@ -4,6 +4,15 @@ app:
|
|||||||
http_addr: ":8080"
|
http_addr: ":8080"
|
||||||
shutdown_timeout: 10s
|
shutdown_timeout: 10s
|
||||||
|
|
||||||
|
registry:
|
||||||
|
enabled: false
|
||||||
|
provider: ""
|
||||||
|
endpoint: ""
|
||||||
|
service_name: "chatappgateway"
|
||||||
|
instance_id: ""
|
||||||
|
register_timeout: 3s
|
||||||
|
deregister_timeout: 5s
|
||||||
|
|
||||||
grpc:
|
grpc:
|
||||||
# Current user instances:
|
# Current user instances:
|
||||||
# - 10.0.11.17:9001 (user-1)
|
# - 10.0.11.17:9001 (user-1)
|
||||||
|
|||||||
@ -4,6 +4,15 @@ app:
|
|||||||
http_addr: ":8080"
|
http_addr: ":8080"
|
||||||
shutdown_timeout: 10s
|
shutdown_timeout: 10s
|
||||||
|
|
||||||
|
registry:
|
||||||
|
enabled: false
|
||||||
|
provider: ""
|
||||||
|
endpoint: ""
|
||||||
|
service_name: "chatappgateway"
|
||||||
|
instance_id: ""
|
||||||
|
register_timeout: 3s
|
||||||
|
deregister_timeout: 5s
|
||||||
|
|
||||||
grpc:
|
grpc:
|
||||||
# Current user instances:
|
# Current user instances:
|
||||||
# - 10.0.11.17:9001 (user-1)
|
# - 10.0.11.17:9001 (user-1)
|
||||||
|
|||||||
4
go.mod
4
go.mod
@ -3,7 +3,7 @@ module chatappgateway
|
|||||||
go 1.23.1
|
go 1.23.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
gitea.haiyihy.com/hy/chatappcommon v0.0.0
|
gitea.haiyihy.com/hy/chatappcommon v0.1.1-0.20260404072625-9a68eb0302e5
|
||||||
google.golang.org/grpc v1.67.3
|
google.golang.org/grpc v1.67.3
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
@ -15,5 +15,3 @@ require (
|
|||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
|
||||||
google.golang.org/protobuf v1.36.11 // indirect
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace gitea.haiyihy.com/hy/chatappcommon => ../Common
|
|
||||||
|
|||||||
2
go.sum
2
go.sum
@ -1,3 +1,5 @@
|
|||||||
|
gitea.haiyihy.com/hy/chatappcommon v0.1.1-0.20260404072625-9a68eb0302e5 h1:RUMxeDXog9ryyLU25wQR44dQYDnDGgeAM+9X3Gvkm74=
|
||||||
|
gitea.haiyihy.com/hy/chatappcommon v0.1.1-0.20260404072625-9a68eb0302e5/go.mod h1:VXhR5abAucTWdJ7j+N09ddF57Pm5ZsKg0h55ejXjQ7s=
|
||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"chatappgateway/internal/integration/paygrpc"
|
"chatappgateway/internal/integration/paygrpc"
|
||||||
"chatappgateway/internal/integration/upstream"
|
"chatappgateway/internal/integration/upstream"
|
||||||
"chatappgateway/internal/integration/usergrpc"
|
"chatappgateway/internal/integration/usergrpc"
|
||||||
|
"chatappgateway/internal/lifecycle"
|
||||||
"chatappgateway/internal/service/auth"
|
"chatappgateway/internal/service/auth"
|
||||||
"chatappgateway/internal/service/pay"
|
"chatappgateway/internal/service/pay"
|
||||||
httpserver "chatappgateway/internal/transport/http"
|
httpserver "chatappgateway/internal/transport/http"
|
||||||
@ -19,6 +20,7 @@ import (
|
|||||||
type Application struct {
|
type Application struct {
|
||||||
server *httpserver.Server
|
server *httpserver.Server
|
||||||
closers []io.Closer
|
closers []io.Closer
|
||||||
|
hooks lifecycle.Hooks
|
||||||
}
|
}
|
||||||
|
|
||||||
// New 构造完整应用,包括 gRPC 连接池、业务服务和 HTTP 服务。
|
// New 构造完整应用,包括 gRPC 连接池、业务服务和 HTTP 服务。
|
||||||
@ -39,6 +41,7 @@ func New(ctx context.Context, cfg config.Config, logger *slog.Logger) (*Applicat
|
|||||||
|
|
||||||
authService := auth.New(userClient)
|
authService := auth.New(userClient)
|
||||||
payService := pay.New(payClient)
|
payService := pay.New(payClient)
|
||||||
|
registryHooks := lifecycle.NewRegistryHooks(cfg.Registry, logger.With("component", "registry_hooks"))
|
||||||
readinessChecker := newReadinessGroup(
|
readinessChecker := newReadinessGroup(
|
||||||
namedChecker{
|
namedChecker{
|
||||||
name: "ChatAppUser",
|
name: "ChatAppUser",
|
||||||
@ -49,16 +52,20 @@ func New(ctx context.Context, cfg config.Config, logger *slog.Logger) (*Applicat
|
|||||||
check: payPool.Ready,
|
check: payPool.Ready,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
server := httpserver.New(cfg.App.Name, cfg.App.HTTPAddr, cfg.App.ShutdownTimeout, logger, authService, payService, readinessChecker)
|
server := httpserver.New(cfg.App.Name, cfg.App.HTTPAddr, cfg.App.ShutdownTimeout, logger, authService, payService, readinessChecker, registryHooks)
|
||||||
|
|
||||||
return &Application{
|
return &Application{
|
||||||
server: server,
|
server: server,
|
||||||
closers: []io.Closer{userPool, payPool},
|
closers: []io.Closer{userPool, payPool},
|
||||||
|
hooks: registryHooks,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run 启动 HTTP 服务。
|
// Run 启动 HTTP 服务。
|
||||||
func (a *Application) Run(ctx context.Context) error {
|
func (a *Application) Run(ctx context.Context) error {
|
||||||
|
if err := a.hooks.OnRegister(ctx); err != nil {
|
||||||
|
return fmt.Errorf("register lifecycle hook: %w", err)
|
||||||
|
}
|
||||||
return a.server.Run(ctx)
|
return a.server.Run(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@ const DefaultPath = "config/local.yaml"
|
|||||||
// Config 汇总整个网关服务的运行参数。
|
// Config 汇总整个网关服务的运行参数。
|
||||||
type Config struct {
|
type Config struct {
|
||||||
App AppConfig `yaml:"app"`
|
App AppConfig `yaml:"app"`
|
||||||
|
Registry RegistryConfig `yaml:"registry"`
|
||||||
GRPC GRPCConfig `yaml:"grpc"`
|
GRPC GRPCConfig `yaml:"grpc"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,6 +27,17 @@ type AppConfig struct {
|
|||||||
ShutdownTimeout time.Duration `yaml:"shutdown_timeout"`
|
ShutdownTimeout time.Duration `yaml:"shutdown_timeout"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegistryConfig 预留服务注册中心接入参数,当前只保留注销钩子扩展点。
|
||||||
|
type RegistryConfig struct {
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
Provider string `yaml:"provider"`
|
||||||
|
Endpoint string `yaml:"endpoint"`
|
||||||
|
ServiceName string `yaml:"service_name"`
|
||||||
|
InstanceID string `yaml:"instance_id"`
|
||||||
|
RegisterTimeout time.Duration `yaml:"register_timeout"`
|
||||||
|
DeregisterTimeout time.Duration `yaml:"deregister_timeout"`
|
||||||
|
}
|
||||||
|
|
||||||
// GRPCConfig 聚合所有下游 gRPC 服务配置。
|
// GRPCConfig 聚合所有下游 gRPC 服务配置。
|
||||||
type GRPCConfig struct {
|
type GRPCConfig struct {
|
||||||
User UpstreamConfig `yaml:"user"`
|
User UpstreamConfig `yaml:"user"`
|
||||||
@ -89,6 +101,10 @@ func defaultConfig() Config {
|
|||||||
HTTPAddr: ":8080",
|
HTTPAddr: ":8080",
|
||||||
ShutdownTimeout: 10 * time.Second,
|
ShutdownTimeout: 10 * time.Second,
|
||||||
},
|
},
|
||||||
|
Registry: RegistryConfig{
|
||||||
|
RegisterTimeout: 3 * time.Second,
|
||||||
|
DeregisterTimeout: 5 * time.Second,
|
||||||
|
},
|
||||||
GRPC: GRPCConfig{
|
GRPC: GRPCConfig{
|
||||||
User: defaultUpstreamConfig("127.0.0.1:9001"),
|
User: defaultUpstreamConfig("127.0.0.1:9001"),
|
||||||
Pay: defaultUpstreamConfig("127.0.0.1:9002"),
|
Pay: defaultUpstreamConfig("127.0.0.1:9002"),
|
||||||
@ -137,6 +153,12 @@ func validate(cfg Config) error {
|
|||||||
if cfg.App.ShutdownTimeout <= 0 {
|
if cfg.App.ShutdownTimeout <= 0 {
|
||||||
return fmt.Errorf("app.shutdown_timeout must be greater than 0")
|
return fmt.Errorf("app.shutdown_timeout must be greater than 0")
|
||||||
}
|
}
|
||||||
|
if cfg.Registry.RegisterTimeout <= 0 {
|
||||||
|
return fmt.Errorf("registry.register_timeout must be greater than 0")
|
||||||
|
}
|
||||||
|
if cfg.Registry.DeregisterTimeout <= 0 {
|
||||||
|
return fmt.Errorf("registry.deregister_timeout must be greater than 0")
|
||||||
|
}
|
||||||
if err := validateUpstream("grpc.user", cfg.GRPC.User); err != nil {
|
if err := validateUpstream("grpc.user", cfg.GRPC.User); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
43
internal/lifecycle/registry.go
Normal file
43
internal/lifecycle/registry.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package lifecycle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
|
"chatappgateway/internal/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hooks 预留服务注册中心生命周期钩子。
|
||||||
|
type Hooks interface {
|
||||||
|
OnRegister(context.Context) error
|
||||||
|
OnDeregister(context.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type registryHooks struct {
|
||||||
|
cfg config.RegistryConfig
|
||||||
|
logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRegistryHooks 返回当前阶段的占位实现,后续可以替换成真实注册中心接入。
|
||||||
|
func NewRegistryHooks(cfg config.RegistryConfig, logger *slog.Logger) Hooks {
|
||||||
|
return ®istryHooks{
|
||||||
|
cfg: cfg,
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *registryHooks) OnRegister(_ context.Context) error {
|
||||||
|
if !h.cfg.Enabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
h.logger.Info("registry register hook reserved", "provider", h.cfg.Provider, "service_name", h.cfg.ServiceName, "instance_id", h.cfg.InstanceID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *registryHooks) OnDeregister(_ context.Context) error {
|
||||||
|
if !h.cfg.Enabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
h.logger.Info("registry deregister hook reserved", "provider", h.cfg.Provider, "service_name", h.cfg.ServiceName, "instance_id", h.cfg.InstanceID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -46,12 +46,18 @@ type Server struct {
|
|||||||
authService AuthService
|
authService AuthService
|
||||||
payService PayService
|
payService PayService
|
||||||
readiness ReadinessChecker
|
readiness ReadinessChecker
|
||||||
|
drainHook DrainHook
|
||||||
handler http.Handler
|
handler http.Handler
|
||||||
ready atomic.Bool
|
ready atomic.Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DrainHook 在服务摘除 readiness 后执行,例如注销注册中心节点。
|
||||||
|
type DrainHook interface {
|
||||||
|
OnDeregister(context.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
// New 创建 HTTP 服务实例。
|
// New 创建 HTTP 服务实例。
|
||||||
func New(appName string, addr string, shutdownTimeout time.Duration, logger *slog.Logger, authService AuthService, payService PayService, readiness ReadinessChecker) *Server {
|
func New(appName string, addr string, shutdownTimeout time.Duration, logger *slog.Logger, authService AuthService, payService PayService, readiness ReadinessChecker, drainHook DrainHook) *Server {
|
||||||
server := &Server{
|
server := &Server{
|
||||||
appName: appName,
|
appName: appName,
|
||||||
addr: addr,
|
addr: addr,
|
||||||
@ -60,6 +66,7 @@ func New(appName string, addr string, shutdownTimeout time.Duration, logger *slo
|
|||||||
authService: authService,
|
authService: authService,
|
||||||
payService: payService,
|
payService: payService,
|
||||||
readiness: readiness,
|
readiness: readiness,
|
||||||
|
drainHook: drainHook,
|
||||||
}
|
}
|
||||||
server.ready.Store(true)
|
server.ready.Store(true)
|
||||||
server.handler = server.withRequestContext(server.routes())
|
server.handler = server.withRequestContext(server.routes())
|
||||||
@ -88,6 +95,11 @@ func (s *Server) Run(ctx context.Context) error {
|
|||||||
s.ready.Store(false)
|
s.ready.Store(false)
|
||||||
shutdownCtx, cancel := context.WithTimeout(context.Background(), s.shutdownTimeout)
|
shutdownCtx, cancel := context.WithTimeout(context.Background(), s.shutdownTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
if s.drainHook != nil {
|
||||||
|
if err := s.drainHook.OnDeregister(shutdownCtx); err != nil {
|
||||||
|
s.logger.Error("run deregister hook failed", "error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
_ = httpServer.Shutdown(shutdownCtx)
|
_ = httpServer.Shutdown(shutdownCtx)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
@ -374,7 +374,7 @@ func newTestEnv(t *testing.T, userTimeout time.Duration, payTimeout time.Duratio
|
|||||||
authService := auth.New(usergrpc.New(commonpb.NewChatAppUserServiceClient(userConn), userTimeout))
|
authService := auth.New(usergrpc.New(commonpb.NewChatAppUserServiceClient(userConn), userTimeout))
|
||||||
payService := payservice.New(paygrpc.New(commonpb.NewChatAppPayServiceClient(payConn), payTimeout))
|
payService := payservice.New(paygrpc.New(commonpb.NewChatAppPayServiceClient(payConn), payTimeout))
|
||||||
readinessChecker := &mockReadinessChecker{}
|
readinessChecker := &mockReadinessChecker{}
|
||||||
handler := httpserver.New("chatappgateway", ":0", 2*time.Second, logger, authService, payService, readinessChecker).Handler()
|
handler := httpserver.New("chatappgateway", ":0", 2*time.Second, logger, authService, payService, readinessChecker, nil).Handler()
|
||||||
|
|
||||||
return &testEnv{
|
return &testEnv{
|
||||||
server: httptest.NewServer(handler),
|
server: httptest.NewServer(handler),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user