Skip to content

Jobs & Queues

Background job processing for reminders, agendas, attendance, and dental workflows.

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 --> WhatsApp

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

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}

Bull Board dashboard at /admin/queues — shows queue depths, job states, failure counts, and retry schedules. Protected by basic auth.

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.