interrupt

package
v0.24.3 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 2025 License: Unlicense Imports: 9 Imported by: 0

README

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.

Documentation

Overview

Package interrupt is a library for providing handling for Ctrl-C/Interrupt handling and triggering callbacks for such things as closing files, flushing buffers, and other elements of graceful shutdowns.

Index

Constants

This section is empty.

Variables

View Source
var (
	// RestartRequested is set true after restart is requested.
	RestartRequested bool // = true

	// ShutdownRequestChan is a channel that can receive shutdown requests
	ShutdownRequestChan = qu.T()

	// HandlersDone is closed after all interrupt handlers run the first time an
	// interrupt is signaled.
	HandlersDone = make(qu.C)
)

Functions

func AddHandler

func AddHandler(handler func())

AddHandler adds a handler to call when a SIGINT (Ctrl+C) is received.

func GoroutineDump

func GoroutineDump() string

GoroutineDump returns a string with the current goroutine dump in order to show what's going on in case of timeout.

func Listener

func Listener()

Listener listens for interrupt signals, registers interrupt callbacks, and responds to custom shutdown signals as required

func Request

func Request()

Request programmatically requests a shutdown

func RequestRestart

func RequestRestart()

RequestRestart sets the reset flag and requests a restart

func Requested

func Requested() bool

Requested returns true if an interrupt has been requested

func Restart

func Restart()

Restart uses syscall.Exec to restart the process. macOS and Windows are not implemented, currently.

Types

type HandlerWithSource

type HandlerWithSource struct {
	Source string
	Fn     func()
}

HandlerWithSource is an interrupt handling closure and the source location that it was sent from.

Source Files

  • main.go
  • restart.go
  • sigterm.go

Jump to

Keyboard shortcuts

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