On disk
Zero bytes
No owner, PID, heartbeat, policy, or fencing token is encoded.
Maintained compatibility · Node.js
A small CommonJS lock-file implementation that keeps the published 1.0.4 contract and makes real asynchronous cleanup failures observable.
Asynchronous unlock still treats ENOENT as success, but now forwards the original non-ENOENT unlink error exactly once. Successful callbacks and every synchronous behavior stay compatible.
Coordination model
The implementation relies on filesystem primitives, not a daemon or an ownership lease. Every participant must follow the same protocol.
On disk
No owner, PID, heartbeat, policy, or fencing token is encoded.
Within one process
Known locks receive best-effort cleanup through signal-exit.
Across processes
Exclusive create, visibility, hard-link, unlink, and metadata behavior determine correctness.
Public surface
All asynchronous operations use callbacks. Sync methods return their documented value or throw, except for best-effort unlockSync.
Async · acquire
lock(path, [options], callback)Creates the lock or calls back with the original acquisition or contention error. Success is callback().
Sync · acquire
lockSync(path, [options])Creates the lock and returns undefined, or throws. Sync calls reject waiting options.
Async · release
unlock(path, [callback])Unlinks the lock. Success and ENOENT call back without an error; other unlink errors are preserved.
Sync · release
unlockSync(path)Best-effort cleanup. It suppresses every unlink error and returns undefined, matching upstream.
Async · observe
check(path, [options], callback)Calls callback(error, isLocked). The result is an observation, not an atomic reservation.
Sync · observe
checkSync(path, [options])Returns whether the lock exists and is not stale, or throws for an unexpected filesystem error.
Mutable compatibility property
lockfile.filetime defaults to ctime on POSIX and mtime on Windows. It selects the stat timestamp used by stale checks.
Timing controls
| Option | Used by | Behavior |
|---|---|---|
wait |
Async lock |
Poll for up to this many milliseconds, then return the original contention error. |
pollPeriod |
Async lock |
Polling interval while waiting. Defaults to 100 milliseconds. |
stale |
Lock and check | Age in milliseconds after which takeover is allowed. Disabled when omitted. |
retries |
lock, lockSync |
Number of additional acquisition attempts. |
retryWait |
Async lock |
Delay between retries. lockSync rejects it. |
lockSync rejects wait and retryWait; checkSync rejects wait. POSIX stale checks use ctime, Windows uses mtime, and sync takeover retains the upstream timestamp-resolution rounding rule.
Compatibility boundary
Published lockfile@1.0.4 discarded every asynchronous unlink error. Version 1.0.5 distinguishes an already-missing lock from a real cleanup failure.
| Unlink outcome | lockfile@1.0.4 |
@stackline/lockfile@1.0.6 |
|---|---|---|
| Success | callback() |
callback() |
ENOENT |
callback() |
callback() |
| Any other error | callback(), error lost |
callback(originalError), exactly once |
| Synchronous unlink error | Suppressed | Suppressed |
First-party declarations model callbacks, options, mutable filetime, and real undefined success values. They add no Promise or ESM implementation.
Different callers can still choose conflicting stale thresholds. The format contains no owner or policy metadata, so resolving that conflict requires a new protocol.
Read the issue 18 boundary, the issue 30 limitation, and the full compatibility contract.
Operational safety
Local tests cannot establish behavior for every mount. Validate the exact operating system, filesystem, topology, and failure modes used in production.
Attribute caching, visibility delay, clock differences, coarse timestamps, or weaker atomicity can invalidate stale and contention assumptions.
A threshold that is too short can remove a live lock. POSIX and Windows deliberately use different metadata timestamps.
Process-exit removal is best-effort. Abrupt termination, power loss, and unlink errors can leave a lock behind.
A party able to modify the directory can bypass the protocol. Use trusted paths and appropriate directory ownership and permissions.
check is an observationAnother participant can act after a check. Acquire the lock for mutual exclusion; do not build a check-then-act security decision.
Heartbeats, ownership metadata, leases, fencing, or compromise detection need a different design. proper-lockfile is not drop-in compatible.
Reference