Repository navigation
Expire push notifications 15 minutes after their event - #100
Merged
Merged
Conversation
Queued notifications never expired, rate-limit and network retries had no limit, and every push was sent with a seven-day ttl, so APNs and FCM delivered it whenever an offline phone reconnected. The broker now fails a notification as EXPIRED once it is 15 minutes old, never sends or resends it after that, and sends Expo an absolute expiration at the same time instead of the ttl. Receipts for pushes already sent are still checked, so unregistered devices are still disabled.
8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Push notifications now expire 15 minutes after the event that produced them. This applies in the broker and at Apple and Google.
Before
prune()only deletesfailedrows, and rate-limit and network retries had no limit. The backoff caps at 256s, so a rate-limited notification was retried about every 4.3 minutes until it was delivered, resolved, paused, or the device was disabled. Resend rate-limited receipts with backoff, but never after resolution #97 extended this to rate-limited receipts.ttl: 7 * 24 * 60 * 60, so APNs and FCM kept it for 7 days and delivered it whenever an offline phone came back.After.
notificationLifetimeMs = 15 * 60_000inexpo-push.ts, measured fromcreated_at_ms, which is when the broker queued the event.expireQueued()runs before each batch and fails queued rows at or past the lifetime asfailed / EXPIRED.canSendQueuedchecks again just before each send.markRetryfails the row asEXPIREDif the next attempt would land at or past the lifetime. Otherwise it backs off as before.DeviceNotRegisteredstill disables the device.PAUSED,RESOLVED), and checked before expiry.The push sends Expo
expiration: floor((created_at_ms + 15 min) / 1000), an absolute Unix time, in place ofttl. Retries keep the same expiration. Expo usesttloverexpirationwhen both are present, sottlis removed.collapseId,tag,priorityandchannelIdare unchanged.Effects to know about
EXPIREDand isn't resent. Resend rate-limited receipts with backoff, but never after resolution #97's receipt resend path is effectively unreachable, and a push that late isn't wanted anyway. Resend rate-limited receipts with backoff, but never after resolution #97'sRESOLVEDguard stays in place.expiresAtMsin the encrypted routing envelope is unchanged. The phone checks it when a notification is tapped from the notification center.priority: "high", which reduces that risk.docs/NOTIFICATIONS.mdanddocs/SPEC.mddescribe the lifetime. Neither documented the old TTL or retry behavior. No schema change.Verification
main: theexpirationfield with nottl, retries keeping the original expiration, rows at or past the lifetime not sent, each retry kind not resending past the lifetime, a row just inside the lifetime still sent, and a queued row expiring while a ticketed row keeps its receipt. One guard passed before and still passes: unregistered devices are disabled from receipts long after the lifetime.pnpm lint