@wenye123/redis-lock
Version:
124 lines (123 loc) • 3.87 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class default_1 {
constructor(options) {
this.redis = options.client;
this.keyPrefix = options.keyPrefix;
// 初始化lua脚本
this.initLua();
}
getKeyName(lockNmae) {
return `${this.keyPrefix}${lockNmae}`;
}
getIdentifier() {
return Math.random()
.toString(16)
.split(".")[1];
}
sleep(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
initLua() {
// 释放锁
this.redis.defineCommand("releaseLock", {
numberOfKeys: 1,
lua: `
if (redis.call("get", KEYS[1]) == ARGV[1])
then
return redis.call("del", KEYS[1]);
end
`,
});
// 获取信号量
this.redis.defineCommand("acquireSemaphore", {
numberOfKeys: 1,
lua: `
redis.call("zremrangebyscore", KEYS[1], "-inf", ARGV[1]);
if (redis.call("zcard", KEYS[1]) < tonumber(ARGV[2]))
then
redis.call("zadd", KEYS[1], ARGV[3], ARGV[4]);
return ARGV[4];
end
`,
});
// 释放信号量
this.redis.defineCommand("refreshSemaphore", {
numberOfKeys: 1,
lua: `
if redis.call("zscore", KEYS[1], ARGV[1])
then
return redis.call("zadd", KEYS[1], ARGV[2], ARGV[1]);
end
`,
});
}
/**
* 请求一个锁标志
* @param lockName 锁名字
* @param acquireTimeout 请求超时毫秒数,默认3000
* @param lockTimeout 锁过期毫秒数,默认5000
*/
async acquireLock(lockName, acquireTimeout = 3000, lockTimeout = 5000) {
lockName = this.getKeyName(lockName);
lockTimeout = Math.ceil(lockTimeout); // 超时时间都是整数
const identifier = this.getIdentifier();
const end = Date.now() + acquireTimeout;
while (Date.now() < end) {
// 设置锁且包含过期时间
const ret = await this.redis.set(lockName, identifier, "PX", lockTimeout, "NX");
if (ret === "OK")
return identifier;
await this.sleep(20);
}
return null;
}
/**
* 释放锁
* @param lockName 锁名字
* @param identifier 锁标志
*/
async releaseLock(lockName, identifier) {
lockName = this.getKeyName(lockName);
const ret = await this.redis.releaseLock(lockName, identifier);
return ret === 1;
}
/**
* 获取信号量
* @param sename 信号量名字
* @param limit 限制数
* @param timeout 信号量过期毫秒数,默认3000
*/
async acquireSemaphore(sename, limit, timeout = 3000) {
sename = this.getKeyName(sename);
const identifier = this.getIdentifier();
const now = Date.now();
const ident = await this.redis.acquireSemaphore(sename, now - timeout, limit, now, identifier);
return ident;
}
/**
* 释放信号量
* @param sename 信号量名字
* @param identifier 信号量标识
*/
async releaseSemaphore(sename, identifier) {
sename = this.getKeyName(sename);
// 正确释放返回true 否则就是该信号量已过期
const ret = await this.redis.zrem(sename, identifier);
return Boolean(ret);
}
/**
* 刷新信号量
* @param sename 信号量名字
* @param identifier 信号量标识符
*/
async refreshSemaphore(sename, identifier) {
sename = this.getKeyName(sename);
const now = Date.now();
const ret = await this.redis.refreshSemaphore(sename, identifier, now);
return ret === 0;
}
}
exports.default = default_1;