mortice
Version:
Isomorphic read/write lock that works in single processes, node clusters and web workers
79 lines • 3.65 kB
JavaScript
import cluster from 'cluster';
import { WORKER_REQUEST_READ_LOCK, WORKER_RELEASE_READ_LOCK, MASTER_GRANT_READ_LOCK, WORKER_REQUEST_WRITE_LOCK, WORKER_RELEASE_WRITE_LOCK, MASTER_GRANT_WRITE_LOCK } from './constants.js';
import { nanoid } from './utils.js';
const handleWorkerLockRequest = (emitter, masterEvent, requestType, releaseType, grantType) => {
return (worker, requestEvent) => {
if (requestEvent != null && requestEvent.type === requestType) {
emitter.dispatchEvent(new MessageEvent(masterEvent, {
data: {
name: requestEvent.name,
handler: async () => {
// grant lock to worker
worker.send({
type: grantType,
name: requestEvent.name,
identifier: requestEvent.identifier
});
// wait for worker to finish
await new Promise((resolve) => {
const releaseEventListener = (releaseEvent) => {
if (releaseEvent.type === releaseType && releaseEvent.identifier === requestEvent.identifier) {
worker.removeListener('message', releaseEventListener);
resolve();
}
};
worker.on('message', releaseEventListener);
});
}
}
}));
}
};
};
const makeWorkerLockRequest = (name, requestType, grantType, releaseType) => {
return async () => {
const id = nanoid();
if (process.send == null) {
throw new Error('No send method on process - are we a cluster worker?');
}
process.send({
type: requestType,
identifier: id,
name
});
return new Promise((resolve) => {
const listener = (event) => {
if (event.type === grantType && event.identifier === id) {
process.removeListener('message', listener);
// grant lock
resolve(() => {
if (process.send == null) {
throw new Error('No send method on process - are we a cluster worker?');
}
// release lock
process.send({
type: releaseType,
identifier: id,
name
});
});
}
};
process.on('message', listener);
});
};
};
export default (options) => {
if (cluster.isPrimary || options.singleProcess) {
const emitter = new EventTarget();
cluster.on('message', handleWorkerLockRequest(emitter, 'requestReadLock', WORKER_REQUEST_READ_LOCK, WORKER_RELEASE_READ_LOCK, MASTER_GRANT_READ_LOCK));
cluster.on('message', handleWorkerLockRequest(emitter, 'requestWriteLock', WORKER_REQUEST_WRITE_LOCK, WORKER_RELEASE_WRITE_LOCK, MASTER_GRANT_WRITE_LOCK));
return emitter;
}
return {
isWorker: true,
readLock: (name) => makeWorkerLockRequest(name, WORKER_REQUEST_READ_LOCK, MASTER_GRANT_READ_LOCK, WORKER_RELEASE_READ_LOCK),
writeLock: (name) => makeWorkerLockRequest(name, WORKER_REQUEST_WRITE_LOCK, MASTER_GRANT_WRITE_LOCK, WORKER_RELEASE_WRITE_LOCK)
};
};
//# sourceMappingURL=node.js.map