169 lines
4.8 KiB
Go
169 lines
4.8 KiB
Go
// Package main provides the API Gateway service entry point.
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
|
|
"git.dcentral.systems/toolz/goplt/internal/client"
|
|
"git.dcentral.systems/toolz/goplt/internal/di"
|
|
"git.dcentral.systems/toolz/goplt/internal/health"
|
|
"git.dcentral.systems/toolz/goplt/internal/metrics"
|
|
"git.dcentral.systems/toolz/goplt/internal/server"
|
|
"git.dcentral.systems/toolz/goplt/pkg/config"
|
|
"git.dcentral.systems/toolz/goplt/pkg/errorbus"
|
|
"git.dcentral.systems/toolz/goplt/pkg/logger"
|
|
"git.dcentral.systems/toolz/goplt/pkg/registry"
|
|
"git.dcentral.systems/toolz/goplt/services/gateway"
|
|
"go.opentelemetry.io/otel/trace"
|
|
"go.uber.org/fx"
|
|
)
|
|
|
|
func main() {
|
|
// Create DI container with core kernel services
|
|
container := di.NewContainer(
|
|
// Invoke lifecycle hooks
|
|
fx.Invoke(di.RegisterLifecycleHooks),
|
|
// Create API Gateway
|
|
fx.Invoke(func(
|
|
cfg config.ConfigProvider,
|
|
log logger.Logger,
|
|
healthRegistry *health.Registry,
|
|
metricsRegistry *metrics.Metrics,
|
|
errorBus errorbus.ErrorPublisher,
|
|
tracer trace.TracerProvider,
|
|
serviceRegistry registry.ServiceRegistry,
|
|
clientFactory *client.ServiceClientFactory,
|
|
lc fx.Lifecycle,
|
|
) {
|
|
// Create HTTP server using server foundation
|
|
srv, err := server.NewServer(cfg, log, healthRegistry, metricsRegistry, errorBus, tracer)
|
|
if err != nil {
|
|
log.Error("Failed to create API Gateway server",
|
|
logger.Error(err),
|
|
)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Setup gateway routes
|
|
gateway, err := gateway.NewGateway(cfg, log, clientFactory, serviceRegistry)
|
|
if err != nil {
|
|
log.Error("Failed to create API Gateway",
|
|
logger.Error(err),
|
|
)
|
|
os.Exit(1)
|
|
}
|
|
gateway.SetupRoutes(srv.Router())
|
|
|
|
// Determine port and host for registration
|
|
gatewayPort := cfg.GetInt("gateway.port")
|
|
if gatewayPort == 0 {
|
|
gatewayPort = cfg.GetInt("server.port")
|
|
if gatewayPort == 0 {
|
|
gatewayPort = 8080
|
|
}
|
|
}
|
|
|
|
// In Docker, always use the Docker service name for health checks
|
|
// Consul (also in Docker) needs to reach the service via Docker DNS
|
|
gatewayHost := cfg.GetString("gateway.host")
|
|
if os.Getenv("ENVIRONMENT") == "production" || os.Getenv("DOCKER") == "true" {
|
|
gatewayHost = "api-gateway" // Docker service name - required for Consul health checks
|
|
} else if gatewayHost == "" {
|
|
gatewayHost = cfg.GetString("server.host")
|
|
if gatewayHost == "" || gatewayHost == "0.0.0.0" {
|
|
gatewayHost = "localhost" // Local development
|
|
}
|
|
}
|
|
|
|
serviceInstance := ®istry.ServiceInstance{
|
|
ID: fmt.Sprintf("api-gateway-%d", os.Getpid()),
|
|
Name: "api-gateway",
|
|
Address: gatewayHost,
|
|
Port: gatewayPort,
|
|
Tags: []string{"gateway", "http"},
|
|
Metadata: map[string]string{
|
|
"version": "1.0.0",
|
|
"protocol": "http",
|
|
},
|
|
}
|
|
|
|
// Register lifecycle hooks
|
|
lc.Append(fx.Hook{
|
|
OnStart: func(ctx context.Context) error {
|
|
// Register with service registry
|
|
if err := serviceRegistry.Register(ctx, serviceInstance); err != nil {
|
|
log.Warn("Failed to register API Gateway with service registry",
|
|
logger.Error(err),
|
|
)
|
|
// Continue anyway - gateway can work without registry
|
|
} else {
|
|
log.Info("API Gateway registered with service registry",
|
|
logger.String("service_id", serviceInstance.ID),
|
|
)
|
|
}
|
|
|
|
// Start HTTP server
|
|
addr := fmt.Sprintf("%s:%d", cfg.GetString("server.host"), gatewayPort)
|
|
log.Info("API Gateway starting",
|
|
logger.String("addr", addr),
|
|
)
|
|
|
|
errChan := make(chan error, 1)
|
|
go func() {
|
|
if err := srv.Start(); err != nil && err != http.ErrServerClosed {
|
|
log.Error("API Gateway server failed",
|
|
logger.String("error", err.Error()),
|
|
)
|
|
errChan <- err
|
|
}
|
|
}()
|
|
|
|
// Wait a short time to detect immediate binding errors
|
|
select {
|
|
case err := <-errChan:
|
|
return fmt.Errorf("API Gateway failed to start: %w", err)
|
|
case <-time.After(500 * time.Millisecond):
|
|
log.Info("API Gateway started successfully",
|
|
logger.String("addr", addr),
|
|
)
|
|
return nil
|
|
}
|
|
},
|
|
OnStop: func(ctx context.Context) error {
|
|
// Deregister from service registry
|
|
if err := serviceRegistry.Deregister(ctx, serviceInstance.ID); err != nil {
|
|
log.Warn("Failed to deregister API Gateway from service registry",
|
|
logger.Error(err),
|
|
)
|
|
} else {
|
|
log.Info("API Gateway deregistered from service registry")
|
|
}
|
|
|
|
// Shutdown HTTP server
|
|
return srv.Shutdown(ctx)
|
|
},
|
|
})
|
|
}),
|
|
)
|
|
|
|
// Create root context
|
|
ctx := context.Background()
|
|
|
|
// Start the application
|
|
if err := container.Start(ctx); err != nil {
|
|
log := logger.GetGlobalLogger()
|
|
if log != nil {
|
|
log.Error("Failed to start API Gateway",
|
|
logger.Error(err),
|
|
)
|
|
} else {
|
|
fmt.Fprintf(os.Stderr, "Failed to start API Gateway: %v\n", err)
|
|
}
|
|
os.Exit(1)
|
|
}
|
|
}
|