feat: implement graceful shutdown with SIGINT/SIGTERM support
- Add WebSocket shutdown() with client notification and graceful close - Enhance download service stop() with pending state persistence - Expand FastAPI lifespan shutdown with proper cleanup sequence - Add SQLite WAL checkpoint before database close - Update stop_server.sh to use SIGTERM with timeout fallback - Configure uvicorn timeout_graceful_shutdown=30s - Update ARCHITECTURE.md with shutdown documentation
This commit is contained in:
@@ -141,6 +141,78 @@ Source: [src/config/settings.py](../src/config/settings.py#L1-L96)
|
||||
|
||||
---
|
||||
|
||||
## 11. Graceful Shutdown
|
||||
|
||||
The application implements a comprehensive graceful shutdown mechanism that ensures data integrity and proper cleanup when the server is stopped via Ctrl+C (SIGINT) or SIGTERM.
|
||||
|
||||
### 11.1 Shutdown Sequence
|
||||
|
||||
```
|
||||
1. SIGINT/SIGTERM received
|
||||
+-- Uvicorn catches signal
|
||||
+-- Stops accepting new requests
|
||||
|
||||
2. FastAPI lifespan shutdown triggered
|
||||
+-- 30 second total timeout
|
||||
|
||||
3. WebSocket shutdown (5s timeout)
|
||||
+-- Broadcast {"type": "server_shutdown"} to all clients
|
||||
+-- Close each connection with code 1001 (Going Away)
|
||||
+-- Clear connection tracking data
|
||||
|
||||
4. Download service stop (10s timeout)
|
||||
+-- Set shutdown flag
|
||||
+-- Persist active download as "pending" in database
|
||||
+-- Cancel active download task
|
||||
+-- Shutdown ThreadPoolExecutor with wait
|
||||
|
||||
5. Progress service cleanup
|
||||
+-- Clear event subscribers
|
||||
+-- Clear active progress tracking
|
||||
|
||||
6. Database cleanup (10s timeout)
|
||||
+-- SQLite: Run PRAGMA wal_checkpoint(TRUNCATE)
|
||||
+-- Dispose async engine
|
||||
+-- Dispose sync engine
|
||||
|
||||
7. Process exits cleanly
|
||||
```
|
||||
|
||||
Source: [src/server/fastapi_app.py](../src/server/fastapi_app.py#L142-L210)
|
||||
|
||||
### 11.2 Key Components
|
||||
|
||||
| Component | File | Shutdown Method |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------ | ------------------------ |
|
||||
| WebSocket Service | [websocket_service.py](../src/server/services/websocket_service.py) | `shutdown(timeout=5.0)` |
|
||||
| Download Service | [download_service.py](../src/server/services/download_service.py) | `stop(timeout=10.0)` |
|
||||
| Database Connection | [connection.py](../src/server/database/connection.py) | `close_db()` |
|
||||
| Uvicorn Config | [run_server.py](../run_server.py) | `timeout_graceful_shutdown=30` |
|
||||
| Stop Script | [stop_server.sh](../stop_server.sh) | SIGTERM with fallback |
|
||||
|
||||
### 11.3 Data Integrity Guarantees
|
||||
|
||||
1. **Active downloads preserved**: In-progress downloads are saved as "pending" and can resume on restart.
|
||||
|
||||
2. **Database WAL flushed**: SQLite WAL checkpoint ensures all writes are in the main database file.
|
||||
|
||||
3. **WebSocket clients notified**: Clients receive shutdown message before connection closes.
|
||||
|
||||
4. **Thread pool cleanup**: Background threads complete or are gracefully cancelled.
|
||||
|
||||
### 11.4 Manual Stop
|
||||
|
||||
```bash
|
||||
# Graceful stop via script (sends SIGTERM, waits up to 30s)
|
||||
./stop_server.sh
|
||||
|
||||
# Or press Ctrl+C in terminal running the server
|
||||
```
|
||||
|
||||
Source: [stop_server.sh](../stop_server.sh#L1-L80)
|
||||
|
||||
---
|
||||
|
||||
## 3. Component Interactions
|
||||
|
||||
### 3.1 Request Flow (REST API)
|
||||
|
||||
Reference in New Issue
Block a user