Files
next.orly.dev/pkg/utils/interrupt/README.md
mleku e56bf76257
Some checks failed
Go / build (push) Has been cancelled
Go / release (push) Has been cancelled
Add NIP-11 relay synchronization and group management features
- Introduced a new `sync` package for managing NIP-11 relay information and relay group configurations.
- Implemented a cache for NIP-11 documents, allowing retrieval of relay public keys and authoritative configurations.
- Enhanced the sync manager to update peer lists based on authoritative configurations from relay group events.
- Updated event handling to incorporate policy checks during event imports, ensuring compliance with relay rules.
- Refactored various components to utilize the new `sha256-simd` package for improved performance.
- Added comprehensive tests to validate the new synchronization and group management functionalities.
- Bumped version to v0.24.1 to reflect these changes.
2025-11-03 18:17:15 +00:00

5.6 KiB

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

  • Signal Handling: Clean handling of SIGINT, SIGTERM, and SIGHUP signals
  • Graceful Shutdown: Allows running goroutines to finish before exit
  • Hot Reload Support: Trigger application reloads on SIGHUP
  • Context Integration: Works seamlessly with Go's context package
  • Custom Callbacks: Execute custom cleanup logic during shutdown
  • Non-blocking: Doesn't block the main application loop

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:

  • New() *Handler - Create a new interrupt handler
  • Shutdown() <-chan struct{} - Channel closed on shutdown signals
  • Reload() <-chan struct{} - Channel closed on reload signals (SIGHUP)
  • Done() <-chan struct{} - Channel closed when all cleanup is complete
  • OnShutdown(func()) - Add a callback to run during shutdown
  • Wait() - Block until shutdown signal received
  • IsShuttingDown() bool - Check if shutdown is in progress

Signal Handling

The package handles these signals:

  • SIGINT: Interrupt (Ctrl+C) - Triggers graceful shutdown
  • SIGTERM: Termination - Triggers graceful shutdown
  • SIGHUP: Hangup - Triggers reload (can be customized)

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:

  • Signal handling for all supported signals
  • Callback execution order and timing
  • Context cancellation
  • Concurrent access patterns
  • Race condition prevention

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

  • Comprehensive test coverage
  • Go best practices compliance
  • Thread-safe design
  • Proper signal handling
  • No external dependencies

Integration

This package integrates well with:

  • HTTP servers (graceful shutdown)
  • Database connections (cleanup)
  • Worker pools (coordination)
  • Long-running services (reload capability)

License

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