UNPKG

@zenweb/cache

Version:
62 lines (61 loc) 1.59 kB
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); } }