UNPKG

node-redisson

Version:

Distributed lock with Redis implementation for Node.js

125 lines (124 loc) 3.69 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CommandExecutor = exports.DEFAULT_REDIS_SCRIPTS = void 0; const ICommandExecutor_1 = require("../contracts/ICommandExecutor"); const ioredis_1 = __importDefault(require("ioredis")); const crypto_1 = require("crypto"); exports.DEFAULT_REDIS_SCRIPTS = Object.freeze({ rTryLockInner: { lua: ` if ((redis.call('exists', KEYS[1]) == 0) or (redis.call('hexists', KEYS[1], ARGV[2]) == 1)) then redis.call('hincrby', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end return redis.call('pttl', KEYS[1]);`, numberOfKeys: 1, }, rUnlockInner: { lua: ` local val = redis.call('get', KEYS[3]); if val ~= false then return tonumber(val); end if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then return nil; end local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); if (counter > 0) then redis.call('pexpire', KEYS[1], ARGV[2]); redis.call('set', KEYS[3], 0, 'px', ARGV[4]); return 0; else redis.call('del', KEYS[1]); #PUB_UNLOCK_REPLACE# redis.call('set', KEYS[3], 1, 'px', ARGV[4]); return 1; end`, numberOfKeys: 3, }, rRenewExpiration: { lua: ` if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then redis.call('pexpire', KEYS[1], ARGV[1]); return 1; end; return 0;`, numberOfKeys: 1, }, rForceUnlock: { lua: ` if (redis.call('del', KEYS[1]) == 1) then #PUB_UNLOCK_REPLACE# return 1 else return 0 end`, numberOfKeys: 2, }, }); class CommandExecutor { constructor(config) { this.config = config; this._id = (0, crypto_1.randomUUID)(); this._redis = this.createRedis(); this._subscribeRedis = this.createRedis(); } createRedis() { const customScripts = this.getRedisScripts(); const scripts = Object.keys(exports.DEFAULT_REDIS_SCRIPTS).reduce((pre, current) => { const defaultValue = exports.DEFAULT_REDIS_SCRIPTS[current]; pre[current] = { ...defaultValue, lua: customScripts[current] ?? defaultValue.lua, }; return pre; }, {}); if ('clusters' in this.config.redis) { return new ioredis_1.default.Cluster(this.config.redis.clusters, { ...this.config.redis.options, scripts, }); } else { return new ioredis_1.default({ ...this.config.redis.options, scripts, }); } } get id() { return this._id; } get redissonConfig() { return this.config; } get serviceManager() { throw new Error('Method not implemented.'); } get redis() { return this._redis; } get subscribeRedis() { return this._subscribeRedis; } waitSubscribeOnce(eventName, timeout) { return new Promise(async (resolve) => { const handler = async (e) => { await this.unsubscribe(eventName, handler); resolve(e); }; if (timeout) { setTimeout(async () => { await this.unsubscribe(eventName, handler); resolve(ICommandExecutor_1.SYMBOL_TIMEOUT); }, timeout); } await this.subscribeOnce(eventName, handler); }); } } exports.CommandExecutor = CommandExecutor;