- Update openapi.yaml spec - Regenerate server_gen.go with oapi-codegen - Update adapter, routes, and server configuration
153 lines
3.8 KiB
Go
153 lines
3.8 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
|
|
apimiddleware "github.com/jfraeys/fetch_ml/internal/api/middleware"
|
|
"github.com/jfraeys/fetch_ml/internal/audit"
|
|
"github.com/jfraeys/fetch_ml/internal/experiment"
|
|
"github.com/jfraeys/fetch_ml/internal/jupyter"
|
|
"github.com/jfraeys/fetch_ml/internal/logging"
|
|
"github.com/jfraeys/fetch_ml/internal/middleware"
|
|
"github.com/jfraeys/fetch_ml/internal/prommetrics"
|
|
"github.com/jfraeys/fetch_ml/internal/queue"
|
|
"github.com/jfraeys/fetch_ml/internal/scheduler"
|
|
"github.com/jfraeys/fetch_ml/internal/storage"
|
|
"github.com/jfraeys/fetch_ml/internal/tracking"
|
|
)
|
|
|
|
// Server represents the API server
|
|
type Server struct {
|
|
taskQueue queue.Backend
|
|
config *ServerConfig
|
|
httpServer *http.Server
|
|
logger *logging.Logger
|
|
expManager *experiment.Manager
|
|
db *storage.DB
|
|
sec *middleware.SecurityMiddleware
|
|
jupyterServiceMgr *jupyter.ServiceManager
|
|
auditLogger *audit.Logger
|
|
promMetrics *prommetrics.Metrics
|
|
validationMiddleware *apimiddleware.ValidationMiddleware
|
|
trackingRegistry *tracking.Registry
|
|
schedulerHub *scheduler.SchedulerHub
|
|
cleanupFuncs []func()
|
|
}
|
|
|
|
// NewServer creates a new API server
|
|
func NewServer(configPath string) (*Server, error) {
|
|
// Load configuration
|
|
cfg, err := LoadServerConfig(configPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := cfg.Validate(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
server := &Server{
|
|
config: cfg,
|
|
}
|
|
|
|
// Initialize components
|
|
if err := server.initializeComponents(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Setup HTTP server
|
|
server.setupHTTPServer()
|
|
|
|
return server, nil
|
|
}
|
|
|
|
// setupHTTPServer sets up the HTTP server and routes
|
|
func (s *Server) setupHTTPServer() {
|
|
mux := http.NewServeMux()
|
|
|
|
// Register all routes
|
|
s.registerRoutes(mux)
|
|
|
|
// Wrap with middleware
|
|
finalHandler := s.wrapWithMiddleware(mux)
|
|
finalHandler = s.wrapWithMetrics(finalHandler)
|
|
|
|
s.httpServer = &http.Server{
|
|
Addr: s.config.Server.Address,
|
|
Handler: finalHandler,
|
|
ReadTimeout: 30 * time.Second,
|
|
WriteTimeout: 30 * time.Second,
|
|
IdleTimeout: 120 * time.Second,
|
|
}
|
|
}
|
|
|
|
// Start starts the server
|
|
func (s *Server) Start() error {
|
|
if !s.config.Server.TLS.Enabled {
|
|
s.logger.Warn(
|
|
"TLS disabled for API server; do not use this configuration in production",
|
|
"address", s.config.Server.Address,
|
|
)
|
|
}
|
|
|
|
go func() {
|
|
var err error
|
|
if s.config.Server.TLS.Enabled {
|
|
s.logger.Info("starting HTTPS server", "address", s.config.Server.Address)
|
|
err = s.httpServer.ListenAndServeTLS(
|
|
s.config.Server.TLS.CertFile,
|
|
s.config.Server.TLS.KeyFile,
|
|
)
|
|
} else {
|
|
s.logger.Info("starting HTTP server", "address", s.config.Server.Address)
|
|
err = s.httpServer.ListenAndServe()
|
|
}
|
|
|
|
if err != nil && err != http.ErrServerClosed {
|
|
s.logger.Error("server failed", "error", err)
|
|
}
|
|
os.Exit(1)
|
|
}()
|
|
|
|
return nil
|
|
}
|
|
|
|
// WaitForShutdown waits for shutdown signals and gracefully shuts down the server
|
|
func (s *Server) WaitForShutdown() {
|
|
sigChan := make(chan os.Signal, 1)
|
|
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
sig := <-sigChan
|
|
s.logger.Info("received shutdown signal", "signal", sig)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
s.logger.Info("shutting down http server...")
|
|
if err := s.httpServer.Shutdown(ctx); err != nil {
|
|
s.logger.Error("server shutdown error", "error", err)
|
|
} else {
|
|
s.logger.Info("http server shutdown complete")
|
|
}
|
|
|
|
// Run cleanup functions
|
|
for _, cleanup := range s.cleanupFuncs {
|
|
cleanup()
|
|
}
|
|
|
|
s.logger.Info("api server stopped")
|
|
}
|
|
|
|
// Close cleans up server resources
|
|
func (s *Server) Close() error {
|
|
// Run all cleanup functions
|
|
for _, cleanup := range s.cleanupFuncs {
|
|
cleanup()
|
|
}
|
|
return nil
|
|
}
|