package main import ( "context" "errors" "log/slog" "net/http" "os" "os/signal" "syscall" "time" "github.com/easyai/easyai-ai-gateway/apps/api/internal/config" "github.com/easyai/easyai-ai-gateway/apps/api/internal/httpapi" "github.com/easyai/easyai-ai-gateway/apps/api/internal/store" ) func main() { cfg := config.Load() logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ Level: cfg.LogLevel, })) ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() db, err := store.Connect(ctx, cfg.DatabaseURL) if err != nil { logger.Error("connect postgres failed", "error", err) os.Exit(1) } defer db.Close() if recovery, err := db.RecoverInterruptedRuntimeState(ctx); err != nil { logger.Error("recover interrupted runtime state failed", "error", err) os.Exit(1) } else if recovery.ReleasedConcurrencyLeases > 0 || recovery.ReleasedRateReservations > 0 || recovery.FailedAttempts > 0 || recovery.FailedTasks > 0 || recovery.RequeuedAsyncTasks > 0 { logger.Warn("interrupted runtime state recovered", "releasedConcurrencyLeases", recovery.ReleasedConcurrencyLeases, "releasedRateReservations", recovery.ReleasedRateReservations, "failedAttempts", recovery.FailedAttempts, "failedTasks", recovery.FailedTasks, "requeuedAsyncTasks", recovery.RequeuedAsyncTasks, ) } server := &http.Server{ Addr: cfg.HTTPAddr, Handler: httpapi.NewServerWithContext(ctx, cfg, db, logger), ReadHeaderTimeout: 10 * time.Second, } go func() { logger.Info("easyai ai gateway api started", "addr", cfg.HTTPAddr) if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { logger.Error("http server failed", "error", err) os.Exit(1) } }() <-ctx.Done() shutdownCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() if err := server.Shutdown(shutdownCtx); err != nil { logger.Error("http shutdown failed", "error", err) os.Exit(1) } logger.Info("easyai ai gateway api stopped") }