You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
2 months ago | |
|---|---|---|
| .. | ||
| README.md | 2 months ago | |
| main.go | 4 months ago | |
| restart.go | 4 months ago | |
| restart_darwin.go | 4 months ago | |
| restart_windows.go | 4 months ago | |
| sigterm.go | 4 months ago | |
README.md
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 handlerShutdown() <-chan struct{}- Channel closed on shutdown signalsReload() <-chan struct{}- Channel closed on reload signals (SIGHUP)Done() <-chan struct{}- Channel closed when all cleanup is completeOnShutdown(func())- Add a callback to run during shutdownWait()- Block until shutdown signal receivedIsShuttingDown() 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
- Signal received (SIGINT/SIGTERM)
- Shutdown callbacks execute (in reverse order added)
- Shutdown channel closes
- Application can perform final cleanup
- 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.