Repository navigation
Let an idle desktop app's saving helper exit - #2466
Merged
Merged
Conversation
The desktop engine sent a health request to its furrow helpers every 20 s for as long as it ran, which reset furrow's one-minute idle clock, so the helper never exited and kept waking about 28 times a second on an idle app. Touch the helpers only while there is saving work: a chat turn running (SealWatch start/end), held calls or a running capture, or a seal still owing its engine sync. An idle app sends nothing; the helper exits through its own idle path and the next save starts it again through Daemon.Do. Touches stay dial-only, so they never start or restart a helper. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AbirAbbas
force-pushed
the
perf/furrow-idle-exit
branch
from
November 6, 2026 16:42
ca47814 to
94ab8a8
Compare
This was referenced Nov 6, 2026
Open
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.
Problem
The desktop engine sends a health request to the
furrow servehelpers it started every 20 seconds for as long as it runs (internal/cellstore/daemon_app.go, added in #2226). Each request resets furrow's one-minute idle clock, so the helper never exits, even on an idle app. While it is alive, furrow wakes about 28 times a second: a 50 ms accept poll plus two 250 ms writer and group-commit waits per open store. On a Mac test app,furrow-0.3.6 serveran at 28 wakeups/s after a turn ended and stayed alive indefinitely.Fix
The 20-second touch now runs only while the app has saving work:
SealWatch.TurnStartedandTurnEnded;sync.An idle app sends nothing. Its helper exits through furrow's own one-minute idle path and stops waking. Touches still only dial, so they never start or restart a helper. Terminal and command-line helper lifetimes are unchanged.
Why this is safe
A stopped helper costs only latency, not a save. This was already the documented contract (
daemonstart.go: "the value costs latency, never correctness"):Daemon.Docallsconnect, which dials and, if nothing listens, callsstartAndDial. That startsfurrow serveand waits up to 5 s for it to listen.Fallbackthen retries seal and sync once through the daemon, which starts a new helper. Other verbs spawn the engine directly.Remaining cost: the first save after an idle period starts the helper again. Furrow's own maintenance (index check and abandoned-plan pruning) runs only in a helper that is at least an hour old, so in the app it now runs less often, as it already did for terminal helpers.
Measurements
furrow-0.3.6 serveon a fresh socket to its first health reply: 4.0 ms median, 4.2 ms max over 10 runs (darwin/arm64).ls -lain the work folder, then 3 min sampled every 5 s.furrow servestarted 6.9 s after send for the end-of-turn save. The turn log has its seal entries at turn end and +2.8 s, the same as with a warm helper. No seal error, failure or warning lines in the home's logs.Tests
TestAppTouchesHelpersOnlyForSavingWorkuses a stub helper on a test socket. It checks that an idle app sends no health requests and that a running turn, held calls, a running capture or a seal still waiting for its sync send exactly one. It also checks that a failed finished capture or an exited helper gets none. It passes 20 runs in a row, with and without-race.TestDesktopIdleAppLetsHelperExitchecks that an idle app's helper exits by its idle limit and that the next request starts a new one.go vet ./internal/cellstore(darwin, linux, windows),gofmt, the SealWatch tests, andgo test -short ./internal/cellstore -count=1pass on macOS.The manual section "Desktop app quit and saving helpers" is updated to match.
🤖 Generated with Claude Code