Jobs & Queues
Jobs & Queues
Section titled “Jobs & Queues”Background job processing for reminders, agendas, attendance, and dental workflows.
Queue Topology
Section titled “Queue Topology”graph LR subgraph Publishers API["API Server"] Cron["Cron Scheduler"] Web["Webhook Handlers"] end
subgraph Redis_["Redis (Railway)"] R1["appointment-reminders"] R2["daily-agenda"] R3["dental-messages"] end
subgraph Workers["BullMQ Workers"] W1["Reminder Worker x5"] W2["Agenda Worker x2"] W3["Dental Worker x3"] end
API --> R1 Cron --> R2 Cron --> R3 Web --> R1 R1 --> W1 R2 --> W2 R3 --> W3 W1 --> WhatsApp["Meta WhatsApp API"] W2 --> WhatsApp W3 --> WhatsAppCron Schedule
Section titled “Cron Schedule”All times in UTC. El Salvador is UTC-6 with no DST.
| Job | UTC | CST | Purpose |
|---|---|---|---|
| Daily Agenda | 13:00 | 7 AM | WhatsApp schedule to all active staff |
| No-Show Mark | 05:00 | 11 PM (prev) | Auto-mark unattended appointments |
| Attendance Dispatch | */30 * * * * | — | QR check-in verification + AI verification |
| Payment Reminders | 14:00 | 8 AM | Monthly + 3-day advance notices |
| Recall Nightly | 06:00 | midnight | Dental recall campaign messages |
Idempotency
Section titled “Idempotency”All appointment-creating jobs use idempotency keys to prevent duplicates:
| Source | Key Pattern |
|---|---|
| Manual booking | MANUAL_{clinicId}_{doctorId}_{date}_{time} |
| WhatsApp booking | WHATSAPP_{clinicId}_{doctorId}_{date}_{time}_{messageId} |
| Reschedule | RESCHEDULE_{appointmentId}_{newDate}_{newTime} |
Monitoring
Section titled “Monitoring”Bull Board dashboard at /admin/queues — shows queue depths, job states,
failure counts, and retry schedules. Protected by basic auth.
Retry Policies
Section titled “Retry Policies”| Queue | Max attempts | Backoff |
|---|---|---|
| appointment-reminders | 3 | Exponential (1min, 5min, 15min) |
| daily-agenda | 2 | Fixed (5min) |
| dental-messages | 3 | Exponential (1min, 10min, 30min) |
Failed jobs are logged to audit_logs with the original payload for debugging.