Loading
Add email background worker command
Description
This PR introduces background email processing so transactional mail is no longer sent inside the web request.
Emails are written to email_jobs, notified via Redis (cdli:queue:email), and delivered by bin/cake email_worker. When the queue is disabled, mail is still sent inline so environments without a worker keep working.
Technicalities
Queue + worker
- New
bin/cake email_workercommand (--oncefor testing) - Consumes Redis with
BRPOP, claims rows withFOR UPDATE - Falls back to DB polling when Redis is empty or a push was missed
- Handles phpredis
BRPOPtimeout ([]) correctly - Shared
EmailJobDispatcherfor worker and sync fallback - Supported actions:
welcome,resetPassword,adminNewUser,adminCrowdsourcingPrivilege,contributionDeclined - Transient failures retry with backoff (1 → 2 → 4 min) up to
max_attempts, thenfailed - Permanent failures (
UndeliverableEmailException) are markedcancelled - Watchdog reclaims stuck
processingjobs after 10 minutes; exhausted attempts are failed instead of reclaimed forever - Fail-fast if
email_jobsis missing (config/schema/email_jobs.sql)
Request-path safety
- Gated by
CDLI_EMAIL_QUEUE_ENABLED/EmailQueue.enabled(default: false) - Forgot-password uses soft success copy and revokes the reset token if enqueue fails
- Reset URL is built in the web request and stored in the job payload
Dev infrastructure
app_email_workerservice (dev/gea/mpi)- Depends on MariaDB, Redis, and Postfix
Tests
EmailWorkerCommandTest: claim / send / retry / fail / cancel / watchdog / priority / duplicate preventionEmailQueueServiceTest: enqueue + sync fallbackEmailJobsTableTest: payload / allow-list validation
Fakes: FakeRedisForWorker, TimeoutFakeRedisForWorker, TestableEmailWorkerCommand, RecordingEmail
Edited by sonikagutha