@zenweb/cache
Version:
Zenweb Cache module
62 lines (61 loc) • 1.59 kB
JavaScript
import { randomBytes, createHash } from 'node:crypto';
import { runRedisScript } from './utils.js';
const RELEASE_SCRIPT = `
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
`;
const RELEASE_SCRIPT_HASH = createHash('sha1').update(RELEASE_SCRIPT).digest('hex');
/**
* 基于 Redis 的分布式锁
*/
export class Locker {
redis;
key;
timeout;
value = randomBytes(16).toString('hex');
/**
* @param redis Redis 实例
* @param key 锁KEY
* @param timeout 锁超时(毫秒) 默认 10秒
*/
constructor(redis, key, timeout = 10000) {
this.redis = redis;
this.key = key;
this.timeout = timeout;
}
/**
* 取得锁
* @returns true 取得成功, 否则失败
*/
async acquire() {
// NX 不存在key 才创建
// PX 过期时间
const result = await this.redis.call('SET', this.key, this.value, 'NX', 'PX', this.timeout);
return result === 'OK';
}
/**
* 释放锁
*/
async release() {
return (await runRedisScript(this.redis, RELEASE_SCRIPT_HASH, RELEASE_SCRIPT, [this.key], [this.value])) === 1;
}
/**
* 使用锁回调
* @param callback 获取结果回调 true: 成功 false: 失败
*/
async using(callback) {
if (await this.acquire()) {
try {
await callback(true);
return;
}
finally {
await this.release();
}
}
callback(false);
}
}