perf(desktop): move observer-feed archive and decrypt commands off main thread - #3415
Merged
Merged
Conversation
…in thread In Tauri 2 a sync command body runs on the main thread; only async commands run on the runtime pool. The observer-feed open path invoked five sync commands, so opening the panel ran up to ten SQLite page reads plus one Schnorr verify + NIP-44 decrypt per frame on the macOS main thread, which beachballs the app — worst on the first open after history accumulates, when the one-shot backfill reads every unindexed row. Routes the four archive commands through the existing run_archive_db_task helper and wraps decrypt_observer_event in spawn_blocking, matching the pattern established for the crypto commands in #1222. Wall time for eager hydration is unchanged; the UI now shows a loading state instead of freezing. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wesbillman
approved these changes
Jul 28, 2026
wesbillman
added a commit
that referenced
this pull request
Jul 29, 2026
## Buzz Desktop release v0.5.1 ### Changes since v0.5.0: - perf(desktop): move observer-feed archive and decrypt commands off main thread ([#3415](#3415)) ([`294c8c821`](294c8c8)) - fix(desktop): preserve shared agent fidelity ([#3553](#3553)) ([`f7a3988ba`](f7a3988)) - feat(agent): route Claude/GPT model families to their native gateway wire ([#3538](#3538)) ([`6438dedf8`](6438ded)) - Refine community invite limits ([#3529](#3529)) ([`24d90d128`](24d90d1)) - feat(agent): fix Anthropic prompt caching with Databricks (+ MCP proxy/TLS passthrough) ([#3463](#3463)) ([`c405ad1d4`](c405ad1)) - feat: add explicit entry for claude-opus-5 in model config ([#2831](#2831)) ([`90e058ebf`](90e058e)) - fix(desktop): clear stale thread new-message pill ([#3411](#3411)) ([`55a3ed7b9`](55a3ed7)) - fix(ci): ratchet file sizes against the base tree ([#3352](#3352)) ([`9227bdf58`](9227bdf)) - feat(desktop): apply WebKit rendering workarounds at startup on Linux ([#3271](#3271)) ([`3ece4461d`](3ece446)) - fix(desktop): stabilize flaky DM expansion E2E ordering assertions ([#2004](#2004)) ([`913d564ce`](913d564)) - fix(desktop): paint community rail full height ([#3382](#3382)) ([`1d3b810ad`](1d3b810)) - feat(desktop): add custom harness inline from agent dialogs ([#3252](#3252)) ([`b0503d80c`](b0503d8)) - feat(desktop): refine agent catalog sharing ([#2439](#2439)) ([`a35771fc4`](a35771f)) - fix(desktop): keep drafts out of the Inbox All view ([#3217](#3217)) ([`3afa129ee`](3afa129)) - fix(desktop): restore the inbox icon in the sidebar ([#3341](#3341)) ([`00ede2e7a`](00ede2e)) - fix(desktop): gate codex-acp on a minimum supported version ([#3254](#3254)) ([`4e3998f36`](4e3998f)) - feat(cli): add users set-status command for NIP-38 profile status ([#3253](#3253)) ([`60158fce3`](60158fc)) - fix(composer): scope multiline block formatting ([#3246](#3246)) ([`5457c947a`](5457c94)) **To release:** merge this PR. The tag and build will happen automatically. Signed-off-by: Wes <wesbillman@users.noreply.github.com>
joahg
added a commit
to joahg/buzz
that referenced
this pull request
Jul 29, 2026
…-style * origin/main: chore(release): release Buzz Desktop version 0.5.1 (block#3566) Run Tauri clippy in pre-push (block#3555) perf(desktop): move observer-feed archive and decrypt commands off main thread (block#3415) fix(desktop): preserve shared agent fidelity (block#3553) Polish mobile navigation and menus (block#3486) feat(agent): route Claude/GPT model families to their native gateway wire (block#3538) Refine community invite limits (block#3529) Polish mobile typing indicator (block#3528) Signed-off-by: Joah Gerstenberg <joah@squareup.com>
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.
Opening the agent observer feed could beachball the app. In Tauri 2, a sync (
pub fn) command body runs on the main thread — onlyasync fncommands run on the runtime pool. Five commands on the observer-feed open path were sync, so panel open ran SQLite I/O and secp256k1 work on the macOS main thread:decrypt_observer_eventread_archived_observer_events_for_channelread_unindexed_observer_rowsindex_observer_channel_iddelete_save_subscriptionEager hydration loads up to 10 pages × 200 frames on panel open, so that's up to 10 main-thread DB reads plus up to 2,000 sequential verify+decrypt calls before any scrolling. The one-shot backfill makes it worse on the first open after history accumulates: one read of every unindexed row, a decrypt per row, then a batch upsert — all on the main thread, and all proportional to archive size.
The four archive commands now route their DB work through the existing
run_archive_db_taskhelper (spawn_blocking+open_db), matchinglist_save_subscriptions,read_archived_events, andarchive_eventsdirectly around them.decrypt_observer_eventbecomesasync fn+tauri::async_runtime::spawn_blocking, withstate.signing_keys()extracted before the spawn sinceStateis notSend— the same patternsign_eventuses from #1222.No frontend changes:
invokeis already promise-based, so the TS wrappers intauriArchive.tsandtauriObserver.tsare unchanged.This removes the freeze, not the work. Eager hydration still takes the same wall time — the feed shows a loading state instead of blocking the UI. Batching the per-frame decrypt IPC (2,000 round-trips into one command) would cut the latency itself; that's deliberately out of scope here.