fix(consul): Fix health checks for gRPC services in Docker
- Add gRPC health check support to Consul registry - Services are gRPC-only, not HTTP - Consul was trying HTTP health checks which failed - Now uses gRPC health checks via grpc.health.v1.Health service - Update HealthCheckConfig to support both HTTP and gRPC - Add GRPC field for gRPC service name - Add UseGRPC flag to choose health check type - Default to gRPC for services (use_grpc: true in config) - Fix service address registration in Docker - Services now register with Docker service name (e.g., auth-service) - Allows Consul to reach services via Docker network DNS - Falls back to localhost for local development - Update default.yaml to enable gRPC health checks - Set use_grpc: true - Set grpc: grpc.health.v1.Health This fixes services being deregistered from Consul due to failed HTTP health checks. Services will now pass gRPC health checks.
This commit is contained in:
@@ -183,7 +183,13 @@ func registerLifecycle(
|
|||||||
serviceID := fmt.Sprintf("audit-service-%d", time.Now().Unix())
|
serviceID := fmt.Sprintf("audit-service-%d", time.Now().Unix())
|
||||||
host := cfg.GetString("services.audit.host")
|
host := cfg.GetString("services.audit.host")
|
||||||
if host == "" {
|
if host == "" {
|
||||||
host = "localhost"
|
// In Docker, use service name for Consul to reach the service
|
||||||
|
// For local development, use localhost
|
||||||
|
if os.Getenv("ENVIRONMENT") == "production" || os.Getenv("DOCKER") == "true" {
|
||||||
|
host = "audit-service" // Docker service name
|
||||||
|
} else {
|
||||||
|
host = "localhost"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
port := grpcServer.Port()
|
port := grpcServer.Port()
|
||||||
|
|
||||||
|
|||||||
@@ -190,7 +190,13 @@ func registerLifecycle(
|
|||||||
serviceID := fmt.Sprintf("auth-service-%d", time.Now().Unix())
|
serviceID := fmt.Sprintf("auth-service-%d", time.Now().Unix())
|
||||||
host := cfg.GetString("services.auth.host")
|
host := cfg.GetString("services.auth.host")
|
||||||
if host == "" {
|
if host == "" {
|
||||||
host = "localhost"
|
// In Docker, use service name for Consul to reach the service
|
||||||
|
// For local development, use localhost
|
||||||
|
if os.Getenv("ENVIRONMENT") == "production" || os.Getenv("DOCKER") == "true" {
|
||||||
|
host = "auth-service" // Docker service name
|
||||||
|
} else {
|
||||||
|
host = "localhost"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
port := grpcServer.Port()
|
port := grpcServer.Port()
|
||||||
|
|
||||||
|
|||||||
@@ -183,7 +183,13 @@ func registerLifecycle(
|
|||||||
serviceID := fmt.Sprintf("authz-service-%d", time.Now().Unix())
|
serviceID := fmt.Sprintf("authz-service-%d", time.Now().Unix())
|
||||||
host := cfg.GetString("services.authz.host")
|
host := cfg.GetString("services.authz.host")
|
||||||
if host == "" {
|
if host == "" {
|
||||||
host = "localhost"
|
// In Docker, use service name for Consul to reach the service
|
||||||
|
// For local development, use localhost
|
||||||
|
if os.Getenv("ENVIRONMENT") == "production" || os.Getenv("DOCKER") == "true" {
|
||||||
|
host = "authz-service" // Docker service name
|
||||||
|
} else {
|
||||||
|
host = "localhost"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
port := grpcServer.Port()
|
port := grpcServer.Port()
|
||||||
|
|
||||||
|
|||||||
@@ -183,7 +183,13 @@ func registerLifecycle(
|
|||||||
serviceID := fmt.Sprintf("identity-service-%d", time.Now().Unix())
|
serviceID := fmt.Sprintf("identity-service-%d", time.Now().Unix())
|
||||||
host := cfg.GetString("services.identity.host")
|
host := cfg.GetString("services.identity.host")
|
||||||
if host == "" {
|
if host == "" {
|
||||||
host = "localhost"
|
// In Docker, use service name for Consul to reach the service
|
||||||
|
// For local development, use localhost
|
||||||
|
if os.Getenv("ENVIRONMENT") == "production" || os.Getenv("DOCKER") == "true" {
|
||||||
|
host = "identity-service" // Docker service name
|
||||||
|
} else {
|
||||||
|
host = "localhost"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
port := grpcServer.Port()
|
port := grpcServer.Port()
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ registry:
|
|||||||
timeout: "3s"
|
timeout: "3s"
|
||||||
deregister_after: "30s"
|
deregister_after: "30s"
|
||||||
http: "/healthz"
|
http: "/healthz"
|
||||||
|
grpc: "grpc.health.v1.Health"
|
||||||
|
use_grpc: true
|
||||||
|
|
||||||
services:
|
services:
|
||||||
audit:
|
audit:
|
||||||
|
|||||||
@@ -218,8 +218,14 @@ func ProvideServiceRegistry() fx.Option {
|
|||||||
healthCheckDeregisterAfter = 30 * time.Second
|
healthCheckDeregisterAfter = 30 * time.Second
|
||||||
}
|
}
|
||||||
healthCheckHTTP := cfg.GetString("registry.consul.health_check.http")
|
healthCheckHTTP := cfg.GetString("registry.consul.health_check.http")
|
||||||
if healthCheckHTTP == "" {
|
healthCheckGRPC := cfg.GetString("registry.consul.health_check.grpc")
|
||||||
healthCheckHTTP = "/healthz"
|
useGRPC := cfg.GetBool("registry.consul.health_check.use_grpc")
|
||||||
|
// Default to gRPC if not explicitly set (services are gRPC by default)
|
||||||
|
if !cfg.IsSet("registry.consul.health_check.use_grpc") {
|
||||||
|
useGRPC = true
|
||||||
|
}
|
||||||
|
if healthCheckGRPC == "" {
|
||||||
|
healthCheckGRPC = "grpc.health.v1.Health"
|
||||||
}
|
}
|
||||||
|
|
||||||
consulCfg.HealthCheck = consul.HealthCheckConfig{
|
consulCfg.HealthCheck = consul.HealthCheckConfig{
|
||||||
@@ -227,6 +233,8 @@ func ProvideServiceRegistry() fx.Option {
|
|||||||
Timeout: healthCheckTimeout,
|
Timeout: healthCheckTimeout,
|
||||||
DeregisterAfter: healthCheckDeregisterAfter,
|
DeregisterAfter: healthCheckDeregisterAfter,
|
||||||
HTTP: healthCheckHTTP,
|
HTTP: healthCheckHTTP,
|
||||||
|
GRPC: healthCheckGRPC,
|
||||||
|
UseGRPC: useGRPC,
|
||||||
}
|
}
|
||||||
|
|
||||||
return consul.NewRegistry(consulCfg)
|
return consul.NewRegistry(consulCfg)
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ type HealthCheckConfig struct {
|
|||||||
Interval time.Duration // Health check interval
|
Interval time.Duration // Health check interval
|
||||||
Timeout time.Duration // Health check timeout
|
Timeout time.Duration // Health check timeout
|
||||||
DeregisterAfter time.Duration // Time to wait before deregistering unhealthy service
|
DeregisterAfter time.Duration // Time to wait before deregistering unhealthy service
|
||||||
HTTP string // HTTP health check endpoint (e.g., "/healthz")
|
HTTP string // HTTP health check endpoint (e.g., "/healthz") - for HTTP services
|
||||||
|
GRPC string // gRPC health check service name (e.g., "grpc.health.v1.Health") - for gRPC services
|
||||||
|
UseGRPC bool // Whether to use gRPC health checks instead of HTTP
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRegistry creates a new Consul-based service registry.
|
// NewRegistry creates a new Consul-based service registry.
|
||||||
@@ -68,7 +70,21 @@ func (r *ConsulRegistry) Register(ctx context.Context, service *registry.Service
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add health check if configured
|
// Add health check if configured
|
||||||
if r.config.HealthCheck.HTTP != "" {
|
if r.config.HealthCheck.UseGRPC {
|
||||||
|
// Use gRPC health check for gRPC services
|
||||||
|
// Format: host:port/service or host:port (uses default health service)
|
||||||
|
grpcAddr := fmt.Sprintf("%s:%d", service.Address, service.Port)
|
||||||
|
if r.config.HealthCheck.GRPC != "" {
|
||||||
|
grpcAddr = fmt.Sprintf("%s:%d/%s", service.Address, service.Port, r.config.HealthCheck.GRPC)
|
||||||
|
}
|
||||||
|
registration.Check = &consulapi.AgentServiceCheck{
|
||||||
|
GRPC: grpcAddr,
|
||||||
|
Interval: r.config.HealthCheck.Interval.String(),
|
||||||
|
Timeout: r.config.HealthCheck.Timeout.String(),
|
||||||
|
DeregisterCriticalServiceAfter: r.config.HealthCheck.DeregisterAfter.String(),
|
||||||
|
}
|
||||||
|
} else if r.config.HealthCheck.HTTP != "" {
|
||||||
|
// Use HTTP health check for HTTP services
|
||||||
healthCheckURL := fmt.Sprintf("http://%s:%d%s", service.Address, service.Port, r.config.HealthCheck.HTTP)
|
healthCheckURL := fmt.Sprintf("http://%s:%d%s", service.Address, service.Port, r.config.HealthCheck.HTTP)
|
||||||
registration.Check = &consulapi.AgentServiceCheck{
|
registration.Check = &consulapi.AgentServiceCheck{
|
||||||
HTTP: healthCheckURL,
|
HTTP: healthCheckURL,
|
||||||
|
|||||||
Reference in New Issue
Block a user