Resources & Locking
Injectable resources, enqueue gates, distributed locks, and periodic tasks.
Injectable resources, enqueue gates, distributed locks, and periodic tasks.
| Member | Description |
|---|---|
resource(name, factory, opts?) | Register an injectable resource (scope, dispose, reloadable). |
reloadResources(names?) → Promise<Record<string, boolean>> | Hot-reload resources: dispose what is cached, rebuild on next use. No argument sweeps every reloadable: true resource; an unknown name reports false rather than throwing. |
| Member | Description |
|---|---|
intercept(interceptor) | Register an enqueue interceptor — runs before defaults, middleware, and gates. |
analyzeArguments(taskName, args?) → InterceptionAnalysis | Dry-run the interceptor chain: what it would do, without enqueuing. A chain that would reject comes back as rejected instead of throwing, and the run leaves interceptionStats() untouched. |
gate(name, gate) | Gate an enqueue with a predicate: false rejects, a Decision can also skip or defer. Accepts a registered predicate's name. |
predicateStats() | Gate outcome counters: { allowed, skipped, deferred, rejected, errors }. |
| Member | Description |
|---|---|
lock(name, opts) → Lock | A lock handle, not yet acquired. opts is { ttlMs = 30000, ownerId = randomUUID(), autoExtend = true }; a non-positive or non-finite ttlMs throws RangeError at construction rather than at acquire time. |
withLock(name, fn, opts?) → Promise<T> | async. Acquire, run fn, release. Rejects with LockNotAcquiredError if another owner holds the lock, and with LockLostError if the lease was gone by the time fn finished — a thrown fn still releases, and its own error propagates unchanged. |
Lock handleLock implements Symbol.dispose, so using lock = queue.lock("report")
releases at block exit. Acquisition is never implicit — a handle you never
acquire() guards nothing.
| Member | Description |
|---|---|
acquire() → boolean | Take the lease for this handle's ownerId (acquireLock). false when another owner holds a live one — it does not wait. On a handle that already believes it holds the lock, it re-validates by extending first rather than trusting local state. |
extend(ttlMs?) → boolean | Push the expiry out (extendLock), defaulting to the handle's own ttlMs. false once the lease is gone, which is how auto-extend learns it lost the lock and stops the timer. |
release() → boolean | Stop renewing and drop the lease (releaseLock). false when this handle was not the holder: releasing is owner-scoped, so a stale handle cannot free somebody else's lock. |
info() → LockInfo | undefined | Current holder (getLockInfo): { lockName, ownerId, acquiredAt, expiresAt }, timestamps in Unix milliseconds. undefined when the lock is free. |
locked | Whether this handle believes it holds the lock. Local state — info() is the authoritative answer. |
A lock is a TTL lease, not a mutex. autoExtend renews at ttlMs / 3 and its
timer is unref'd, so it never keeps the process alive; a holder that stalls
past ttlMs anyway loses the lease while still inside its critical section.
Size ttlMs against your worst case, and treat a false from release() as
"the section ran unprotected", not as a no-op.
Schedules live in storage, not in the process, so they outlive the code that
registered them: a schedule deleted while the registering code still runs comes
back on the next registerPeriodic call.
| Member | Description |
|---|---|
registerPeriodic(name, task, cron, opts?) → number | Register or replace a cron schedule → the next fire time (Unix ms). opts: args, queue, timezone, enabled. Throws on an invalid cron expression rather than registering a schedule that never fires. |
listPeriodic() → PeriodicTask[] | Every registered schedule, paused ones included: name, taskName, cronExpr, queue, enabled, lastRun (null until the first fire), nextRun, timezone (null for UTC). Timestamps are Unix milliseconds. |
pausePeriodic(name) / resumePeriodic(name) → boolean | Stop a schedule firing, or start it again, keeping the registration. Both are setPeriodicEnabled on the native queue. false when no schedule had that name. |
deletePeriodic(name) → boolean | Unschedule for good. false when no schedule had that name. |
A paused schedule accumulates no backlog. Its nextRun stays where it was, so
resuming past that instant fires once, immediately, and the schedule then
advances from now — the occurrences missed while paused are not replayed.