Repository navigation
fix(mobile): resolve iOS pushes on a fresh connection and retry a stale one - #8722
Conversation
…le one The Notification Service Extension used URLSession.shared. A long-lived extension process reuses pooled connections after the network path changes (VPN up or down), and a stale connection makes the relay /query time out or fail with -1005. The resolver then gives up and iOS shows the gateway's fixed "Reconnect to your relay now" body. - Use an ephemeral session per notification and invalidate it when done. - Retry /query once on timeout or a dropped connection, on a new session with a freshly signed NIP-98 proof. - Replace the gateway body with "You have a new message." so an unresolved push no longer reads like an instruction. Co-authored-by: studio <dc2fc481343672df31a689840c09299972e704dac592e0da6f18486646a7ee3e@localhost> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tom Brow <tomb@squareup.com>
…expiry Co-authored-by: studio <dc2fc481343672df31a689840c09299972e704dac592e0da6f18486646a7ee3e@localhost> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tom Brow <tomb@squareup.com>
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b1aaa7cde4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Co-authored-by: studio <dc2fc481343672df31a689840c09299972e704dac592e0da6f18486646a7ee3e@localhost> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tom Brow <tomb@squareup.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 176dd62565
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Retry sessions now come from an injectable factory, and the resolver's cancel() stops a retry that is running or about to start. Co-authored-by: studio <dc2fc481343672df31a689840c09299972e704dac592e0da6f18486646a7ee3e@localhost> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tom Brow <tomb@squareup.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Breezy! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
🔐 Codex Security Review
Review SummaryOverall Risk: NONE
FindingsNo concrete security, correctness, or reliability findings were identified. Notes
Generated by Codex Security Review | |
johnmatthewtennant
left a comment
There was a problem hiding this comment.
🤖 Reviewed exact head 0bee7e95fb0cb33b16e5a8a31c254587b5c20d62; no correctness blockers retained after all 35 fanout passes and source disposition. The retry cancellation owner now covers queued and active retries, and the fresh-session test distinguishes the retry session.
I independently inspected source and tests, but ran no Swift/native tests on Linux. A real push through the NSE and human acceptance remain unverified by this review.
…nity-storage-calculation * origin/main: fix(mobile): resolve iOS pushes on a fresh connection and retry a stale one (#8722) ci(loadgen): publish buzz-loadgen as ghcr.io/block/buzz-loadgen (#8717) test(relay): fix main's build after the test-state helper rename (#8718) fix(db): keep lease releases durable and deflake PostgreSQL lane tests (#8676) test: dedupe collect_until_eose by event id and uncap two shell tests (#8677) ci: cache the Tauri apt .debs and fit a cold Windows Rust run in its cap (#8679) test(desktop): gate flaky E2E specs on the state they assume (#8681) test(desktop): settle composer edits and press hover-only row actions by keyboard (#8682) Signed-off-by: Shu Hui <shu@squareup.com>
…vent-guards * origin/main: (29 commits) Restyle community invitations (#8728) feat(relay): add incremental artifact reads (#8523) fix(mobile): show agent DM typing and balance reply bubble padding (#8731) perf(relay): route author- and #p-scoped global subscriptions by selector (#8666) fix(desktop): fix the product races behind four E2E flakes (#8680) test(scripts): stop file-size fixtures leaking git repos and fsmonitor daemons (#8727) test(mobile): keep late callbacks and fixed sleeps from failing tests (#8678) fix(mobile): resolve iOS pushes on a fresh connection and retry a stale one (#8722) ci(loadgen): publish buzz-loadgen as ghcr.io/block/buzz-loadgen (#8717) test(relay): fix main's build after the test-state helper rename (#8718) fix(db): keep lease releases durable and deflake PostgreSQL lane tests (#8676) test: dedupe collect_until_eose by event id and uncap two shell tests (#8677) ci: cache the Tauri apt .debs and fit a cold Windows Rust run in its cap (#8679) test(desktop): gate flaky E2E specs on the state they assume (#8681) test(desktop): settle composer edits and press hover-only row actions by keyboard (#8682) test(desktop): measure inline video controls against their player (#8683) relay: open the search pool lazily so a dead reader can't block boot (#8662) fix(mobile): address #8650 second-pass review (#8691) Revert "fix(mobile): push every message in your own Solo chats (#8615)" (#8690) fix: don't notify workflow owners through their attribution tag (#8694) ... Signed-off-by: Ravneet Arora <rarora@squareup.com>
Summary
iOS users were seeing a run of push notifications that just said "Reconnect to your relay now". That is the push gateway's fixed APNs body. It shows when the Notification Service Extension (NSE) can't fetch the message from the relay.
On-device logs from one affected iPhone over a full day showed 12 of 385 NSE runs fail to resolve. Each failed relay
/query: 10 hit the 8 second timeout and 2 gotNSURLErrorNetworkConnectionLost(-1005). All 12 ran on a reused pooled connection fromURLSession.sharedin a long-lived NSE process. That process lived for hours while the network path changed between VPN and cellular. Of the fresh connections, 0 of 473 failed.This change:
/queryonce if it times out or loses its connection mid-request. The retry uses a new session and a freshly signed NIP-98 proof, because the relay rejects a replayed proof. Other failures (HTTP errors, offline, cancellation) are not retried. The retry is bounded to one attempt, so the worst case is about 16 seconds, inside the NSE's roughly 30 second budget.Related issue
N/A. Reported in Buzz #buzz-mobile.
Validation
BuzzPushNotificationResolverTests:Authorizationproof, and resolves.notConnectedToInternetis not retried.cancel()(called when the NSE finishes or expires) stops a pending retry.swift testsuite passes.didReceiveand to cancel it on expiry are included.simctl pushneeds notification permission, which the app only requests after joining a community.🤖 Generated with Claude Code