Implementation:Puppeteer Puppeteer Mutex
| Property | Value |
|---|---|
| sources | packages/puppeteer-core/src/util/Mutex.ts |
| domains | Utility, Concurrency |
| last_updated | 2026-02-12 00:00 GMT |
Overview
Description
The Mutex class implements a FIFO (first-in, first-out) mutual exclusion lock for coordinating asynchronous operations in Puppeteer. It ensures that only one asynchronous operation can hold the lock at a time, with subsequent acquirers queued and served in order. The mutex integrates with the TC39 Explicit Resource Management proposal through a disposable Guard inner class, allowing callers to use the await using syntax to automatically release the lock when the guard goes out of scope.
Internally, the mutex tracks a queue of pending acquirers using Deferred instances. When acquire is called on an already-locked mutex, a new deferred is created and its resolve callback is pushed into the queue. When release is called, the next queued resolver is invoked, passing the lock to the next waiter in FIFO order.
Usage
The mutex is used internally by Puppeteer to serialize access to shared resources, such as during guarded decorator execution or when writing frames in the screen recorder. It is not part of the public API.
Code Reference
Source Location
packages/puppeteer-core/src/util/Mutex.ts
Signature
export class Mutex {
static Guard: {
new (mutex: Mutex, onRelease?: () => void): {
[disposeSymbol](): void;
};
};
async acquire(onRelease?: () => void): Promise<InstanceType<typeof Mutex.Guard>>;
release(): void;
}
Import
import {Mutex} from '../util/Mutex.js';
I/O Contract
| Method | Parameter | Type | Description |
|---|---|---|---|
| acquire | onRelease | undefined | Optional callback invoked when the guard is disposed |
| Method | Return Type | Description |
|---|---|---|
| acquire | Promise<Mutex.Guard> |
Resolves with a disposable guard once the lock is acquired |
| release | void |
Releases the lock and passes it to the next queued acquirer |
Usage Examples
const mutex = new Mutex();
// Using explicit resource management (await using)
{
await using _guard = await mutex.acquire();
// Critical section: only one async operation executes here at a time
await performExclusiveOperation();
}
// Lock is automatically released when _guard goes out of scope
// Manual acquire/release pattern
const guard = await mutex.acquire(() => {
console.log('Lock released');
});
try {
await doWork();
} finally {
guard[Symbol.dispose]();
}