Skip to content

perf(desktop): stop the Projects fan refetching on re-entry and running after leave - #6458

Merged
wesbillman merged 2 commits into
mainfrom
perf/projects-fan-lifecycle
Aug 21, 2026
Merged

perf(desktop): stop the Projects fan refetching on re-entry and running after leave#6458
wesbillman merged 2 commits into
mainfrom
perf/projects-fan-lifecycle

Conversation

@Maxwellimus

Copy link
Copy Markdown
Contributor

Entering Projects fires a large fan: an exhaustive paginated relay enumeration (projects/repos/tombstones), five 2,000-event work-item queries plus assignment-operation scans, per-repo activity summaries, and a local-repository filesystem scan. Measured on a large community (101 issues / 258 PRs):

query measured cost
work-items (5 × 2,000-event REQs + assignment scans) 3.5–3.9s
activity summaries 4.1s
repository activity 1.0–2.2s
local repository scan 1.7s

Two lifecycle bugs made the fan far more expensive than it needs to be:

  • Freshness windows guaranteed a full refetch on nearly every re-entry (60s enumeration, 30s work-items/activity, 10s local scan) — i.e., the costs above were re-paid on almost every visit. Every local write path already invalidates its keys explicitly (issue/PR mutations, project creation, repo sync), so the short windows only served remote-actor freshness. Raised to 5m/2m/2m with a 30m enumeration cache: re-entries now paint from cache, and the fan re-runs at most every 2–5 minutes.
  • Leaving Projects left the whole fan running, competing with the next surface's channel fetches on the same relay connection. AbortSignal is now threaded through the enumeration and assignment pagination loops (optional params — behavior identical without a signal), and leaving the surface cancels the work-items query. Deliberately NOT cancelled: the enumeration (the always-mounted sidebar projects section observes it and its 30m cache is valuable), repo snapshots and local scans (native work that can't abort — cancelling would discard the finished result and force the same clones again), and activity summaries (a single bounded request).

Abort behavior is covered by red-first unit tests on both pagination loops. Remaining follow-up (out of scope): the queries themselves want a relay-side aggregate instead of shipping thousands of events to compute counts client-side.

@Maxwellimus
Maxwellimus force-pushed the perf/projects-fan-lifecycle branch from 54b8b0d to 77cac8a Compare August 21, 2026 05:48
Project enumeration is an exhaustive paginated relay scan and the
work-items fan is five 2,000-event queries, yet their freshness windows
(60s/30s, 10s for the local-repo filesystem scan) guaranteed a full
refetch on nearly every Projects re-entry. Every local write path
already invalidates its keys explicitly (issue/PR mutations, project
creation, repo sync), so the short windows only served remote-actor
freshness. Raise them (5m enumeration, 2m work items/activity/local
repos) and keep the enumeration cached for 30m so re-entering Projects
paints from cache instead of blocking on the scan.

Signed-off-by: Max Lampert <maxwell@squareup.com>
@Maxwellimus
Maxwellimus force-pushed the perf/projects-fan-lifecycle branch from 77cac8a to 6e2809c Compare August 21, 2026 18:32
Leaving Projects used to leave the whole fan running: the project
enumeration paginates the relay exhaustively, work items are five
2,000-event queries plus assignment-operation scans, and all of it
competed with the next surface's channel fetches over the same relay
connection.

Thread AbortSignal through the enumeration and assignment pagination
loops (additive optional params; behavior is unchanged without a
signal) and cancel the fan's queries when ProjectsScreen unmounts.
Cancellation only discards in-flight requests — cached data stays and
the next visit refetches per staleTime. The enumeration key is shared
with the project-detail screen, so it is cancelled only when no other
observer holds it.

Signed-off-by: Max Lampert <maxwell@squareup.com>
@Maxwellimus
Maxwellimus force-pushed the perf/projects-fan-lifecycle branch from 6e2809c to 0f83238 Compare August 21, 2026 19:38
@Maxwellimus

Copy link
Copy Markdown
Contributor Author

🤖 Comment from Maxwell's AI agent.

Adversarial-review findings addressed in the latest push:

  • Reconnect auto-heal can now repair partial work-items results: work-items added to RELAY_PROJECT_QUERY_PARTS in relayQueryInvalidation.ts (with test). Previously a partial fan-out result could sit "fresh" for the full two-minute window after a relay hiccup.
  • Cache key now includes repository addresses: attach/detach-repository flows change the fan-out inputs without changing project ids; keying on addresses prevents a pre-attach result from serving as fresh.
  • Abort check after the eager fan-out (projectWorkItems.ts): skips the reduce work and avoids caching a result for a surface the user already left.

Tracked follow-up (deferred): the five eager 2,000-event queries are single bounded REQs that relayClient.fetchEvents cannot abort mid-flight — only the assignment pagination is abort-aware. Making individual REQs cancellable needs abort support in the relay client itself; out of scope for this PR.

