Preventing duplicate customer messages when background jobs retry.
Push notifications are not financial ledger entries, but duplicates still damage trust. A customer should not receive the same failure alert three times because a worker retried, nor should two scheduler processes send the same campaign simultaneously.
Task queues normally provide at-least-once execution. Notification systems must design around that fact.
Claim the campaign before sending
Two workers can pick up the same scheduled campaign. Reading its status and then updating it is vulnerable to a race.
Lock the campaign and transition it to sending inside one database transaction:
with database_transaction():
campaign = Campaign.objects.select_for_update().get(id=campaign_id)
if campaign.status not in {"draft", "queued", "scheduled"}:
return
campaign.status = "sending"
campaign.save()
Only the worker that successfully claims the campaign proceeds.
Deduplicate recipients by delivery destination
A user may have duplicate device records, or the same token may appear in customer and merchant contexts. Build the target list from active devices, validate token format, and retain one target per actual push token.
Give each delivery a deterministic identity
Create a non-sensitive delivery key from the campaign and device token:
delivery_key = sha256(f"{campaign_id}:{device_token}".encode()).hexdigest()
Store one delivery record per campaign and key under a unique database constraint. Create that record before calling the push provider.
If a duplicate task finds the record, it can inspect the existing status rather than sending again.
Record actual provider outcomes
Queued does not mean sent. The delivery record should distinguish pending, accepted, and failed outcomes and retain a safe error message.
Campaign totals can then be calculated from delivery rows rather than optimistic task counts.
Handle partial failure
One invalid device token should not abort an entire campaign. Each delivery is an independent attempt, while the campaign summarizes the results.
If the campaign-level task crashes, move the campaign out of a permanent sending state so operations can inspect or retry it safely. Existing delivery keys prevent already-sent targets from receiving the message again.
The design principle
Exactly-once delivery cannot be guaranteed across every external push platform, but the application can guarantee that it submits each campaign-device pair at most once under its own retry model.
That requires transactional campaign claiming, target deduplication, deterministic delivery identities, and persistent per-device outcomes.
Top comments (0)