@solid/community-server
Version:
Community Solid Server: an open and modular implementation of the Solid specifications
63 lines • 2.82 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.WrappedExpiringReadWriteLocker = void 0;
const global_logger_factory_1 = require("global-logger-factory");
const InternalServerError_1 = require("../errors/InternalServerError");
/**
* Wraps around an existing {@link ReadWriteLocker} and adds expiration logic to prevent locks from getting stuck.
*/
class WrappedExpiringReadWriteLocker {
logger = (0, global_logger_factory_1.getLoggerFor)(this);
locker;
expiration;
/**
* @param locker - Instance of ResourceLocker to use for acquiring a lock.
* @param expiration - Time in ms after which the lock expires.
*/
constructor(locker, expiration) {
this.locker = locker;
this.expiration = expiration;
}
async withReadLock(identifier, whileLocked) {
return this.locker.withReadLock(identifier, async () => this.expiringPromise(identifier, whileLocked));
}
async withWriteLock(identifier, whileLocked) {
return this.locker.withWriteLock(identifier, async () => this.expiringPromise(identifier, whileLocked));
}
/**
* Creates a Promise that either resolves the given input function or rejects if time runs out,
* whichever happens first. The input function can reset the timer by calling the `maintainLock` function
* it receives. The ResourceIdentifier is only used for logging.
*/
async expiringPromise(identifier, whileLocked) {
let timer;
let createTimeout;
// Promise that throws an error when the timer finishes
const timerPromise = new Promise((resolve, reject) => {
// Starts the timer that will cause this promise to error after a given time
createTimeout = () => setTimeout(() => {
this.logger.error(`Lock expired after ${this.expiration}ms on ${identifier.path}`);
reject(new InternalServerError_1.InternalServerError(`Lock expired after ${this.expiration}ms on ${identifier.path}`));
}, this.expiration);
timer = createTimeout();
});
// Restarts the timer
const renewTimer = () => {
this.logger.verbose(`Renewed expiring lock on ${identifier.path}`);
clearTimeout(timer);
timer = createTimeout();
};
// Runs the main function and cleans up the timer afterwards
async function runWithTimeout() {
try {
return await whileLocked(renewTimer);
}
finally {
clearTimeout(timer);
}
}
return Promise.race([timerPromise, runWithTimeout()]);
}
}
exports.WrappedExpiringReadWriteLocker = WrappedExpiringReadWriteLocker;
//# sourceMappingURL=WrappedExpiringReadWriteLocker.js.map