node-redisson
Version:
Distributed lock with Redis implementation for Node.js
125 lines (124 loc) • 3.69 kB
JavaScript
"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;