shutdown

package
v1.2.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 11, 2025 License: MIT Imports: 7 Imported by: 0

README

Shutdown Package

Home  /  Shutdown Package

 

This package provides comprehensive graceful shutdown management for RabbitMQ applications and other closable resources. It handles signal management, timeout control, in-flight operation tracking, and coordinated component shutdown.

 

Features

  • Signal Handling: Automatic handling of SIGINT, SIGTERM, and SIGHUP signals
  • Component Management: Register and coordinate shutdown of multiple components
  • In-Flight Tracking: Track and wait for ongoing operations to complete
  • Timeout Control: Configurable timeouts for shutdown operations
  • Concurrent Shutdown: Parallel shutdown of components for faster completion
  • Structured Logging: Optional structured logging of shutdown events
  • Context Support: Context-aware operations with cancellation support

🔝 back to top

 

Basic Usage

Simple Shutdown Manager
import (
    "github.com/cloudresty/go-rabbitmq/shutdown"
    "time"
)

// Create shutdown manager with default configuration
config := shutdown.DefaultShutdownConfig()
shutdownManager := shutdown.NewShutdownManager(config)

// Register components that need graceful shutdown
shutdownManager.Register(publisher)
shutdownManager.Register(consumer)
shutdownManager.Register(connection)

// Setup signal handling
shutdownManager.SetupSignalHandler()

// Your application logic here...

// Wait for shutdown to complete
shutdownManager.Wait()

🔝 back to top

 

Custom Configuration
config := shutdown.ShutdownConfig{
    Timeout:           time.Minute,     // 1 minute total shutdown timeout
    SignalTimeout:     time.Second * 10, // 10 seconds after signal
    GracefulDrainTime: time.Second * 30, // 30 seconds for in-flight operations
    Logger:            myCustomLogger,    // Optional custom logger
}

shutdownManager := shutdown.NewShutdownManager(config)

🔝 back to top

 

With Custom Logger
// Implement the Logger interface
type MyLogger struct{}

func (l MyLogger) Debug(msg string, fields ...shutdown.Field) {
    // Your debug logging implementation
}

func (l MyLogger) Info(msg string, fields ...shutdown.Field) {
    // Your info logging implementation
}

func (l MyLogger) Warn(msg string, fields ...shutdown.Field) {
    // Your warning logging implementation
}

func (l MyLogger) Error(msg string, fields ...shutdown.Field) {
    // Your error logging implementation
}

// Use custom logger
config := shutdown.DefaultShutdownConfig()
config.Logger = MyLogger{}
shutdownManager := shutdown.NewShutdownManager(config)

🔝 back to top

 

Advanced Usage

In-Flight Operation Tracking
// Get the in-flight tracker
tracker := shutdownManager.GetInFlightTracker()

// Before starting an operation
if tracker.Start() {
    defer tracker.Done() // Ensure this is called when operation completes

    // Perform your operation
    processMessage(message)
} else {
    // Shutdown is in progress, don't start new operations
    return ErrShutdownInProgress
}

🔝 back to top

 

Manual Shutdown
// Trigger shutdown programmatically
go func() {
    time.Sleep(5 * time.Minute) // Some condition
    shutdownManager.Shutdown()
}()

// Wait for shutdown with context
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

if err := shutdownManager.WaitWithContext(ctx); err != nil {
    log.Printf("Shutdown wait interrupted: %v", err)
}

🔝 back to top

 

Checking Shutdown Status
if shutdownManager.IsShutdown() {
    // Shutdown has been initiated
    return ErrShutdownInProgress
}

// Safe to continue with operations

🔝 back to top

 

Integration Patterns

Web Server Integration
func runWebServer() {
    // Setup shutdown manager
    config := shutdown.DefaultShutdownConfig()
    shutdownManager := shutdown.NewShutdownManager(config)

    // Create HTTP server
    server := &http.Server{
        Addr:    ":8080",
        Handler: mux,
    }

    // Register server for shutdown
    shutdownManager.Register(&serverCloser{server})

    // Setup signal handling
    shutdownManager.SetupSignalHandler()

    // Start server
    go func() {
        if err := server.ListenAndServe(); err != http.ErrServerClosed {
            log.Printf("Server error: %v", err)
        }
    }()

    // Wait for shutdown
    shutdownManager.Wait()
}

// Custom closer for HTTP server
type serverCloser struct {
    server *http.Server
}

func (sc *serverCloser) Close() error {
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    return sc.server.Shutdown(ctx)
}

🔝 back to top

 

Database Connection Pool
// Custom closer for database connections
type dbCloser struct {
    db *sql.DB
}

func (dc *dbCloser) Close() error {
    return dc.db.Close()
}

// Register database for shutdown
shutdownManager.Register(&dbCloser{db})

🔝 back to top

 

Worker Pool Integration
type workerPool struct {
    workers   []Worker
    shutdown  chan struct{}
    wg        sync.WaitGroup
    tracker   *shutdown.InFlightTracker
}

