package app import ( "context" "log" "os" "os/signal" "sync" "syscall" "time" "github.com/labstack/echo/v4" ) // App manages application lifecycle and graceful shutdown type App struct { echo *echo.Echo 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, shutdownTimeout: 30 * time.Second, shutdownDone: make(chan struct{}), } } // 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() // Channel to track shutdown completion done := make(chan struct{}) // Perform shutdown in goroutine go func() { defer close(done) // Stop accepting new connections and shutdown HTTP server log.Println("Stopping HTTP server...") if err := a.echo.Close(); err != nil { log.Printf("Error stopping HTTP server: %v", err) } log.Println("All services stopped") }() // Wait for shutdown or timeout select { case <-done: close(a.shutdownDone) log.Println("Graceful shutdown completed successfully") return nil case <-ctx.Done(): close(a.shutdownDone) log.Printf("Shutdown timed out after %v", a.shutdownTimeout) return ctx.Err() } } // 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 }