runlock

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Jul 21, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package runlock is the sidecar run-liveness lock: an exclusive BSD flock(2) held by `awf run` / `awf resume` for a run's lifetime, plus a non-blocking shared probe (Held) that distinguishes a live run (lock held) from a crashed one (lock free).

It is NOT durable state — a missing or stale run.lock can never corrupt resume or the content-addressed artifacts — so the "interpreter is the only writer to state" invariant is untouched. The kernel releases the lock on ANY termination (clean exit, crash, SIGKILL), which is what makes the probe meaningful. Go opens files O_CLOEXEC, so child processes (the agent CLI, docker) never inherit the fd and cannot keep the lock alive after the runner dies. Single-host / no-NFS precondition (over NFS flock degrades to fcntl byte-range locks).

This package is the single owner of the lock-file convention; cli (the runner) and ui (a read-only liveness prober) both depend on it.

Index

Constants

This section is empty.

Variables

View Source
var ErrHeld = errors.New("run is already active (lock held by a live process)")

ErrHeld means another live process already holds the run lock — the run is currently being driven elsewhere. `awf run` / `awf resume` refuse on this.

Functions

func Held

func Held(runDir string) (bool, error)

Held reports whether a live process holds <runDir>/run.lock. It attempts a non-blocking SHARED flock: EWOULDBLOCK ⇒ a live EXCLUSIVE holder (the run process) ⇒ running; success ⇒ no holder (the shared lock is immediately released). A missing lock file reports not-held. Callers use this to split the "started, no terminal event" bucket into running (held) vs crashed (not held).

LOCK_SH (NOT LOCK_EX) is load-bearing: a shared probe conflicts with the writer's LOCK_EX (→ correctly "held") but NOT with other shared probers, so two concurrent probers never false-positive each other as a live run.

Types

type Lock

type Lock struct {
	// contains filtered or unexported fields
}

Lock is a held exclusive advisory lock. The holder keeps the fd open for the run's lifetime; Release drops it on clean exit and the kernel drops it on any abnormal exit.

func Acquire

func Acquire(runDir string) (*Lock, error)

Acquire opens (creating if absent) <runDir>/run.lock and takes a non-blocking exclusive flock. Returns ErrHeld if a live holder exists.

func (*Lock) Release

func (l *Lock) Release()

Release drops the advisory lock and closes the fd. Best-effort: the kernel also releases on process exit, so a Release error is not actionable. A double Release is a no-op.

Jump to

Keyboard shortcuts

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