func (wp *workerPool) Start(shutdownManager *shutdown.ShutdownManager) {
    wp.tracker = shutdownManager.GetInFlightTracker()

    for _, worker := range wp.workers {
        wp.wg.Add(1)
        go func(w Worker) {
            defer wp.wg.Done()
            wp.runWorker(w)
        }(worker)
    }
}

func (wp *workerPool) runWorker(worker Worker) {
    for {
        select {
        case job := <-worker.JobChan():
            // Track in-flight operation
            if wp.tracker.Start() {
                wp.processJob(job)
                wp.tracker.Done()
            } else {
                // Shutdown in progress, reject job
                job.Reject()
            }
        case <-wp.shutdown:
            return
        }
    }
}

func (wp *workerPool) Close() error {
    close(wp.shutdown)
    wp.wg.Wait()
    return nil
}

🔝 back to top

 

Best Practices

1. Component Registration Order

Register components in reverse dependency order (most dependent first):

// Register in order of dependency (reverse of startup order)
shutdownManager.Register(httpServer)    // Depends on services
shutdownManager.Register(messageQueue)  // Depends on database
shutdownManager.Register(database)      // Independent

🔝 back to top

 

2. Timeout Configuration

Set appropriate timeouts based on your application's needs:

config := shutdown.ShutdownConfig{
    Timeout:           time.Minute * 2,  // Overall timeout
    SignalTimeout:     time.Second * 15, // Grace period
    GracefulDrainTime: time.Minute,      // Drain time
}

🔝 back to top

 

3. In-Flight Operation Patterns

Always use defer for tracking completion:

if tracker.Start() {
    defer tracker.Done() // Critical: always call Done()

    // Your operation here
    return processMessage(msg)
}

🔝 back to top

 

4. Error Handling

Handle shutdown errors gracefully:

type resilientCloser struct {
    component Component
    logger    Logger
}

func (rc *resilientCloser) Close() error {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    if err := rc.component.Shutdown(ctx); err != nil {
        rc.logger.Warn("Component shutdown failed",
            shutdown.StringField("error", err.Error()))
        // Don't return error to avoid blocking other shutdowns
        return nil
    }
    return nil
}

🔝 back to top

 

5. Testing Shutdown Logic

Test shutdown behavior in your applications:

func TestGracefulShutdown(t *testing.T) {
    config := shutdown.DefaultShutdownConfig()
    config.Timeout = time.Second // Short timeout for testing

    manager := shutdown.NewShutdownManager(config)

    // Register test components
    manager.Register(&testComponent{})

    // Trigger shutdown
    go manager.Shutdown()

    // Verify shutdown completes within timeout
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()

    if err := manager.WaitWithContext(ctx); err != nil {
        t.Errorf("Shutdown timeout: %v", err)
    }
}

🔝 back to top

 

Error Handling

The shutdown package handles various error scenarios:

🔝 back to top

 

Component Shutdown Errors
// Components that fail to shutdown don't block others
type faultyComponent struct{}

func (fc *faultyComponent) Close() error {
    return errors.New("simulated failure")
}

// This won't prevent other components from shutting down
manager.Register(&faultyComponent{})

🔝 back to top

 

Timeout Handling
// Shutdown will timeout after configured duration
config := shutdown.ShutdownConfig{
    Timeout: time.Second * 5, // Short timeout
}

manager := shutdown.NewShutdownManager(config)
// If shutdown takes longer than 5 seconds, it will timeout

🔝 back to top

 

Signal Handling
// Automatic handling of common shutdown signals
signals := manager.SetupSignalHandler()

// You can also monitor signals manually
go func() {
    sig := <-signals
    log.Printf("Received signal: %s", sig)
    // Shutdown is automatically triggered
}()

🔝 back to top

 

Performance Considerations

  • Concurrent Shutdown: Components shut down in parallel for faster completion
  • Resource Cleanup: Automatic cleanup of internal resources
  • Memory Efficiency: Minimal memory overhead for tracking operations
  • Signal Handling: Efficient signal handling with minimal goroutines

🔝 back to top

 

Troubleshooting

Common Issues
  1. Shutdown Timeout
WARN: Graceful shutdown timeout exceeded

Solution: Increase timeout or optimize component shutdown logic.

🔝 back to top

 

  1. Component Registration After Shutdown
if !manager.IsShutdown() {
    manager.Register(component)
}

🔝 back to top

 

  1. In-Flight Operation Leaks
// Always use defer
if tracker.Start() {
    defer tracker.Done() // Don't forget this!
    // ... operation ...
}

🔝 back to top

 

For more examples and patterns, see the examples/ directory in the main repository.

🔝 back to top

 


 

An open source project brought to you by the Cloudresty team.

Website  |  LinkedIn  |  BlueSky  |  GitHub  |  Docker Hub

 

Documentation

Overview

Package shutdown provides coordinated graceful shutdown management for RabbitMQ components and other closable resources. It handles signal management, timeout control, and tracking of in-flight operations during shutdown.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Closable

type Closable interface {
	Close() error
}

Closable interface for components that can be gracefully closed

