Files
yaak-mountain-loop/crates/yaak-git/polling.ts
T
Gregory SchierandClaude Opus 5 a939f2ac55 fix(git): stop polling a sync directory that is not a git repository
A workspace whose sync directory points at a plain folder still ran the whole
git polling loop. `useGitFetchAll` was unconditional, and `cmd_git_fetch_all`
shells out twice — once to probe `git --version`, once for the fetch itself —
so every window focus spawned two processes to be told

    fatal: not a git repository (or any of the parent directories): .git

`cmd_git_branch_info` failed alongside it, and neither backed off, so the
failures repeated for as long as the workspace stayed open. Reported by a user
whose console was full of both errors.

Branch info (or status, in the dialogs) is now the repository probe, and the
fetch only runs once that probe has succeeded. A non-repository sync directory
therefore costs one libgit2 lookup rather than a pair of subprocesses. Since
branch info is no longer keyed on the fetch timestamp, a completed fetch
invalidates what it invalidates instead — which also stops the branch-info cache
growing an entry per fetch.

Failed git queries now pace themselves: `shouldRetryAfterFailure` holds a query
back for 30s after its first failure and doubles that per consecutive failure up
to ten minutes. That predicate drives `refetchOnWindowFocus` and `retryOnMount`
both: a probe that has never succeeded has no data, so `refetchOnMount` never
gets consulted (`shouldLoadOnMount` in query-core short-circuits on
`state.data === undefined`), and without `retryOnMount` reopening the commit or
remotes dialog on a non-repository re-ran the failed probe immediately.

Any git mutation still invalidates the whole `["git"]` key, so an actual
`git init` takes effect straight away.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 17:01:52 -07:00

22 lines
740 B
TypeScript

/**
* When a git query that failed is allowed to run again.
*
* Nothing here retries on its own; the git queries are polled by window focus and by a
* long interval. The failures worth pacing are the ones that do not clear up on their
* own — a sync directory that is not a repository, a repository that was deleted — where
* every focus event would otherwise re-run the same doomed command.
*/
const RETRY_BASE_MS = 30_000;
const RETRY_MAX_MS = 10 * 60_000;
export function shouldRetryAfterFailure(
failureCount: number,
erroredAt: number,
now: number,
): boolean {
if (failureCount <= 0) return true;
const wait = Math.min(RETRY_BASE_MS * 2 ** (failureCount - 1), RETRY_MAX_MS);
return now - erroredAt >= wait;
}