1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
| // 简单分布式锁
class DistributedLock {
constructor(redis) {
this.redis = redis;
}
async acquire(key, ttl = 30) {
const lockValue = generateUUID();
const result = await this.redis.setnx(key, lockValue, ttl);
if (result === 1) {
return {
acquired: true,
value: lockValue
};
}
return {
acquired: false,
value: null
};
}
async release(key, lockValue) {
const script = `
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
`;
const result = await this.redis.eval(script, 1, key, lockValue);
return result === 1;
}
async extend(key, lockValue, ttl) {
const script = `
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("expire", KEYS[1], ARGV[2])
else
return 0
end
`;
return await this.redis.eval(script, 1, key, lockValue, ttl);
}
}
// 可重入锁
class ReentrantLock {
constructor(redis) {
this.redis = redis;
}
async acquire(key, lockId, ttl = 30) {
const lockKey = `reentrant:${key}:${lockId}`;
const counterKey = `reentrant:${key}:counter`;
const script = `
local counter = redis.call("incr", KEYS[2])
redis.call("expire", KEYS[2], ARGV[1])
redis.call("set", KEYS[1], "1", "EX", ARGV[1])
return counter
`;
return await this.redis.eval(script, 2, lockKey, counterKey, ttl);
}
async release(key, lockId) {
const lockKey = `reentrant:${key}:${lockId}`;
const counterKey = `reentrant:${key}:counter`;
const script = `
local count = redis.call("get", KEYS[1])
if count == "0" then
return 0
end
redis.call("decr", KEYS[2])
if tonumber(redis.call("get", KEYS[2])) == 0 then
redis.call("del", KEYS[1])
redis.call("del", KEYS[2])
end
return 1
`;
return await this.redis.eval(script, 2, lockKey, counterKey);
}
}
|