Worker coordination with file locks

This commit is contained in:
Jonas Linter
2025-10-15 10:07:42 +02:00
parent 0d04a546cf
commit 361611ae1b
7 changed files with 944 additions and 14 deletions

View File

@@ -0,0 +1,154 @@
╔══════════════════════════════════════════════════════════════════════════════╗
║ MULTI-WORKER FASTAPI ARCHITECTURE ║
╚══════════════════════════════════════════════════════════════════════════════╝
┌─────────────────────────────────────────────────────────────────────────────┐
│ Command: uvicorn alpine_bits_python.api:app --workers 4 │
└─────────────────────────────────────────────────────────────────────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Master Process (uvicorn supervisor) ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
│ │ │ │
┌───────────┼──────────┼──────────┼──────────┼───────────┐
│ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌──────────────────┐
│Worker 0│ │Worker 1│ │Worker 2│ │Worker 3│ │Lock File │
│PID:1001│ │PID:1002│ │PID:1003│ │PID:1004│ │/tmp/alpinebits │
└────┬───┘ └───┬────┘ └───┬────┘ └───┬────┘ │_primary_worker │
│ │ │ │ │.lock │
│ │ │ │ └──────────────────┘
│ │ │ │ ▲
│ │ │ │ │
└─────────┴──────────┴──────────┴─────────────┤
All try to acquire lock │
│ │
▼ │
┌───────────────────────┐ │
│ fcntl.flock(LOCK_EX) │────────────┘
│ Non-blocking attempt │
└───────────────────────┘
┏━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┓
▼ ▼
┌─────────┐ ┌──────────────┐
│SUCCESS │ │ WOULD BLOCK │
│(First) │ │(Others) │
└────┬────┘ └──────┬───────┘
│ │
▼ ▼
╔════════════════════════════════╗ ╔══════════════════════════════╗
║ PRIMARY WORKER ║ ║ SECONDARY WORKERS ║
║ (Worker 0, PID 1001) ║ ║ (Workers 1-3) ║
╠════════════════════════════════╣ ╠══════════════════════════════╣
║ ║ ║ ║
║ ✓ Handle HTTP requests ║ ║ ✓ Handle HTTP requests ║
║ ✓ Start email scheduler ║ ║ ✗ Skip email scheduler ║
║ ✓ Send daily reports ║ ║ ✗ Skip daily reports ║
║ ✓ Run DB migrations ║ ║ ✗ Skip DB migrations ║
║ ✓ Hash customers (startup) ║ ║ ✗ Skip customer hashing ║
║ ✓ Send error alerts ║ ║ ✓ Send error alerts ║
║ ✓ Process webhooks ║ ║ ✓ Process webhooks ║
║ ✓ AlpineBits endpoints ║ ║ ✓ AlpineBits endpoints ║
║ ║ ║ ║
║ Holds: worker_lock ║ ║ worker_lock = None ║
║ ║ ║ ║
╚════════════════════════════════╝ ╚══════════════════════════════╝
│ │
│ │
└──────────┬───────────────────────────┘
┌───────────────────────────┐
│ Incoming HTTP Request │
└───────────────────────────┘
(Load balanced by OS)
┌───────────┴──────────────┐
│ │
▼ ▼
Any worker can handle Round-robin distribution
the request normally across all 4 workers
╔══════════════════════════════════════════════════════════════════════════════╗
║ SINGLETON SERVICES ║
╚══════════════════════════════════════════════════════════════════════════════╝
Only run on PRIMARY worker:
┌─────────────────────────────────────────────────────────────┐
│ Email Scheduler │
│ ├─ Daily Report: 8:00 AM │
│ └─ Stats Collection: Per-hotel reservation counts │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Startup Tasks (One-time) │
│ ├─ Database table creation │
│ ├─ Customer data hashing/backfill │
│ └─ Configuration validation │
└─────────────────────────────────────────────────────────────┘
╔══════════════════════════════════════════════════════════════════════════════╗
║ SHARED SERVICES ║
╚══════════════════════════════════════════════════════════════════════════════╝
Run on ALL workers (primary + secondary):
┌─────────────────────────────────────────────────────────────┐
│ HTTP Request Handling │
│ ├─ Webhook endpoints (/api/webhook/*) │
│ ├─ AlpineBits endpoints (/api/alpinebits/*) │
│ └─ Health checks (/api/health) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Error Alert Handler │
│ └─ Any worker can send immediate error alerts │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Event Dispatching │
│ └─ Background tasks triggered by webhooks │
└─────────────────────────────────────────────────────────────┘
╔══════════════════════════════════════════════════════════════════════════════╗
║ SHUTDOWN & FAILOVER ║
╚══════════════════════════════════════════════════════════════════════════════╝
Graceful Shutdown:
┌─────────────────────────────────────────────────────────────┐
│ 1. SIGTERM received │
│ 2. Stop scheduler (primary only) │
│ 3. Close email handler │
│ 4. Release worker_lock (primary only) │
│ 5. Dispose database engine │
└─────────────────────────────────────────────────────────────┘
Primary Worker Crash:
┌─────────────────────────────────────────────────────────────┐
│ 1. Primary worker crashes │
│ 2. OS automatically releases file lock │
│ 3. Secondary workers continue handling requests │
│ 4. On next restart, first worker becomes new primary │
└─────────────────────────────────────────────────────────────┘
╔══════════════════════════════════════════════════════════════════════════════╗
║ KEY BENEFITS ║
╚══════════════════════════════════════════════════════════════════════════════╝
✓ No duplicate email notifications
✓ No race conditions in database operations
✓ Automatic failover if primary crashes
✓ Load distribution for HTTP requests
✓ No external dependencies (Redis, etc.)
✓ Simple and reliable