Add Bun.file().lock() and FileLock
Closed
RO
2mo ago+1098+1098+0123456789012345678901234567890123456789-2-2-0123456789
Adds advisory file locking to Bun.file().
API
await using lock = await Bun.file("data.json").lock();
const data = JSON.parse(await lock.text());
data.count++;
await lock.truncate();
await lock.write(JSON.stringify(data));
// lock released on scope exit
Bun.file().lock({ exclusive = true, nonblocking = false, signal? })returnsPromise<FileLock>. On POSIX this isflock(2); on Windows,LockFileExover the full file range. The wait runs on the WorkPool and pollsLOCK_NBwith a futex-backed sleep so anAbortSignalactually breaks out of the wait rather than resolving late.FileLockimplementsSymbol.asyncDisposeandunlock()/close(). While held it also exposesbytes(n?),read(n?),text(n?),arrayBuffer(n?),write(data), andtruncate(n?)operating on the locked fd (positional from offset 0).Bun.file(fd).unlock()releases a lock on a caller-owned fd. On a path-backedBunFileit rejects, pointing the user at theFileLockreturned bylock().
Implementation
- New
bun_sys::flock/funlockwrappers (POSIXflock, Win32LockFileEx/UnlockFileEx) andTag::flock. FileLockJS class (src/runtime/webcore/FileLock.classes.ts,src/runtime/webcore/blob/FileLock.rs).- Two
ConcurrentPromiseTaskcontexts:LockTaskCtxfor acquisition andIoTaskCtxfor read/write/truncate.
Tests
test/js/bun/io/bun-file-lock.test.ts covers: async disposable release, shared locks, cross-process blocking wait, nonblocking rejection under contention, AbortSignal mid-wait and pre-aborted, fd-backed lock/unlock, error paths for non-file blobs and path-backed unlock(), and the full read/write/truncate round-trip. All 16 tests pass on the debug build and fail on the released binary (lock is not a function).
no test proof · iteration 4 · Platform-specific test(s) that do not run on this machine. Deferring to CI, which covers all platforms: test/js/bun/io/bun-file-lock.test.ts
Fixes #26230