fix(tools): add spawnSync timeout to local git calls #44

Closed
opened 2026-08-11 16:08:59 +03:00 by slaid098 · 0 comments
Owner

Контекст

PR#41 (issue #40) добавил timeout: 5000 к resolveForgejoRepo spawnSync("git", ...) в _shared.ts:49. Но другие spawnSync("git", ...) вызовы в TS-тулах — без timeout. Локальный git обычно быстрый, но git pull на медленном remote, git checkout на FUSE/NFS, или git commit с большим diff могут hang'ать.

Проблемные call sites:

  • merge-pr.ts:61,67,71,78,79,96 — git() helper (6 вызовов: branch --list, rev-parse, checkout, pull, branch -D) без timeout.
  • create-pr.ts:62 — spawnSync("git rev-parse --abbrev-ref HEAD") без timeout.
  • commit.ts:16,42,53 — spawnSync("git", ...) (log, diff --cached, commit) без timeout.

Задача

  1. merge-pr.ts — git() helper (строки 5-7, используется на 61,67,71,78,79,96): добавить timeout: 10000 (10с) к spawnSync options.
  2. create-pr.ts:62 — spawnSync("git rev-parse --abbrev-ref HEAD"): добавить timeout: 5000 (5с, быстрая операция).
  3. commit.ts:16,42,53 — spawnSync("git", ...) (log, diff --cached, commit): добавить timeout: 10000 (10с). git commit может быть медленным с pre-commit hooks.
  4. При timeout spawnSync возвращает signal: 'SIGTERM' — обработать: вернуть читаемую ошибку [git] <cmd> timed out after Nms вместо пустого stdout.

Контракты

  • spawnSync(cmd, args, { encoding: "utf-8", timeout: N }) — Node/Bun spawnSync поддерживает timeout опцию.
  • При timeout: result.signal === 'SIGTERM', result.status === null. Нужно проверить result.signal и вернуть ошибку.
  • git() helper в merge-pr.ts — если получает timeout, должна вернуть ошибку (не throw — merge-pr должен graceful-fail с сообщением).
  • commit.ts — git commit с pre-commit hooks может занять >10с. Рассмотреть 30с для commit. Но git log/git diff --cached — 10с достаточно.

Инварианты

  • Существующие вызовы продолжают работать (добавляется только timeout option).
  • git pull (merge-pr.ts:78) — 10с может быть tight на медленном remote. Но git pull на origin (local network / Forgejo) обычно <5с. Если tight — оставить 10с + retry на уровне выше.
  • git commit с hooks — 10с может быть tight. Рассмотреть 30с для commit specifically.

Граничные случаи

  • git pull на медленном remote (Forgejo за Nginx, медленный response) — 10с timeout, затем merge-pr fails с читаемой ошибкой. Агент может retry.
  • git commit с pre-commit hooks (ruff, mypy) — может занять 30-60с на большом репо. 10с слишком мало. Рассмотреть timeout: 30000 для commit.
  • git checkout на FUSE/NFS mount — может hang. 10с timeout спасает.
  • spawnSync timeout убивает процесс SIGTERM — git может оставить .git/index.lock. Нужно упомянуть в ошибке (агент может удалить lock).

Влияние на связанные компоненты

  • merge-pr — все 6 git() вызовов получают timeout. Merge-pr теперь fails fast вместо hang.
  • create-pr — git rev-parse получает timeout.
  • commit — git log/diff/commit получают timeout. Commit с hooks может нуждаться в большем timeout.

Вне scope

  • Python subprocess.run git calls (pipeline-status.py:42,377; spec-status.py:61,159; project-status.py:69,237) — issue Волны 1 (Python oracles).
  • curl в skills — issue Волны 2.
  • Server-side Forgejo — issue #19 в forgejo-infra.
  • resolveForgejoRepo в _shared.ts — уже пофикшен в PR#41 (timeout: 5000).

Критерии приемки

  • merge-pr.ts git() helper имеет timeout: 10000 (все 6 call sites).
  • create-pr.ts:62 spawnSync имеет timeout: 5000.
  • commit.ts:16,42,53 spawnSync имеет timeout: 10000 (или 30000 для commit).
  • При timeout (result.signal === 'SIGTERM') — читаемая ошибка [git] <cmd> timed out after Nms.
  • Существующие вызовы продолжают работать (backward compatible).
  • Тесты (если есть) — зелёные.
