perf(mobile): pace startup subscriptions - #7002
Conversation
Signed-off-by: Carl <4ddaeec1f70e26699465b4f4d4a55a825abb6045d769a21d44551b15c1e81f93@buzz.block.builderlab.xyz>
Co-authored-by: Tom Brow <tomb@block.xyz> Signed-off-by: Carl <4ddaeec1f70e26699465b4f4d4a55a825abb6045d769a21d44551b15c1e81f93@buzz.block.builderlab.xyz>
Signed-off-by: Carl <4ddaeec1f70e26699465b4f4d4a55a825abb6045d769a21d44551b15c1e81f93@buzz.block.builderlab.xyz>
Signed-off-by: Carl <4ddaeec1f70e26699465b4f4d4a55a825abb6045d769a21d44551b15c1e81f93@buzz.block.builderlab.xyz>
Signed-off-by: Carl <4ddaeec1f70e26699465b4f4d4a55a825abb6045d769a21d44551b15c1e81f93@buzz.block.builderlab.xyz>
Signed-off-by: Carl <4ddaeec1f70e26699465b4f4d4a55a825abb6045d769a21d44551b15c1e81f93@buzz.block.builderlab.xyz> Co-authored-by: Amp <amp@ampcode.com> Ai-assisted: true Signed-off-by: Carl <4ddaeec1f70e26699465b4f4d4a55a825abb6045d769a21d44551b15c1e81f93@buzz.block.builderlab.xyz>
Signed-off-by: Carl <4ddaeec1f70e26699465b4f4d4a55a825abb6045d769a21d44551b15c1e81f93@buzz.block.builderlab.xyz>
🔐 Codex Security Review
|
|
@codex review |
|
@builderbot review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5d7c606cb9
ℹ️ 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".
| List<NostrFilter> filters, { | ||
| Duration timeout = const Duration(seconds: 8), | ||
| }) async { | ||
| if (_rateLimitGate.isActive) await _rateLimitGate.wait(); |
There was a problem hiding this comment.
Include gate waits in the query timeout
When the rate-limit gate is already active, this await occurs before the HTTP client's timeout starts; the gate lasts 10 seconds by default and accepts hints up to 300 seconds. The channel startup path computes an eight-second remaining budget and passes it to queryRelay, so after a 429 or a WebSocket request that arms the gate, Conversations can remain loading for the gate duration plus another eight seconds rather than honoring the advertised total startup deadline. Include the gate wait in the timeout budget or make the caller's deadline cancel the entire operation.
Useful? React with 👍 / 👎.
| } catch (error) { | ||
| if (error is _StaleChannelRefresh) rethrow; | ||
| debugPrint('[ChannelsNotifier] last-message batch failed: $error'); |
There was a problem hiding this comment.
Recover timestamps when a latest-message batch fails
When /query returns an error or times out for a batch, this path only logs and discards it. The replaced _fetchLastMessageEvents path used _fetchChannelHistoryBatch, whose bounded WebSocket fallback recovered those timestamps; the new live subscriptions request limit: 0, and _backstopRefresh explicitly disables fetchLastMessage, so an inactive channel's lastMessageAt remains null until a new live event arrives. That leaves activity-sorted channel lists incorrectly ordered and prevents timestamp-based “Mark read” behavior for the affected channels.
Useful? React with 👍 / 👎.
| const channelQueryBatchSize = 100; | ||
| const liveSubscriptionMaxConcurrent = 4; | ||
| const liveSubscriptionStartInterval = Duration(milliseconds: 125); | ||
|
|
||
| typedef TaskDelay = Future<void> Function(Duration duration); |
There was a problem hiding this comment.
Document or privatize the new channel-sync API
The new top-level constants and TaskDelay typedef are public declarations without doc comments; chunkChannelQueryItems and defaultTaskDelay are also exposed without documentation. Either make these implementation/test helpers private or add documentation for every public declaration as required by the repository contributor guide.
AGENTS.md reference: AGENTS.md:L147-L150
Useful? React with 👍 / 👎.
What changed?
Mobile startup now chunks latest-message and unread catch-up queries at 100, retries relay subscription-capacity errors without arming the rate-limit gate, and admits live subscriptions through one globally serialized 125 ms pacer with at most four active readiness waits. Readiness remains cancellable and bounded when a relay never sends EOSE.
Channel refreshes preserve newer live timestamps only within the same relay-and-identity scope, preventing cached state from crossing community or account boundaries.
Why?
This reduces startup subscription pressure while preserving relay pacing, recovery, and tenant-isolation guarantees.
How is it tested?
Build and run.
Added tests: