This document describes the graceful shutdown implementation for the PredictIQ API backend workers.
The application now supports graceful shutdown of all background workers when receiving termination signals (SIGTERM, SIGINT, Ctrl+C). This ensures that:
- In-flight work is completed or properly handled
- Workers stop cleanly without data loss
- Shutdown completes within a reasonable timeout (30 seconds by default)
- Application state is properly saved before termination
-
ShutdownCoordinator (
src/shutdown.rs)- Coordinates shutdown across all workers
- Uses broadcast channels to signal shutdown
- Tracks worker completion with watch channels
- Implements timeout handling
-
WorkerHandle (
src/shutdown.rs)- Wraps individual worker tasks
- Provides join/abort functionality
- Reports completion to coordinator
-
Signal Handlers (
src/shutdown.rs)- Cross-platform signal handling (Unix/Windows)
- Listens for SIGTERM, SIGINT, Ctrl+C, etc.
The following background workers support graceful shutdown:
-
Blockchain Sync Worker (
src/blockchain.rs)- Saves sync cursor before shutdown
- Completes current sync operation
- Logs remaining state
-
Blockchain Transaction Monitor (
src/blockchain.rs)- Logs watched transactions count
- Stops monitoring gracefully
-
Email Queue Worker (
src/email/queue.rs)- Processes remaining retries
- Reports jobs still in processing state
- Completes current job processing
-
Rate Limiter Cleanup (
src/lib.rs)- Performs final cleanup
- Stops periodic maintenance
The application automatically handles graceful shutdown when receiving termination signals:
# Send SIGTERM (recommended)
kill -TERM <pid>
# Send SIGINT (Ctrl+C)
kill -INT <pid>Environment variables that affect shutdown behavior:
RUST_LOG: Set toinfoordebugto see shutdown logs- No specific shutdown timeout configuration (hardcoded to 30 seconds)
The enhanced health endpoint (/health) provides worker status:
{
"status": "ok",
"timestamp": "2024-03-30T10:00:00Z",
"workers": {
"blockchain_sync": "running",
"blockchain_monitor": "running",
"email_queue": "running",
"rate_limiter_cleanup": "running",
"email_queue_processing": 0
}
}Run the shutdown-specific tests:
cargo test shutdown_testsRun the full integration test (requires Redis and PostgreSQL):
cargo test test_graceful_shutdown_integration --ignoredUse the provided test scripts:
Linux/macOS:
./test_shutdown.shWindows:
.\test_shutdown.ps1- Signal handler receives termination signal
- ShutdownCoordinator broadcasts shutdown signal to all workers
- Each worker:
- Receives shutdown signal via broadcast channel
- Completes current operation or saves state
- Reports completion to coordinator
- Coordinator waits for all workers with timeout
- HTTP server stops accepting new connections
- Application exits
- Timeout: If workers don't complete within 30 seconds, shutdown proceeds anyway
- Worker Errors: Individual worker failures don't prevent overall shutdown
- Signal Errors: Signal handler setup failures are logged but don't prevent startup
- Blockchain Sync: Cursor position saved to Redis
- Email Queue: Jobs remain in Redis queues for next startup
- Transaction Monitor: Watched transactions logged for debugging
- Rate Limiter: Final cleanup performed
-
Shutdown Timeout
- Check worker logs for stuck operations
- Verify Redis/database connectivity
- Consider increasing timeout in code
-
Workers Not Stopping
- Ensure broadcast channels are properly subscribed
- Check for infinite loops without shutdown checks
- Verify tokio::select! usage
-
Data Loss
- Check that state is saved before worker exit
- Verify database transactions are committed
- Ensure Redis operations complete
Enable debug logging to see detailed shutdown flow:
RUST_LOG=debug cargo runLook for these log messages:
- "Initiating graceful shutdown for N workers"
- "Worker 'name' received shutdown signal"
- "Worker 'name' shutdown complete"
- "All workers completed graceful shutdown"
- Configurable Timeout: Make shutdown timeout configurable via environment variable
- Drain Mode: Stop accepting new work before shutdown
- Health Checks: More detailed worker health reporting
- Metrics: Prometheus metrics for shutdown events
- Job Recovery: Better handling of interrupted jobs on restart
tokio: Async runtime with signal handlinganyhow: Error handlingtracing: Loggingserde_json: Health endpoint JSON responses
- Rust: 1.70+
- Platforms: Linux, macOS, Windows
- Signals: SIGTERM, SIGINT (Unix), Ctrl+C/Break/Close/Shutdown (Windows)