## Контекст PR#41 (issue #40) добавил `timeout: 5000` к `resolveForgejoRepo` `spawnSync("git", ...)` в `_shared.ts:49`. Но другие `spawnSync("git", ...)` вызовы в TS-тулах — без timeout. Локальный git обычно быстрый, но `git pull` на медленном remote, `git checkout` на FUSE/NFS, или `git commit` с большим diff могут hang'ать. Проблемные call sites: - `merge-pr.ts:61,67,71,78,79,96` — `git()` helper (6 вызовов: branch --list, rev-parse, checkout, pull, branch -D) без timeout. - `create-pr.ts:62` — `spawnSync("git rev-parse --abbrev-ref HEAD")` без timeout. - `commit.ts:16,42,53` — `spawnSync("git", ...)` (log, diff --cached, commit) без timeout. ## Задача 1. `merge-pr.ts` — `git()` helper (строки 5-7, используется на 61,67,71,78,79,96): добавить `timeout: 10000` (10с) к `spawnSync` options. 2. `create-pr.ts:62` — `spawnSync("git rev-parse --abbrev-ref HEAD")`: добавить `timeout: 5000` (5с, быстрая операция). 3. `commit.ts:16,42,53` — `spawnSync("git", ...)` (log, diff --cached, commit): добавить `timeout: 10000` (10с). `git commit` может быть медленным с pre-commit hooks. 4. При timeout `spawnSync` возвращает `signal: 'SIGTERM'` — обработать: вернуть читаемую ошибку `[git] <cmd> timed out after Nms` вместо пустого stdout. ## Контракты - `spawnSync(cmd, args, { encoding: "utf-8", timeout: N })` — Node/Bun spawnSync поддерживает `timeout` опцию. - При timeout: `result.signal === 'SIGTERM'`, `result.status === null`. Нужно проверить `result.signal` и вернуть ошибку. - `git()` helper в `merge-pr.ts` — если получает timeout, должна вернуть ошибку (не throw — merge-pr должен graceful-fail с сообщением). - `commit.ts` — `git commit` с pre-commit hooks может занять >10с. Рассмотреть 30с для commit. Но `git log`/`git diff --cached` — 10с достаточно. ## Инварианты - Существующие вызовы продолжают работать (добавляется только `timeout` option). - `git pull` (`merge-pr.ts:78`) — 10с может быть tight на медленном remote. Но `git pull` на origin (local network / Forgejo) обычно <5с. Если tight — оставить 10с + retry на уровне выше. - `git commit` с hooks — 10с может быть tight. Рассмотреть 30с для commit specifically. ## Граничные случаи - `git pull` на медленном remote (Forgejo за Nginx, медленный response) — 10с timeout, затем merge-pr fails с читаемой ошибкой. Агент может retry. - `git commit` с pre-commit hooks (ruff, mypy) — может занять 30-60с на большом репо. 10с слишком мало. Рассмотреть `timeout: 30000` для commit. - `git checkout` на FUSE/NFS mount — может hang. 10с timeout спасает. - `spawnSync` timeout убивает процесс SIGTERM — git может оставить `.git/index.lock`. Нужно упомянуть в ошибке (агент может удалить lock). ## Влияние на связанные компоненты - `merge-pr` — все 6 git() вызовов получают timeout. Merge-pr теперь fails fast вместо hang. - `create-pr` — git rev-parse получает timeout. - `commit` — git log/diff/commit получают timeout. Commit с hooks может нуждаться в большем timeout. ## Вне scope - Python `subprocess.run` git calls (pipeline-status.py:42,377; spec-status.py:61,159; project-status.py:69,237) — issue Волны 1 (Python oracles). - curl в skills — issue Волны 2. - Server-side Forgejo — issue #19 в forgejo-infra. - `resolveForgejoRepo` в `_shared.ts` — уже пофикшен в PR#41 (timeout: 5000). ## Критерии приемки - [ ] `merge-pr.ts` `git()` helper имеет `timeout: 10000` (все 6 call sites). - [ ] `create-pr.ts:62` `spawnSync` имеет `timeout: 5000`. - [ ] `commit.ts:16,42,53` `spawnSync` имеет `timeout: 10000` (или 30000 для commit). - [ ] При timeout (`result.signal === 'SIGTERM'`) — читаемая ошибка `[git] <cmd> timed out after Nms`. - [ ] Существующие вызовы продолжают работать (backward compatible). - [ ] Тесты (если есть) — зелёные.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
slaid098/opencode-config#44
No description provided.