package app import ( "context" "errors" "log" "net/http" "os" "os/signal" "sync" "syscall" "time" "github.com/labstack/echo/v5" ) // App manages application lifecycle and graceful shutdown type App struct { echo *echo.Echo server *http.Server shutdownTimeout time.Duration shutdownMutex sync.Mutex shutdownDone chan struct{} } // New creates a new App instance func New(echo *echo.Echo) *App { return &App{ echo: echo, server: nil, shutdownTimeout: 30 * time.Second, shutdownDone: make(chan struct{}), } } func (a *App) StartServer(addr string) error { a.server = &http.Server{ Addr: addr, Handler: a.echo, } // Start HTTP server in background go func() { if err := a.server.ListenAndServe(); err != nil && errors.Is(err, http.ErrServerClosed) { log.Fatalf("Server failed to start: %v", err) } }() return nil } // Start begins all background services and blocks until shutdown signal func (a *App) Start() error { log.Println("Starting application lifecycle management...") // Setup signal handling for graceful shutdown sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGINT, // Ctrl+C syscall.SIGTERM, // kill syscall.SIGQUIT, // quit ) // Wait for shutdown signal sig := <-sigChan log.Printf("Received signal: %v. Initiating graceful shutdown...", sig) // Perform graceful shutdown if err := a.Shutdown(); err != nil { log.Printf("Error during shutdown: %v", err) return err } log.Println("Application shutdown complete") return nil } // Shutdown performs graceful shutdown of all services func (a *App) Shutdown() error { a.shutdownMutex.Lock() defer a.shutdownMutex.Unlock() select { case <-a.shutdownDone: log.Println("Shutdown already in progress") return nil default: // Continue with shutdown } log.Println("Beginning graceful shutdown...") // Create context with timeout ctx, cancel := context.WithTimeout(context.Background(), a.shutdownTimeout) defer cancel() log.Println("Stopping HTTP Server...") if a.server != nil { if err := a.server.Shutdown(ctx); err != nil { log.Printf("Error stopping HTTP server: %v", err) } } close(a.shutdownDone) log.Println("Graceful shutdown completed successfully") return nil } // SetShutdownTimeout sets the maximum time to wait for graceful shutdown func (a *App) SetShutdownTimeout(timeout time.Duration) { a.shutdownTimeout = timeout } // ShutdownDone returns a channel that closes when shutdown is complete func (a *App) ShutdownDone() <-chan struct{} { return a.shutdownDone }