Skip to content

fix(watch): single-instance lock to prevent duplicate daemons#8

Merged
akihidem merged 1 commit into
mainfrom
fix/watch-singleton-lock
Jun 9, 2026
Merged

fix(watch): single-instance lock to prevent duplicate daemons#8
akihidem merged 1 commit into
mainfrom
fix/watch-singleton-lock

Conversation

@akihidem

@akihidem akihidem commented Jun 9, 2026

Copy link
Copy Markdown
Owner

なぜ

cogsync watch に多重起動ガードが無く(本体に flock/pidfile/O_EXCL 不在を確認)、複数 tmux shell + bashrc autostart の素朴な pgrep ガードはレースで重複起動する。結果 deepwork が二重計上され通知も重複する。起動方法に依らず単一インスタンスにするため watch 本体でロックを取る。

何を

  • src/util/singleton-lock.ts(新規): acquireSingleInstanceLock = O_EXCL pidfile(アトミック)+ process.kill(pid,0) 死活判定で stale 回収。release は自 pid のロックのみ削除。
  • src/watch.ts: runWatch 冒頭で <XDG_STATE_HOME or ~/.local/state>/cogsync/watch.lock を取得。取れなければメッセージを出して return。--once 診断は対象外
  • tests/singleton-lock.test.ts: 取得 / 二重 null / stale 回収 / 壊れ pid / release 冪等 / シグナル非干渉 の5件。

設計判断

  • O_EXCL pidfile(外部依存なし・POSIX アトミック)。同時起動でも取得は最大1本。
  • --once はロック対象外: 診断用の1回 poll は daemon 稼働中でも実行できるべき(初回 feed は +0 分で二重計上にならない)。
  • ロックはシグナルを横取りしない: SIGINT/SIGTERM ハンドラを登録すると watch の stop(deepwork 保存)より先に発火し process.exit() で保存を奪う回帰になる。ロックは exit クリーンアップのみに徹し、シグナルは watch に委ねる。← 独立敵対レビューで検出した回帰を修正し回帰テストで pin。

スコープ外

  • pid 再利用の完全防止(boot-id 併記等)。失敗モードは fail-safe(起動拒否)でデータ破壊ではないため許容。
  • 既存 state.json の read-modify-write 競合(lost-update)は本 PR の射程外。

検証方法

  • npm test: 38 pass / 0 fail(既存33+新規5)。tsc --noEmit: 0
  • 実プロセス検証: ①生存 pid ロック保持下で2本目 daemon が即 exit(hang せず)②SIGINT で watch の deepwork 保存が走る③exit でロックファイル削除。
  • 独立敵対レビュー(別エージェント・30〜50 並列ストレス)で SIGINT 保存奪取の回帰を検出 → 修正+回帰テストで pin。

依存

  • なし(新規依存・設定変更なし)。

🤖 Generated with Claude Code

複数 tmux shell + autostart のレースで cogsync watch が多重起動し deepwork を二重計上していた。runWatch 冒頭に O_EXCL pidfile ロックを追加(--once 診断は対象外)。stale な pidfile は process.kill(pid,0) の死活判定で回収。ロックはシグナルを横取りせず exit クリーンアップのみに徹し、watch 終了時の deepwork 保存を奪わない。テスト5件。

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@akihidem akihidem merged commit 4309619 into main Jun 9, 2026
2 checks passed
@akihidem akihidem deleted the fix/watch-singleton-lock branch June 9, 2026 03:08
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.

1 participant