@Maxwellimus
Maxwellimus marked this pull request as ready for review August 21, 2026 21:22
@Maxwellimus
Maxwellimus requested a review from a team as a code owner August 21, 2026 21:22
@Maxwellimus
Maxwellimus requested a review from wesbillman August 21, 2026 21:22

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carl, an automated reviewer, commenting via Wes’s GitHub account.

Reviewed exact head 0f832387d7adc8bf7b9cae84e2029973793e6c51 against GitHub-stated base aeb741fd31044ec560d953b0986dec2e7e93e2c6 (merge base 24ec6a468ec9d0d425ee58fbfc4d416412c446ad). No blocking lifecycle or cache defect found. Overview leave cancels the work-item prefix without killing the sidebar-owned project enumeration, cancellation preserves prior cache and remains cooperative at pagination boundaries, repository-address keying closes attach/detach reuse, and reconnect invalidation covers work items. Focused abort/enumeration/reconnect validation passed 22/22; exact-head CI is green and the diff check was clean.

@wesbillman
wesbillman merged commit b85d680 into main Aug 21, 2026
24 checks passed
@wesbillman
wesbillman deleted the perf/projects-fan-lifecycle branch August 21, 2026 23:40
brow added a commit that referenced this pull request Aug 22, 2026
* origin/main: (65 commits)
  fix(composer): preserve caret when inserting mentions mid-message (#6531)
  chore(deps): update rust crate async-trait to v0.1.92 (#6094)
  chore(deps): update dependency sonner to v2.0.8 (#6093)
  chore(deps): update rust crate http-body-util to v0.1.4 (#5452)
  chore(deps): update rust crate http to v1.4.2 (#5451)
  chore(deps): update rust crate futures-util to v0.3.33 (#5448)
  chore(deps): update rust crate futures to v0.3.33 (#5445)
  chore(deps): update dependency @tauri-apps/api to v2.11.1 (#5444)
  chore(deps): update ubuntu:24.04 docker digest to 561618e (#5442)
  chore(deps): update swatinem/rust-cache digest to 6323deb (#5441)
  fix(desktop): restore true zoom by scaling the root rem (#6514)
  chore(desktop): drop unused ORIGINAL_CONTENT from empty-edit-delete spec (#6517)
  feat(workflows): clarify workflow setup and activation (#6470)
  perf(desktop): stop the Projects fan refetching on re-entry and running after leave (#6458)
  perf(desktop): keep the member roster off the channel-switch path (#6456)
  fix(deletion): allow IRSA S3 credentials (#6495)
  docs(nips): comprehensive NIP-FI — core + claimable profiles (EDGE/LIFECYCLE/DELEG/CONF) (#5946)
  fix(benchmarks): wait for scripted event delivery (#6487)
  Polish mobile channel navigation and message sends (#6488)
  Clarify huddle message destination (#6496)
  ...

Signed-off-by: leader <71e9f2c44a6932b6772caaaccda1911d010463c3e2c6c40410b8329956046801@buzz.block.builderlab.xyz>

Co-authored-by: Tom Brow <tomb@block.xyz>
Signed-off-by: Tom Brow <tomb@block.xyz>
brow added a commit that referenced this pull request Aug 22, 2026
…ifications-pr

* origin/main: (38 commits)
  fix(composer): preserve caret when inserting mentions mid-message (#6531)
  chore(deps): update rust crate async-trait to v0.1.92 (#6094)
  chore(deps): update dependency sonner to v2.0.8 (#6093)
  chore(deps): update rust crate http-body-util to v0.1.4 (#5452)
  chore(deps): update rust crate http to v1.4.2 (#5451)
  chore(deps): update rust crate futures-util to v0.3.33 (#5448)
  chore(deps): update rust crate futures to v0.3.33 (#5445)
  chore(deps): update dependency @tauri-apps/api to v2.11.1 (#5444)
  chore(deps): update ubuntu:24.04 docker digest to 561618e (#5442)
  chore(deps): update swatinem/rust-cache digest to 6323deb (#5441)
  fix(desktop): restore true zoom by scaling the root rem (#6514)
  chore(desktop): drop unused ORIGINAL_CONTENT from empty-edit-delete spec (#6517)
  feat(workflows): clarify workflow setup and activation (#6470)
  perf(desktop): stop the Projects fan refetching on re-entry and running after leave (#6458)
  perf(desktop): keep the member roster off the channel-switch path (#6456)
  fix(deletion): allow IRSA S3 credentials (#6495)
  docs(nips): comprehensive NIP-FI — core + claimable profiles (EDGE/LIFECYCLE/DELEG/CONF) (#5946)
  fix(benchmarks): wait for scripted event delivery (#6487)
  Polish mobile channel navigation and message sends (#6488)
  Clarify huddle message destination (#6496)
  ...

Signed-off-by: Tom Brow <tomb@block.xyz>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants