package shutdown import ( "context" "fmt" "net/http" "time" ) // HTTPServerComponent wraps an HTTP server for graceful shutdown type HTTPServerComponent struct { name string server *http.Server priority int } // NewHTTPServerComponent creates a new HTTP server component func NewHTTPServerComponent(name string, server *http.Server, priority int) *HTTPServerComponent { return &HTTPServerComponent{ name: name, server: server, priority: priority, } } func (h *HTTPServerComponent) Name() string { return h.name } func (h *HTTPServerComponent) Priority() int { return h.priority } func (h *HTTPServerComponent) CanForceStop() bool { return true } func (h *HTTPServerComponent) Shutdown(ctx context.Context) error { if h.server == nil { return nil } return h.server.Shutdown(ctx) } // P2PNodeComponent wraps a P2P node for graceful shutdown type P2PNodeComponent struct { name string closer func() error priority int } // NewP2PNodeComponent creates a new P2P node component func NewP2PNodeComponent(name string, closer func() error, priority int) *P2PNodeComponent { return &P2PNodeComponent{ name: name, closer: closer, priority: priority, } } func (p *P2PNodeComponent) Name() string { return p.name } func (p *P2PNodeComponent) Priority() int { return p.priority } func (p *P2PNodeComponent) CanForceStop() bool { return true } func (p *P2PNodeComponent) Shutdown(ctx context.Context) error { if p.closer == nil { return nil } // P2P nodes typically need time to disconnect gracefully done := make(chan error, 1) go func() { done <- p.closer() }() select { case err := <-done: return err case <-ctx.Done(): return ctx.Err() } } // DatabaseComponent wraps a database connection for graceful shutdown type DatabaseComponent struct { name string closer func() error priority int } // NewDatabaseComponent creates a new database component func NewDatabaseComponent(name string, closer func() error, priority int) *DatabaseComponent { return &DatabaseComponent{ name: name, closer: closer, priority: priority, } } func (d *DatabaseComponent) Name() string { return d.name } func (d *DatabaseComponent) Priority() int { return d.priority } func (d *DatabaseComponent) CanForceStop() bool { return false // Databases shouldn't be force-stopped } func (d *DatabaseComponent) Shutdown(ctx context.Context) error { if d.closer == nil { return nil } return d.closer() } // ElectionManagerComponent wraps an election manager for graceful shutdown type ElectionManagerComponent struct { name string stopper func() priority int } // NewElectionManagerComponent creates a new election manager component func NewElectionManagerComponent(name string, stopper func(), priority int) *ElectionManagerComponent { return &ElectionManagerComponent{ name: name, stopper: stopper, priority: priority, } } func (e *ElectionManagerComponent) Name() string { return e.name } func (e *ElectionManagerComponent) Priority() int { return e.priority } func (e *ElectionManagerComponent) CanForceStop() bool { return true } func (e *ElectionManagerComponent) Shutdown(ctx context.Context) error { if e.stopper == nil { return nil } // Election managers need special handling to transfer leadership done := make(chan struct{}) go func() { e.stopper() close(done) }() select { case <-done: return nil case <-ctx.Done(): return ctx.Err() } } // PubSubComponent wraps a PubSub system for graceful shutdown type PubSubComponent struct { name string closer func() error priority int } // NewPubSubComponent creates a new PubSub component func NewPubSubComponent(name string, closer func() error, priority int) *PubSubComponent { return &PubSubComponent{ name: name, closer: closer, priority: priority, } } func (p *PubSubComponent) Name() string { return p.name } func (p *PubSubComponent) Priority() int { return p.priority } func (p *PubSubComponent) CanForceStop() bool { return true } func (p *PubSubComponent) Shutdown(ctx context.Context) error { if p.closer == nil { return nil } return p.closer() } // MonitoringComponent wraps a monitoring system for graceful shutdown type MonitoringComponent struct { name string closer func() error priority int } // NewMonitoringComponent creates a new monitoring component func NewMonitoringComponent(name string, closer func() error, priority int) *MonitoringComponent { return &MonitoringComponent{ name: name, closer: closer, priority: priority, } } func (m *MonitoringComponent) Name() string { return m.name } func (m *MonitoringComponent) Priority() int { return m.priority } func (m *MonitoringComponent) CanForceStop() bool { return true } func (m *MonitoringComponent) Shutdown(ctx context.Context) error { if m.closer == nil { return nil } return m.closer() } // GenericComponent provides a generic wrapper for any component with a close function type GenericComponent struct { name string closer func() error priority int canForceStop bool shutdownFunc func(ctx context.Context) error } // NewGenericComponent creates a new generic component func NewGenericComponent(name string, priority int, canForceStop bool) *GenericComponent { return &GenericComponent{ name: name, priority: priority, canForceStop: canForceStop, } } // SetCloser sets a simple closer function func (g *GenericComponent) SetCloser(closer func() error) *GenericComponent { g.closer = closer return g } // SetShutdownFunc sets a context-aware shutdown function func (g *GenericComponent) SetShutdownFunc(shutdownFunc func(ctx context.Context) error) *GenericComponent { g.shutdownFunc = shutdownFunc return g } func (g *GenericComponent) Name() string { return g.name } func (g *GenericComponent) Priority() int { return g.priority } func (g *GenericComponent) CanForceStop() bool { return g.canForceStop } func (g *GenericComponent) Shutdown(ctx context.Context) error { if g.shutdownFunc != nil { return g.shutdownFunc(ctx) } if g.closer != nil { // Wrap simple closer in context-aware function done := make(chan error, 1) go func() { done <- g.closer() }() select { case err := <-done: return err case <-ctx.Done(): return ctx.Err() } } return nil } // WorkerPoolComponent manages a pool of workers for graceful shutdown type WorkerPoolComponent struct { name string stopCh chan struct{} workers int priority int shutdownTime time.Duration } // NewWorkerPoolComponent creates a new worker pool component func NewWorkerPoolComponent(name string, stopCh chan struct{}, workers int, priority int) *WorkerPoolComponent { return &WorkerPoolComponent{ name: name, stopCh: stopCh, workers: workers, priority: priority, shutdownTime: 10 * time.Second, } } func (w *WorkerPoolComponent) Name() string { return fmt.Sprintf("%s (workers: %d)", w.name, w.workers) } func (w *WorkerPoolComponent) Priority() int { return w.priority } func (w *WorkerPoolComponent) CanForceStop() bool { return true } func (w *WorkerPoolComponent) Shutdown(ctx context.Context) error { if w.stopCh == nil { return nil } // Signal workers to stop close(w.stopCh) // Wait for workers to finish with timeout timeout := w.shutdownTime if deadline, ok := ctx.Deadline(); ok { if remaining := time.Until(deadline); remaining < timeout { timeout = remaining } } // In a real implementation, you would wait for workers to signal completion select { case <-time.After(timeout): return fmt.Errorf("workers did not shut down within %v", timeout) case <-ctx.Done(): return ctx.Err() } }