Phase 1:
Event Ingestion
~5-10ms
Phase 2:
Queue Routing
~2-5ms
AMQP Publish → notification.events exchange
Topic routing to queues:
• notifications.web
• notifications.ios
• notifications.android
• notifications.email
Phase 3:
Batch Processing
~50-100ms
loop [for each platform queue]
Basic.Consume (prefetch: 100)
GET user_prefs + device_tokens
Cached preferences & tokens
Batching:
Collect up to 500 device tokens per FCM request
alt [by platform]
[platform = web/ios/android]
[platform = email]
[else → DLQ]
Phase 4:
External Delivery
~100-300ms
par [parallel delivery]
POST /fcm/send (multicast)
200 OK + delivery receipts
Phase 5:
User Receives
~10-50ms
📱 Push Notification
Displayed to User
✅ End-to-End:
P50: ~200ms
P95: <500ms
P99: ~800ms
Async: Log delivery status to PostgreSQL for analytics & retry tracking
⚠️ Error Handling:
• FCM 500 → Retry with exponential backoff (10s min)
• FCM 429 → Wait for retry-after header (default 60s)
• Token invalid (400/404) → Remove from DB, do not retry
• Timeout (10s) → Re-queue with jittering
• Max retries → Move to DLQ