UNPKG

@solid/community-server

Version:

Community Solid Server: an open and modular implementation of the Solid specifications

63 lines 2.82 kB
"use strict"; 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