UNPKG

@wenye123/redis-lock

Version:
124 lines (123 loc) 3.87 kB
"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;