feat(workspace): WorktreeService with acquire/release state machine

This commit is contained in:
2026-05-02 08:03:30 +08:00
parent bd91880898
commit d76ed67666
6 changed files with 325 additions and 0 deletions
+14
View File
@@ -23,6 +23,9 @@ import (
// 状态转移方法,不直接操作 pgx.Tx。
type Tx interface {
GetWorktreeForUpdate(ctx context.Context, wsID uuid.UUID, branch string) (*Worktree, error)
// GetWorktreeByIDForUpdate 在事务内对 id 行加 FOR UPDATE — Acquire/Release 必须用它,
// GetWorktreeByID 不带行锁,并发时会 TOCTOU。
GetWorktreeByIDForUpdate(ctx context.Context, id uuid.UUID) (*Worktree, error)
GetWorktreeByID(ctx context.Context, id uuid.UUID) (*Worktree, error)
InsertWorktree(ctx context.Context, w *Worktree) (*Worktree, error)
SetWorktreeActive(ctx context.Context, id uuid.UUID, holder string) (*Worktree, error)
@@ -355,6 +358,17 @@ func (t *pgTx) GetWorktreeByID(ctx context.Context, id uuid.UUID) (*Worktree, er
return rowToWorktree(row), nil
}
func (t *pgTx) GetWorktreeByIDForUpdate(ctx context.Context, id uuid.UUID) (*Worktree, error) {
row, err := t.q.GetWorktreeByIDForUpdate(ctx, toPgUUID(id))
if errors.Is(err, pgx.ErrNoRows) {
return nil, errs.New(errs.CodeNotFound, "worktree not found")
}
if err != nil {
return nil, errs.Wrap(err, errs.CodeInternal, "select for update")
}
return rowToWorktree(row), nil
}
func (t *pgTx) InsertWorktree(ctx context.Context, w *Worktree) (*Worktree, error) {
row, err := t.q.CreateWorktree(ctx, workspacesqlc.CreateWorktreeParams{
ID: toPgUUID(w.ID),