This commit is contained in:
parent
9cc568e06f
commit
d2586defda
135
README.md
135
README.md
@ -2,37 +2,138 @@
|
||||
|
||||
|
||||
## Overview
|
||||
This part of the backend handles device push notifications for registered users. It consumes messages from RabbitMQ, looks up user device tokens from a MySQL database, and sends notifications via Expo's API. Failed deliveries are retried or sent to a dead-letter queue.
|
||||
|
||||
This service consumes messages from RabbitMQ, retrieves encrypted push tokens from a MySQL database, decrypts them, and sends notifications via the Expo Push API. It includes comprehensive error handling, automatic retries, dead-letter queuing, and Prometheus metrics.
|
||||
|
||||
|
||||
## Requirements
|
||||
- Python 3.12+
|
||||
- MySQL database
|
||||
- RabbitMQ
|
||||
- Python packages from requirements.txt
|
||||
## Features
|
||||
|
||||
- **Asynchronous Architecture**: Built with `asyncio`, `aio_pika`, and `aiomysql` for high-performance concurrent operations
|
||||
- **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
|
||||
- **Health Monitoring**: Database connection pool health checks every 60 seconds
|
||||
- **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
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Running the Service
|
||||
|
||||
```bash
|
||||
python rabbitmq_handler.py
|
||||
```
|
||||
|
||||
The service will:
|
||||
1. Connect to the MySQL database
|
||||
2. Establish RabbitMQ connection and declare queues
|
||||
3. Start consuming messages
|
||||
4. Begin Prometheus metrics server on port 9000
|
||||
|
||||
|
||||
## Configuration
|
||||
|
||||
**Environment variables:**
|
||||
### Database Manager (`db.py`)
|
||||
|
||||
- `LOG_LEVEL` (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
||||
- **Pool Size**: 5 connections (configurable)
|
||||
- **Health Check Interval**: 60 seconds
|
||||
- **Auto-commit**: Enabled
|
||||
- **Cursor Type**: DictCursor for convenient row access
|
||||
|
||||
- `RABBITMQ_URL`
|
||||
### RabbitMQ Consumer (`rabbitmq_handler.py`)
|
||||
|
||||
- `MYSQL_HOST`, `MYSQL_USER`, `MYSQL_PASSWORD`, `MYSQL_DATABASE`
|
||||
- **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)
|
||||
|
||||
- `API_ENDPOINT` (Expo push API)
|
||||
### 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)
|
||||
|
||||
## Metrics
|
||||
### Message Format
|
||||
|
||||
Metrics are exposed on port `9000` for Prometheus, including:
|
||||
Messages should be published to RabbitMQ with the following structure:
|
||||
|
||||
- `MSG_PUBLISHED`
|
||||
```json
|
||||
{
|
||||
"title": "New Message",
|
||||
"body": "You have a new notification",
|
||||
"data": {
|
||||
"category": "utility",
|
||||
"link": "https://example.com",
|
||||
"timestamp": "1760734800"
|
||||
}
|
||||
```
|
||||
|
||||
- `MSG_FAILED`
|
||||
**Routing Key**: `notify.user.<user_id>` or `notify.user.retry` for retries
|
||||
|
||||
- `MSG_RETRY`
|
||||
### Retry Messages
|
||||
|
||||
- Queue sizes
|
||||
Retry messages include additional metadata:
|
||||
|
||||
```json
|
||||
{
|
||||
"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 notifications
|
||||
- `msg_retry_total{queue_name, uuid, retry_count}`: Retry attempts
|
||||
- `msg_failed_total`: Failed deliveries
|
||||
- `queue_depth{queue_name}`: Current queue message counts
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Connection Issues
|
||||
- `aiomysql` uses `PyMySQL` which requires the `mysql_native_password` plugin to be used. Can be checked and changed via:
|
||||
```sql
|
||||
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';
|
||||
```
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user