type Field

type Field interface {
	Key() string
	Value() any
}

Field represents a log field

func DurationField

func DurationField(key string, value time.Duration) Field

func IntField

func IntField(key string, value int) Field

func StringField

func StringField(key, value string) Field

Helper functions for creating fields

type InFlightTracker

type InFlightTracker struct {
	// contains filtered or unexported fields
}

InFlightTracker tracks in-flight operations for graceful shutdown

func NewInFlightTracker

func NewInFlightTracker() *InFlightTracker

NewInFlightTracker creates a new in-flight operations tracker

func (*InFlightTracker) Close

func (ift *InFlightTracker) Close() error

Close prevents new operations and waits for existing ones to complete

func (*InFlightTracker) CloseWithTimeout

func (ift *InFlightTracker) CloseWithTimeout(timeout time.Duration) error

CloseWithTimeout waits for in-flight operations with a timeout

func (*InFlightTracker) Done

func (ift *InFlightTracker) Done()

Done marks the completion of an operation

func (*InFlightTracker) IsClosed

func (ift *InFlightTracker) IsClosed() bool

IsClosed returns true if the tracker is closed

func (*InFlightTracker) Start

func (ift *InFlightTracker) Start() bool

Start marks the beginning of an operation

type Logger

type Logger interface {
	Debug(msg string, fields ...Field)
	Info(msg string, fields ...Field)
	Warn(msg string, fields ...Field)
	Error(msg string, fields ...Field)
}

Logger interface for structured logging

type NoOpLogger

type NoOpLogger struct{}

NoOpLogger provides a no-operation logger implementation

func (NoOpLogger) Debug

func (l NoOpLogger) Debug(msg string, fields ...Field)

func (NoOpLogger) Error

func (l NoOpLogger) Error(msg string, fields ...Field)

func (NoOpLogger) Info

func (l NoOpLogger) Info(msg string, fields ...Field)

func (NoOpLogger) Warn

func (l NoOpLogger) Warn(msg string, fields ...Field)

type ShutdownConfig

type ShutdownConfig struct {
	Timeout           time.Duration // Overall shutdown timeout
	SignalTimeout     time.Duration // Additional time to wait after receiving signal
	GracefulDrainTime time.Duration // Time to allow for in-flight operations to complete
	Logger            Logger        // Logger for shutdown events
}

ShutdownConfig holds configuration for the shutdown manager

func DefaultShutdownConfig

func DefaultShutdownConfig() ShutdownConfig

DefaultShutdownConfig returns sensible default shutdown configuration

type ShutdownManager

type ShutdownManager struct {
	// contains filtered or unexported fields
}

ShutdownManager provides coordinated graceful shutdown for RabbitMQ components

func NewShutdownManager

func NewShutdownManager(config ShutdownConfig) *ShutdownManager

NewShutdownManager creates a new shutdown manager

func (*ShutdownManager) GetInFlightTracker

func (sm *ShutdownManager) GetInFlightTracker() *InFlightTracker

GetInFlightTracker returns the in-flight operations tracker

func (*ShutdownManager) IsShutdown

func (sm *ShutdownManager) IsShutdown() bool

IsShutdown returns true if shutdown has been initiated

func (*ShutdownManager) IsShutdownComplete

func (sm *ShutdownManager) IsShutdownComplete() bool

IsShutdownComplete implements the simplified GracefulShutdown interface

func (*ShutdownManager) Register

func (sm *ShutdownManager) Register(component Closable)

Register adds a component to be managed during shutdown

func (*ShutdownManager) RegisterComponent

func (sm *ShutdownManager) RegisterComponent(component rabbitmq.Closable) error

RegisterComponent implements the simplified GracefulShutdown interface

func (*ShutdownManager) SetupSignalHandler

func (sm *ShutdownManager) SetupSignalHandler() <-chan os.Signal

SetupSignalHandler sets up signal handling for graceful shutdown

func (*ShutdownManager) SetupSignalHandling

func (sm *ShutdownManager) SetupSignalHandling() <-chan struct{}

SetupSignalHandling implements the simplified GracefulShutdown interface

func (*ShutdownManager) Shutdown

func (sm *ShutdownManager) Shutdown()

Shutdown performs graceful shutdown of all registered components

func (*ShutdownManager) ShutdownGracefully

func (sm *ShutdownManager) ShutdownGracefully(ctx context.Context) error

ShutdownGracefully implements the simplified GracefulShutdown interface

func (*ShutdownManager) Wait

func (sm *ShutdownManager) Wait()

Wait blocks until shutdown is complete

func (*ShutdownManager) WaitWithContext

func (sm *ShutdownManager) WaitWithContext(ctx context.Context) error

WaitWithContext blocks until shutdown is complete or context is cancelled

type SimpleField

type SimpleField struct {
	// contains filtered or unexported fields
}

SimpleField implements the Field interface for simple key-value pairs

func (SimpleField) Key

func (f SimpleField) Key() string

func (SimpleField) Value

func (f SimpleField) Value() any

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL