Fix digest job race: events received between fetch and delete are dropped unsent #8
Loading…
Reference in a new issue
No description provided.
Delete branch "mailship-091-event-arrival-race-in-digest-job-events--614"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
mailship-091
Summary: Fix two bugs in the digest cron worker: (1) a race condition where events arriving between the fetch and the delete are deleted without being emailed, and (2) a stale closure that prevents
last_digest_atfrom advancing, causing duplicate sends on every tick.Changes:
src/database.ts— AddeddeleteEventsByIds(subscriptionId, eventIds)which deletes only the exact events that were sent, identified by their primary-key IDs. This replaces the timestamp-baseddeleteEventsForSubscription(sub.id, since)that previously deleted every row withreceived_at > since— including events that arrived during the slow digest send (profile loads, MJML render, SMTP).src/worker/email.ts— Two changes. First,runJobnow collects the IDs of the events it fetched and callsdeleteEventsByIdswith those IDs instead of the timestamp-based delete. Second,createJobnow re-fetches the subscription from the database on each cron tick before callingrunJob, sosub.last_digest_atreflects the latest value instead of the stale value captured when the job was first registered.test/event-arrival-race.test.js— New test that simulates the race: inserts Event A, fetches it, inserts Event B (the late arrival), deletes by the fetched IDs, and asserts that Event B survives. Previously this test failed because the timestamp-based delete removed Event B too.How to test: Run
pnpm run build && node test/event-arrival-race.test.jswithDATA_DIRset to a temporary directory. All 7 assertions should pass, confirming that a late-arriving event is no longer deleted.