AutoplayLeaseTrait
{@see \NHA\StateStore} slice: the single-driver lease for the autoplay loop.
bot.php's in-process loop and the standalone autoplay.php runner both use
AutoPlayer; the lease stops them submitting two intents per
interval from one token.
Relies on the host's array $data, save() and string $path.
Tags
Table of Contents
Methods
- acquireAutoplayLease() : bool
- Takes (or renews) the autoplay driver lease for `$holder`.
- autoplayLeaseHolder() : string|null
- The id of the process currently holding a live autoplay lease, or null.
- leaseTtlForInterval() : int
- The lease TTL for a given autoplay interval: three intervals, floored at 45 seconds. A fixed TTL shorter than the interval expires in the gap between turns, so lease ownership ping-pongs between the two runners (harmless flapping, but noisy). Deriving it from the interval keeps the lease alive across the quiet stretch.
- releaseAutoplayLease() : void
- Drops the lease if `$holder` currently holds it (call on clean shutdown).
- withLeaseLock() : T
- Runs `$fn` while holding an exclusive OS lock on a sibling `.lease.lock` file, with `$this->data` first re-read from disk so `$fn` sees the lease exactly as other processes last left it — and, on {@see save()}, does not clobber unrelated keys another process wrote in the meantime.
Methods
acquireAutoplayLease()
Takes (or renews) the autoplay driver lease for `$holder`.
public
acquireAutoplayLease(string $holder[, int|null $interval = null ]) : bool
Only one process should drive an agent's autoplay loop at a time. Each loop passes a stable per-process holder id; the first to acquire the lease drives, the others skip their turn until it expires (a crashed driver frees it within the TTL).
The acquire/release is done under an exclusive OS lock (see withLeaseLock()), so two runners starting at the same instant cannot both observe "no lease" and both claim it — it is a real compare-and-swap, not just an atomic file write.
Parameters
- $holder : string
-
A stable id for the calling loop, e.g.
"bot.php:1234". - $interval : int|null = null
-
The loop's turn interval in seconds. The lease TTL is derived from it (leaseTtlForInterval()) so the lease outlives the gap between turns; null → the 45s floor.
Return values
bool —True when $holder now holds the lease (it was free, expired,
or already theirs); false when another holder's lease is live.
autoplayLeaseHolder()
The id of the process currently holding a live autoplay lease, or null.
public
autoplayLeaseHolder() : string|null
Return values
string|nullleaseTtlForInterval()
The lease TTL for a given autoplay interval: three intervals, floored at 45 seconds. A fixed TTL shorter than the interval expires in the gap between turns, so lease ownership ping-pongs between the two runners (harmless flapping, but noisy). Deriving it from the interval keeps the lease alive across the quiet stretch.
public
static leaseTtlForInterval(int|null $interval) : int
Parameters
- $interval : int|null
Return values
intreleaseAutoplayLease()
Drops the lease if `$holder` currently holds it (call on clean shutdown).
public
releaseAutoplayLease(string $holder) : void
Parameters
- $holder : string
withLeaseLock()
Runs `$fn` while holding an exclusive OS lock on a sibling `.lease.lock` file, with `$this->data` first re-read from disk so `$fn` sees the lease exactly as other processes last left it — and, on {@see save()}, does not clobber unrelated keys another process wrote in the meantime.
private
withLeaseLock(callable(): T $fn) : T
The re-read is only adopted when it decodes to a non-empty array. An empty
or truncated state file (full disk, interrupted first write, a hand-edit)
would otherwise become [], and the next save() would persist a
file holding nothing but the lease — dropping the agent token, which the
NHA server issues exactly once. A stale in-memory read is the safe failure.
Degrades to running $fn unlocked (the old best-effort read-modify-write)
when the lock file can't be opened: a rare doubled interval beats a loop
that never drives.
Parameters
- $fn : callable(): T