executorlock

package
v0.3.28 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 7, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package executorlock provides a per-task, cross-process "spawn lock" that serializes the check-window-then-start-executor critical section shared by the daemon executor and every ty TUI detail view.

Without it, the daemon and a detail view can each observe "no tmux window yet" and both spawn an executor for the same task — two Claude sessions in one worktree with clobbered pane ids (the "executors mixed up" bug).

This is deliberately distinct from the TUI's long-lived executor *ownership* lock (internal/ui, acquireExecutorLock), which gates borrowing a live pane for the whole life of a detail view. The spawn lock is held only around the spawn decision and released immediately, so it never blocks a TUI from later joining the daemon's live pane.

Index

Constants

This section is empty.

Variables

View Source
var ErrRepoLockTimeout = errors.New("executorlock: timed out waiting for repo worktree lock")

ErrRepoLockTimeout is returned by AcquireRepo when the repository lock could not be taken before the timeout elapsed.

View Source
var ErrSpawnLockTimeout = errors.New("executorlock: timed out waiting for spawn lock")

ErrSpawnLockTimeout is returned by AcquireSpawn when the lock could not be taken before the timeout elapsed (another spawner is holding it).

Functions

func AcquireRepo added in v0.3.22

func AcquireRepo(lockDir, repoPath string, timeout time.Duration) (func(), error)

AcquireRepo takes an exclusive, cross-process lock for a repository, blocking up to timeout, and returns a release func.

`git worktree add` is not safe to run concurrently in the same repository: it writes .git/config (to record the new worktree's upstream) under a lock file of git's own, and the loser does not retry — it fails outright with

error: could not lock config file .git/config: File exists

Nothing serialized this before because nothing could reach it concurrently: steps sharing one branch were forced to run one at a time by git itself. Once a workflow's parallel steps each got their own branch they spawn together, and two `worktree add` calls land in the same repo in the same instant.

func AcquireSpawn

func AcquireSpawn(lockDir string, taskID int64, timeout time.Duration) (func(), error)

AcquireSpawn takes an exclusive, cross-process lock serializing executor spawns for taskID, blocking up to timeout for any concurrent holder to release. It returns a release func that must be called once the spawn decision is made.

lockDir is the directory the lock file lives in — co-locate it with the task DB so isolated instances (custom DB path, e.g. QA harnesses) get their own lock namespace and don't contend with the real daemon.

The lock is tied to the open file description, so it is released automatically if the holding process exits — a crashed spawner never leaves it stuck.

func RepoLockPath added in v0.3.22

func RepoLockPath(lockDir, repoPath string) string

RepoLockPath returns the lock-file path serializing worktree creation in one repository. The repo path is hashed so the file name is filesystem-safe and bounded regardless of how deep the repo lives.

func SpawnLockPath

func SpawnLockPath(lockDir string, taskID int64) string

SpawnLockPath returns the lock-file path for a task's spawn lock in lockDir. Exported so callers can reason about / clean up the file if needed.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL