UNPKG

node-redisson

Version:

Distributed lock with Redis implementation for Node.js

103 lines (102 loc) 4.19 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RedissonLock = void 0; const ICommandExecutor_1 = require("../contracts/ICommandExecutor"); const TimeUnit_1 = require("../utils/TimeUnit"); const RedissonBaseLock_1 = require("./RedissonBaseLock"); class RedissonLock extends RedissonBaseLock_1.RedissonBaseLock { constructor(commandExecutor, lockName, clientId) { super(commandExecutor, lockName, clientId); } async tryLock(waitTime, leaseTime, unit = TimeUnit_1.TimeUnit.MILLISECONDS) { const waitForever = waitTime === false; let time = unit.toMillis(waitForever ? 0 : waitTime); let current = TimeUnit_1.TimeUnit.now(); const clientId = this.clientId; const ttl = await this.tryAcquire({ leaseTime, unit, clientId }); // lock acquired if (ttl === null) { return true; } const isTimeOver = () => { if (waitForever) return false; // calc wait time time -= TimeUnit_1.TimeUnit.now() - current; // time over, get lock fail return time <= 0; }; // wait lock while (true) { if (isTimeOver()) return false; const ttl = await this.tryAcquire({ leaseTime, unit, clientId }); // lock acquired if (ttl === null) { return true; } if (isTimeOver()) return false; // waiting for message const _waitTime = waitForever || (ttl >= 0 && ttl < time) ? ttl : time; // console.log({ ttl, _waitTime }); const waitResult = await this.commandExecutor.waitSubscribeOnce(this.getChannelName(), // When waitting forever, ttl has a possibility eq 0. // So when _waitTime lte 0, set the timeout to 1000ms. Number(_waitTime > 0 ? _waitTime : 1000)); if (!waitForever && waitResult === ICommandExecutor_1.SYMBOL_TIMEOUT) { return false; } } } async tryAcquire(options) { const { leaseTime, unit, clientId } = options; /** * ttlRemaining == null -> lock acquired * ttlRemaining is a number -> the lock remaining time */ const ttlRemaining = await this.tryLockInner(leaseTime !== true && leaseTime > 0 ? { leaseTime, unit, clientId, } : { leaseTime: this.internalLockLeaseTime, unit: TimeUnit_1.TimeUnit.MILLISECONDS, clientId, }); if (ttlRemaining === null) { // lock acquired if (leaseTime !== true && leaseTime > 0) { this.internalLockLeaseTime = unit.toMillis(leaseTime); } else { this.scheduleExpirationRenewal(clientId); } } return ttlRemaining; } async tryLockInner(options) { return this.commandExecutor.redis.rTryLockInner(this.lockName, options.unit.toMillis(options.leaseTime), this.getClientName(options.clientId)); } async unlockInner(clientId, requestId, timeout) { const result = await this.commandExecutor.redis.rUnlockInner(this.lockName, this.getChannelName(), this.getUnlockLatchName(requestId), ICommandExecutor_1.UnlockMessages.UNLOCK, this.internalLockLeaseTime, this.getClientName(clientId), timeout); // console.log({ clientName: this.getClientName(clientId), result }); if (result === null) { return null; } return !!result; } async lock(leaseTime = true, unit) { await this.tryLock(false, leaseTime, unit); } async forceUnlock() { const result = await this.commandExecutor.redis.rForceUnlock(this.lockName, this.getChannelName(), ICommandExecutor_1.UnlockMessages.UNLOCK); return !!result; } getChannelName() { return RedissonBaseLock_1.RedissonBaseLock.prefixName('redisson_lock__channel', this.lockName); } } exports.RedissonLock = RedissonLock;