3.6 KiB
3.6 KiB
Backend Push Notifications
Overview
This service consumes messages from RabbitMQ, retrieves encrypted push tokens from a MySQL database, decrypts them, and sends notifications via the Expo Push API.
Features
- Automatic Retry Logic: Failed notifications are automatically retried up to 5 times with exponential backoff
- Dead Letter Queue (DLQ): Messages that exceed retry limits are moved to a DLQ for manual inspection
- Prometheus Metrics: Real-time monitoring of queue depths and message processing stats
- Token Management: Automatically expires invalid or unregistered device tokens
Architecture
RabbitMQ → Consumer → Database Lookup → Token Decryption → Expo Push API
↓ ↓
Retry Queue ←─────────── Delivery Validation ──────┘
↓
Dead Letter Queue
Prerequisites
- Python 3.10+
- MySQL/MariaDB database
- RabbitMQ server
- Expo Push Notification service account
Installation
pip install -r requirements.txt
Running the Service
python rabbitmq_handler.py
The service will:
- Connect to the MySQL database
- Establish RabbitMQ connection and declare queues
- Start consuming messages
- Begin Prometheus metrics server on port 9000
Configuration
Database Manager (db.py)
- Pool Size: 5 connections (configurable)
- Health Check Interval: 60 seconds
- Auto-commit: Enabled
- Cursor Type: DictCursor for convenient row access
RabbitMQ Consumer (rabbitmq_handler.py)
- Queue Name:
notifications - Retry Queue:
notifications_retry - Dead Letter Queue:
notifications_dlq - Max Retries: 5 attempts
- Retry TTL: 30 seconds
- Routing Key:
notify.user.*(standard),notify.user.retry(retries)
Notification Sender (send_notification.py)
- Endpoint:
https://exp.host/--/api/v2/push/send - Max Retries: 5 attempts
- Timeout: 5 seconds per request
- Backoff Strategy: Exponential (2^attempt seconds)
Message Format
Messages should be published to RabbitMQ with the following structure:
{
"title": "New Message",
"body": "You have a new notification",
"data": {
"category": "utility",
"link": "https://example.com",
"timestamp": "1760734800"
}
Routing Key: notify.user.<user_id> or notify.user.retry for retries
Retry Messages
Retry messages include additional metadata:
{
"title": "Notification Title",
"body": "Notification message body",
"uuid": "device-uuid-here",
"retry_count": 2
}
Delivery Validation
The service validates delivery results from the Expo Push API:
| Status | API Status | Action |
|---|---|---|
ok |
ok |
Success - metric incremented |
ok |
error (DeviceNotRegistered) |
Token expired in database |
ok |
error (other) |
Sent to DLQ |
error |
- | Sent to DLQ |
failure |
- | Requeued for retry |
Monitoring
Prometheus Metrics
Available at http://localhost:9000/metrics:
msg_published_total: Successfully delivered notificationsmsg_retry_total{queue_name, uuid, retry_count}: Retry attemptsmsg_failed_total: Failed deliveriesqueue_depth{queue_name}: Current queue message counts
Troubleshooting
Connection Issues
aiomysqlusesPyMySQLwhich requires themysql_native_passwordplugin to be used. Can be checked and changed via:
SELECT user, host, plugin FROM mysql.user WHERE user='backend-push-notifications';
ALTER USER 'backend-push-notifications'@'%' IDENTIFIED WITH mysql_native_password BY 'db_password';