README.md raw

interrupt

Graceful shutdown handling for Go applications. This package provides utilities for handling OS signals (SIGINT, SIGTERM) to enable clean shutdowns and hot reloading capabilities.

Features

Installation

go get next.orly.dev/pkg/utils/interrupt

Usage

Basic Shutdown Handling

package main

import (
    "context"
    "log"
    "time"

    "next.orly.dev/pkg/utils/interrupt"
)

func main() {
    // Create interrupt handler
    handler := interrupt.New()

    // Start your application
    go func() {
        for {
            select {
            case <-handler.Shutdown():
                log.Println("Shutting down worker...")
                return
            default:
                // Do work
                time.Sleep(time.Second)
            }
        }
    }()

    // Wait for shutdown signal
    <-handler.Done()
    log.Println("Application stopped")
}

Context Integration

func worker(ctx context.Context) {
    handler := interrupt.New()

    // Create context that cancels on shutdown
    workCtx, cancel := context.WithCancel(ctx)
    defer cancel()

    go func() {
        <-handler.Shutdown()
        cancel()
    }()

    // Use workCtx for all operations
    for {
        select {
        case <-workCtx.Done():
            return
        default:
            // Do work with context
        }
    }
}

Custom Shutdown Callbacks

handler := interrupt.New()

// Add cleanup callbacks
handler.OnShutdown(func() {
    log.Println("Closing database connections...")
    db.Close()
})

handler.OnShutdown(func() {
    log.Println("Saving application state...")
    saveState()
})

// Callbacks execute in reverse order when shutdown occurs
<-handler.Done()

Hot Reload Support

handler := interrupt.New()

// Handle reload signals
go func() {
    for {
        select {
        case <-handler.Reload():
            log.Println("Reloading configuration...")
            reloadConfig()
        case <-handler.Shutdown():
            return
        }
    }
}()

<-handler.Done()

API Reference

Handler

The main interrupt handler type.

Methods:

Signal Handling

The package handles these signals:

Shutdown Process

  1. Signal received (SIGINT/SIGTERM)
  2. Shutdown callbacks execute (in reverse order added)
  3. Shutdown channel closes
  4. Application can perform final cleanup
  5. Done channel closes

Testing

The interrupt package includes comprehensive tests:

Running Tests

# Run interrupt package tests
go test ./pkg/utils/interrupt

# Run with verbose output
go test -v ./pkg/utils/interrupt

# Run with race detection
go test -race ./pkg/utils/interrupt

Integration Testing

Part of the full test suite:

# Run all tests including interrupt
./scripts/test.sh

# Run specific package tests
go test ./pkg/utils/...

Test Coverage

Tests cover:

Example Test

# Test signal handling
go test -v ./pkg/utils/interrupt -run TestSignalHandling

# Test callback execution
go test -v ./pkg/utils/interrupt -run TestShutdownCallbacks

Examples

HTTP Server with Graceful Shutdown

package main

import (
    "context"
    "log"
    "net/http"
    "time"

    "next.orly.dev/pkg/utils/interrupt"
)

func main() {
    handler := interrupt.New()

    server := &http.Server{
        Addr: ":8080",
        Handler: http.DefaultServeMux,
    }

    // Shutdown server gracefully
    handler.OnShutdown(func() {
        ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
        defer cancel()
        server.Shutdown(ctx)
    })

    go server.ListenAndServe()

    <-handler.Done()
    log.Println("Server stopped")
}

Worker Pool with Cleanup

func main() {
    handler := interrupt.New()

    // Start worker pool
    pool := NewWorkerPool(10)
    pool.Start()

    // Clean shutdown
    handler.OnShutdown(func() {
        log.Println("Stopping worker pool...")
        pool.Stop()
    })

    <-handler.Done()
}

Development

Building

go build ./pkg/utils/interrupt

Code Quality

Integration

This package integrates well with:

License

Part of the next.orly.dev project. See main LICENSE file.