effect-distributed-lock 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/examples/concurrent.ts +111 -0
  2. package/package.json +1 -1
  3. package/src/DistributedSemaphore.ts +1 -0
  4. package/src/RedisBacking.ts +2 -2
  5. package/redis-semaphore/.codeclimate.yml +0 -5
  6. package/redis-semaphore/.fossa.yml +0 -14
  7. package/redis-semaphore/.github/dependabot.yml +0 -6
  8. package/redis-semaphore/.github/workflows/branches.yml +0 -39
  9. package/redis-semaphore/.github/workflows/pull-requests.yml +0 -35
  10. package/redis-semaphore/.mocharc.yaml +0 -6
  11. package/redis-semaphore/.prettierrc +0 -6
  12. package/redis-semaphore/.snyk +0 -4
  13. package/redis-semaphore/.yarnrc.yml +0 -2
  14. package/redis-semaphore/CHANGELOG.md +0 -70
  15. package/redis-semaphore/Dockerfile +0 -5
  16. package/redis-semaphore/LICENSE +0 -21
  17. package/redis-semaphore/README.md +0 -445
  18. package/redis-semaphore/docker-compose.yml +0 -31
  19. package/redis-semaphore/eslint.config.mjs +0 -73
  20. package/redis-semaphore/package.json +0 -79
  21. package/redis-semaphore/setup-redis-servers.sh +0 -2
  22. package/redis-semaphore/src/Lock.ts +0 -172
  23. package/redis-semaphore/src/RedisMultiSemaphore.ts +0 -56
  24. package/redis-semaphore/src/RedisMutex.ts +0 -45
  25. package/redis-semaphore/src/RedisSemaphore.ts +0 -49
  26. package/redis-semaphore/src/RedlockMultiSemaphore.ts +0 -56
  27. package/redis-semaphore/src/RedlockMutex.ts +0 -52
  28. package/redis-semaphore/src/RedlockSemaphore.ts +0 -49
  29. package/redis-semaphore/src/errors/LostLockError.ts +0 -1
  30. package/redis-semaphore/src/errors/TimeoutError.ts +0 -1
  31. package/redis-semaphore/src/index.ts +0 -23
  32. package/redis-semaphore/src/misc.ts +0 -12
  33. package/redis-semaphore/src/multiSemaphore/acquire/index.ts +0 -53
  34. package/redis-semaphore/src/multiSemaphore/acquire/lua.ts +0 -31
  35. package/redis-semaphore/src/multiSemaphore/refresh/index.ts +0 -32
  36. package/redis-semaphore/src/multiSemaphore/refresh/lua.ts +0 -31
  37. package/redis-semaphore/src/multiSemaphore/release/index.ts +0 -22
  38. package/redis-semaphore/src/multiSemaphore/release/lua.ts +0 -17
  39. package/redis-semaphore/src/mutex/acquire.ts +0 -42
  40. package/redis-semaphore/src/mutex/refresh.ts +0 -37
  41. package/redis-semaphore/src/mutex/release.ts +0 -30
  42. package/redis-semaphore/src/redlockMultiSemaphore/acquire.ts +0 -56
  43. package/redis-semaphore/src/redlockMultiSemaphore/refresh.ts +0 -68
  44. package/redis-semaphore/src/redlockMultiSemaphore/release.ts +0 -19
  45. package/redis-semaphore/src/redlockMutex/acquire.ts +0 -54
  46. package/redis-semaphore/src/redlockMutex/refresh.ts +0 -53
  47. package/redis-semaphore/src/redlockMutex/release.ts +0 -19
  48. package/redis-semaphore/src/redlockSemaphore/acquire.ts +0 -55
  49. package/redis-semaphore/src/redlockSemaphore/refresh.ts +0 -60
  50. package/redis-semaphore/src/redlockSemaphore/release.ts +0 -18
  51. package/redis-semaphore/src/semaphore/acquire/index.ts +0 -52
  52. package/redis-semaphore/src/semaphore/acquire/lua.ts +0 -25
  53. package/redis-semaphore/src/semaphore/refresh/index.ts +0 -31
  54. package/redis-semaphore/src/semaphore/refresh/lua.ts +0 -25
  55. package/redis-semaphore/src/semaphore/release.ts +0 -14
  56. package/redis-semaphore/src/types.ts +0 -63
  57. package/redis-semaphore/src/utils/createEval.ts +0 -45
  58. package/redis-semaphore/src/utils/index.ts +0 -13
  59. package/redis-semaphore/src/utils/redlock.ts +0 -7
  60. package/redis-semaphore/test/init.test.ts +0 -9
  61. package/redis-semaphore/test/redisClient.ts +0 -82
  62. package/redis-semaphore/test/setup.ts +0 -6
  63. package/redis-semaphore/test/shell.test.ts +0 -15
  64. package/redis-semaphore/test/shell.ts +0 -48
  65. package/redis-semaphore/test/src/Lock.test.ts +0 -37
  66. package/redis-semaphore/test/src/RedisMultiSemaphore.test.ts +0 -425
  67. package/redis-semaphore/test/src/RedisMutex.test.ts +0 -334
  68. package/redis-semaphore/test/src/RedisSemaphore.test.ts +0 -367
  69. package/redis-semaphore/test/src/RedlockMultiSemaphore.test.ts +0 -671
  70. package/redis-semaphore/test/src/RedlockMutex.test.ts +0 -328
  71. package/redis-semaphore/test/src/RedlockSemaphore.test.ts +0 -579
  72. package/redis-semaphore/test/src/index.test.ts +0 -22
  73. package/redis-semaphore/test/src/multiSemaphore/acquire/index.test.ts +0 -51
  74. package/redis-semaphore/test/src/multiSemaphore/acquire/internal.test.ts +0 -67
  75. package/redis-semaphore/test/src/multiSemaphore/refresh/index.test.ts +0 -52
  76. package/redis-semaphore/test/src/multiSemaphore/release/index.test.ts +0 -18
  77. package/redis-semaphore/test/src/mutex/acquire.test.ts +0 -78
  78. package/redis-semaphore/test/src/mutex/refresh.test.ts +0 -22
  79. package/redis-semaphore/test/src/mutex/release.test.ts +0 -17
  80. package/redis-semaphore/test/src/redlockMutex/acquire.test.ts +0 -90
  81. package/redis-semaphore/test/src/redlockMutex/refresh.test.ts +0 -27
  82. package/redis-semaphore/test/src/redlockMutex/release.test.ts +0 -17
  83. package/redis-semaphore/test/src/semaphore/acquire/index.test.ts +0 -49
  84. package/redis-semaphore/test/src/semaphore/acquire/internal.test.ts +0 -65
  85. package/redis-semaphore/test/src/semaphore/refresh/index.test.ts +0 -44
  86. package/redis-semaphore/test/src/semaphore/release.test.ts +0 -18
  87. package/redis-semaphore/test/src/utils/eval.test.ts +0 -22
  88. package/redis-semaphore/test/src/utils/index.test.ts +0 -19
  89. package/redis-semaphore/test/src/utils/redlock.test.ts +0 -31
  90. package/redis-semaphore/test/unhandledRejection.ts +0 -28
  91. package/redis-semaphore/tsconfig.build-commonjs.json +0 -9
  92. package/redis-semaphore/tsconfig.build-es.json +0 -9
  93. package/redis-semaphore/tsconfig.json +0 -11
  94. package/redis-semaphore/yarn.lock +0 -5338
  95. /package/examples/{index.ts → kitchen-sink.ts} +0 -0
@@ -1,22 +0,0 @@
1
- import createDebug from 'debug'
2
- import { RedisClient } from '../../types'
3
- import { releaseLua } from './lua'
4
-
5
- const debug = createDebug('redis-semaphore:multi-semaphore:release')
6
-
7
- export interface Options {
8
- identifier: string
9
- lockTimeout: number
10
- now: number
11
- }
12
-
13
- export async function releaseSemaphore(
14
- client: RedisClient,
15
- key: string,
16
- permits: number,
17
- identifier: string
18
- ): Promise<void> {
19
- debug(key, identifier, permits)
20
- const result = await releaseLua(client, [key, permits, identifier])
21
- debug('result', typeof result, result)
22
- }
@@ -1,17 +0,0 @@
1
- import { createEval } from '../../utils/index'
2
-
3
- export const releaseLua = createEval<[string, number, string], number>(
4
- `
5
- local key = KEYS[1]
6
- local permits = tonumber(ARGV[1])
7
- local identifier = ARGV[2]
8
- local args = {}
9
-
10
- for i=0, permits - 1 do
11
- table.insert(args, identifier .. '_' .. i)
12
- end
13
-
14
- return redis.call('zrem', key, unpack(args))
15
- `,
16
- 1
17
- )
@@ -1,42 +0,0 @@
1
- import createDebug from 'debug'
2
- import { RedisClient } from '../types'
3
- import { delay } from '../utils'
4
-
5
- const debug = createDebug('redis-semaphore:mutex:acquire')
6
-
7
- export interface Options {
8
- identifier: string
9
- lockTimeout: number
10
- acquireTimeout: number
11
- acquireAttemptsLimit: number
12
- retryInterval: number
13
- }
14
-
15
- export async function acquireMutex(
16
- client: RedisClient,
17
- key: string,
18
- options: Options
19
- ): Promise<boolean> {
20
- const {
21
- identifier,
22
- lockTimeout,
23
- acquireTimeout,
24
- acquireAttemptsLimit,
25
- retryInterval
26
- } = options
27
- let attempt = 0
28
- const end = Date.now() + acquireTimeout
29
- while (Date.now() < end && ++attempt <= acquireAttemptsLimit) {
30
- debug(key, identifier, 'attempt', attempt)
31
- const result = await client.set(key, identifier, 'PX', lockTimeout, 'NX')
32
- debug('result', typeof result, result)
33
- if (result === 'OK') {
34
- debug(key, identifier, 'acquired')
35
- return true
36
- } else {
37
- await delay(retryInterval)
38
- }
39
- }
40
- debug(key, identifier, 'timeout or reach limit')
41
- return false
42
- }
@@ -1,37 +0,0 @@
1
- import createDebug from 'debug'
2
- import { RedisClient } from '../types'
3
- import { createEval } from '../utils/index'
4
-
5
- const debug = createDebug('redis-semaphore:mutex:refresh')
6
-
7
- export const expireIfEqualLua = createEval<[string, string, number], 0 | 1>(
8
- `
9
- local key = KEYS[1]
10
- local identifier = ARGV[1]
11
- local lockTimeout = ARGV[2]
12
-
13
- local value = redis.call('get', key)
14
-
15
- if value == identifier then
16
- redis.call('pexpire', key, lockTimeout)
17
- return 1
18
- end
19
-
20
- return 0
21
- `,
22
- 1
23
- )
24
-
25
- export async function refreshMutex(
26
- client: RedisClient,
27
- key: string,
28
- identifier: string,
29
- lockTimeout: number
30
- ): Promise<boolean> {
31
- debug(key, identifier)
32
- const result = await expireIfEqualLua(client, [key, identifier, lockTimeout])
33
- debug('result', typeof result, result)
34
-
35
- // support options.stringNumbers
36
- return +result === 1
37
- }
@@ -1,30 +0,0 @@
1
- import createDebug from 'debug'
2
- import { createEval } from '../utils/index'
3
-
4
- import type { RedisClient } from '../types'
5
-
6
- const debug = createDebug('redis-semaphore:mutex:release')
7
-
8
- export const delIfEqualLua = createEval<[string, string], 0 | 1>(
9
- `
10
- local key = KEYS[1]
11
- local identifier = ARGV[1]
12
-
13
- if redis.call('get', key) == identifier then
14
- return redis.call('del', key)
15
- end
16
-
17
- return 0
18
- `,
19
- 1
20
- )
21
-
22
- export async function releaseMutex(
23
- client: RedisClient,
24
- key: string,
25
- identifier: string
26
- ): Promise<void> {
27
- debug(key, identifier)
28
- const result = await delIfEqualLua(client, [key, identifier])
29
- debug('result', typeof result, result)
30
- }
@@ -1,56 +0,0 @@
1
- import createDebug from 'debug'
2
- import { acquireLua } from '../multiSemaphore/acquire/lua'
3
- import { RedisClient } from '../types'
4
- import { delay } from '../utils'
5
- import { getQuorum, smartSum } from '../utils/redlock'
6
-
7
- const debug = createDebug('redis-semaphore:redlock-multi-semaphore:acquire')
8
-
9
- export interface Options {
10
- identifier: string
11
- lockTimeout: number
12
- acquireTimeout: number
13
- acquireAttemptsLimit: number
14
- retryInterval: number
15
- }
16
-
17
- export async function acquireRedlockMultiSemaphore(
18
- clients: RedisClient[],
19
- key: string,
20
- limit: number,
21
- permits: number,
22
- options: Options
23
- ): Promise<boolean> {
24
- const {
25
- identifier,
26
- lockTimeout,
27
- acquireTimeout,
28
- acquireAttemptsLimit,
29
- retryInterval
30
- } = options
31
- let attempt = 0
32
- const end = Date.now() + acquireTimeout
33
- const quorum = getQuorum(clients.length)
34
- let now: number
35
- while ((now = Date.now()) < end && ++attempt <= acquireAttemptsLimit) {
36
- debug(key, identifier, 'attempt', attempt)
37
- const promises = clients.map(client =>
38
- acquireLua(client, [key, limit, permits, identifier, lockTimeout, now])
39
- .then(result => +result)
40
- .catch(() => 0)
41
- )
42
- const results = await Promise.all(promises)
43
- if (results.reduce(smartSum, 0) >= quorum) {
44
- debug(key, identifier, 'acquired')
45
- return true
46
- } else {
47
- const promises = clients.map(client =>
48
- client.zrem(key, identifier).catch(() => 0)
49
- )
50
- await Promise.all(promises)
51
- await delay(retryInterval)
52
- }
53
- }
54
- debug(key, identifier, 'timeout or reach limit')
55
- return false
56
- }
@@ -1,68 +0,0 @@
1
- import createDebug from 'debug'
2
- import { acquireLua } from '../multiSemaphore/acquire/lua'
3
- import { refreshLua } from '../multiSemaphore/refresh/lua'
4
- import { releaseLua } from '../multiSemaphore/release/lua'
5
- import { RedisClient } from '../types'
6
- import { getQuorum, smartSum } from '../utils/redlock'
7
-
8
- const debug = createDebug('redis-semaphore:redlock-semaphore:refresh')
9
-
10
- interface Options {
11
- identifier: string
12
- lockTimeout: number
13
- }
14
-
15
- export async function refreshRedlockMultiSemaphore(
16
- clients: RedisClient[],
17
- key: string,
18
- limit: number,
19
- permits: number,
20
- options: Options
21
- ): Promise<boolean> {
22
- const { identifier, lockTimeout } = options
23
- const now = Date.now()
24
- debug(key, identifier, now)
25
- const quorum = getQuorum(clients.length)
26
- const promises = clients.map(client =>
27
- refreshLua(client, [key, limit, permits, identifier, lockTimeout, now])
28
- .then(result => +result)
29
- .catch(() => 0)
30
- )
31
- const results = await Promise.all(promises)
32
- debug('results', results)
33
- const refreshedCount = results.reduce(smartSum, 0)
34
- if (refreshedCount >= quorum) {
35
- debug(key, identifier, 'refreshed')
36
- if (refreshedCount < clients.length) {
37
- debug(key, identifier, 'try to acquire on failed nodes')
38
- const promises = results
39
- .reduce<RedisClient[]>((failedClients, result, index) => {
40
- if (!result) {
41
- failedClients.push(clients[index])
42
- }
43
- return failedClients
44
- }, [])
45
- .map(client =>
46
- acquireLua(client, [
47
- key,
48
- limit,
49
- permits,
50
- identifier,
51
- lockTimeout,
52
- now
53
- ])
54
- .then(result => +result)
55
- .catch(() => 0)
56
- )
57
- const acquireResults = await Promise.all(promises)
58
- debug(key, identifier, 'acquire on failed nodes results', acquireResults)
59
- }
60
- return true
61
- } else {
62
- const promises = clients.map(client =>
63
- releaseLua(client, [key, permits, identifier]).catch(() => 0)
64
- )
65
- await Promise.all(promises)
66
- return false
67
- }
68
- }
@@ -1,19 +0,0 @@
1
- import createDebug from 'debug'
2
- import { releaseLua } from '../multiSemaphore/release/lua'
3
- import { RedisClient } from '../types'
4
-
5
- const debug = createDebug('redis-semaphore:redlock-mutex:release')
6
-
7
- export async function releaseRedlockMultiSemaphore(
8
- clients: RedisClient[],
9
- key: string,
10
- permits: number,
11
- identifier: string
12
- ): Promise<void> {
13
- debug(key, identifier)
14
- const promises = clients.map(client =>
15
- releaseLua(client, [key, permits, identifier]).catch(() => 0)
16
- )
17
- const results = await Promise.all(promises)
18
- debug('results', results)
19
- }
@@ -1,54 +0,0 @@
1
- import createDebug from 'debug'
2
- import { delIfEqualLua } from '../mutex/release'
3
- import { RedisClient } from '../types'
4
- import { delay } from '../utils'
5
- import { getQuorum, smartSum } from '../utils/redlock'
6
-
7
- const debug = createDebug('redis-semaphore:redlock-mutex:acquire')
8
-
9
- export interface Options {
10
- identifier: string
11
- lockTimeout: number
12
- acquireTimeout: number
13
- acquireAttemptsLimit: number
14
- retryInterval: number
15
- }
16
-
17
- export async function acquireRedlockMutex(
18
- clients: RedisClient[],
19
- key: string,
20
- options: Options
21
- ): Promise<boolean> {
22
- const {
23
- identifier,
24
- lockTimeout,
25
- acquireTimeout,
26
- acquireAttemptsLimit,
27
- retryInterval
28
- } = options
29
- let attempt = 0
30
- const end = Date.now() + acquireTimeout
31
- const quorum = getQuorum(clients.length)
32
- while (Date.now() < end && ++attempt <= acquireAttemptsLimit) {
33
- debug(key, identifier, 'attempt', attempt)
34
- const promises = clients.map(client =>
35
- client
36
- .set(key, identifier, 'PX', lockTimeout, 'NX')
37
- .then(result => (result === 'OK' ? 1 : 0))
38
- .catch(() => 0)
39
- )
40
- const results = await Promise.all(promises)
41
- if (results.reduce(smartSum, 0) >= quorum) {
42
- debug(key, identifier, 'acquired')
43
- return true
44
- } else {
45
- const promises = clients.map(client =>
46
- delIfEqualLua(client, [key, identifier]).catch(() => 0)
47
- )
48
- await Promise.all(promises)
49
- await delay(retryInterval)
50
- }
51
- }
52
- debug(key, identifier, 'timeout or reach limit')
53
- return false
54
- }
@@ -1,53 +0,0 @@
1
- import createDebug from 'debug'
2
- import { expireIfEqualLua } from '../mutex/refresh'
3
- import { delIfEqualLua } from '../mutex/release'
4
- import { RedisClient } from '../types'
5
- import { getQuorum, smartSum } from '../utils/redlock'
6
-
7
- const debug = createDebug('redis-semaphore:redlock-mutex:refresh')
8
-
9
- export async function refreshRedlockMutex(
10
- clients: RedisClient[],
11
- key: string,
12
- identifier: string,
13
- lockTimeout: number
14
- ): Promise<boolean> {
15
- debug(key, identifier)
16
- const quorum = getQuorum(clients.length)
17
- const promises = clients.map(client =>
18
- expireIfEqualLua(client, [key, identifier, lockTimeout])
19
- .then(result => +result)
20
- .catch(() => 0)
21
- )
22
- const results = await Promise.all(promises)
23
- debug('results', results)
24
- const refreshedCount = results.reduce(smartSum, 0)
25
- if (refreshedCount >= quorum) {
26
- debug(key, identifier, 'refreshed')
27
- if (refreshedCount < clients.length) {
28
- debug(key, identifier, 'try to acquire on failed nodes')
29
- const promises = results
30
- .reduce<RedisClient[]>((failedClients, result, index) => {
31
- if (!result) {
32
- failedClients.push(clients[index])
33
- }
34
- return failedClients
35
- }, [])
36
- .map(client =>
37
- client
38
- .set(key, identifier, 'PX', lockTimeout, 'NX')
39
- .then(result => (result === 'OK' ? 1 : 0))
40
- .catch(() => 0)
41
- )
42
- const acquireResults = await Promise.all(promises)
43
- debug(key, identifier, 'acquire on failed nodes results', acquireResults)
44
- }
45
- return true
46
- } else {
47
- const promises = clients.map(client =>
48
- delIfEqualLua(client, [key, identifier]).catch(() => 0)
49
- )
50
- await Promise.all(promises)
51
- return false
52
- }
53
- }
@@ -1,19 +0,0 @@
1
- import createDebug from 'debug'
2
- import { delIfEqualLua } from '../mutex/release'
3
-
4
- import type { RedisClient } from '../types'
5
-
6
- const debug = createDebug('redis-semaphore:redlock-mutex:release')
7
-
8
- export async function releaseRedlockMutex(
9
- clients: RedisClient[],
10
- key: string,
11
- identifier: string
12
- ): Promise<void> {
13
- debug(key, identifier)
14
- const promises = clients.map(client =>
15
- delIfEqualLua(client, [key, identifier]).catch(() => 0)
16
- )
17
- const results = await Promise.all(promises)
18
- debug('results', results)
19
- }
@@ -1,55 +0,0 @@
1
- import createDebug from 'debug'
2
- import { acquireLua } from '../semaphore/acquire/lua'
3
- import { RedisClient } from '../types'
4
- import { delay } from '../utils'
5
- import { getQuorum, smartSum } from '../utils/redlock'
6
-
7
- const debug = createDebug('redis-semaphore:redlock-semaphore:acquire')
8
-
9
- export interface Options {
10
- identifier: string
11
- lockTimeout: number
12
- acquireTimeout: number
13
- acquireAttemptsLimit: number
14
- retryInterval: number
15
- }
16
-
17
- export async function acquireRedlockSemaphore(
18
- clients: RedisClient[],
19
- key: string,
20
- limit: number,
21
- options: Options
22
- ): Promise<boolean> {
23
- const {
24
- identifier,
25
- lockTimeout,
26
- acquireTimeout,
27
- acquireAttemptsLimit,
28
- retryInterval
29
- } = options
30
- let attempt = 0
31
- const end = Date.now() + acquireTimeout
32
- const quorum = getQuorum(clients.length)
33
- let now: number
34
- while ((now = Date.now()) < end && ++attempt <= acquireAttemptsLimit) {
35
- debug(key, identifier, 'attempt', attempt)
36
- const promises = clients.map(client =>
37
- acquireLua(client, [key, limit, identifier, lockTimeout, now])
38
- .then(result => +result)
39
- .catch(() => 0)
40
- )
41
- const results = await Promise.all(promises)
42
- if (results.reduce(smartSum, 0) >= quorum) {
43
- debug(key, identifier, 'acquired')
44
- return true
45
- } else {
46
- const promises = clients.map(client =>
47
- client.zrem(key, identifier).catch(() => 0)
48
- )
49
- await Promise.all(promises)
50
- await delay(retryInterval)
51
- }
52
- }
53
- debug(key, identifier, 'timeout or reach limit')
54
- return false
55
- }
@@ -1,60 +0,0 @@
1
- import createDebug from 'debug'
2
- import { acquireLua } from '../semaphore/acquire/lua'
3
- import { refreshLua } from '../semaphore/refresh/lua'
4
- import { getQuorum, smartSum } from '../utils/redlock'
5
-
6
- import type { RedisClient } from '../types'
7
-
8
- const debug = createDebug('redis-semaphore:redlock-semaphore:refresh')
9
-
10
- interface Options {
11
- identifier: string
12
- lockTimeout: number
13
- }
14
-
15
- export async function refreshRedlockSemaphore(
16
- clients: RedisClient[],
17
- key: string,
18
- limit: number,
19
- options: Options
20
- ): Promise<boolean> {
21
- const { identifier, lockTimeout } = options
22
- const now = Date.now()
23
- debug(key, identifier, now)
24
- const quorum = getQuorum(clients.length)
25
- const promises = clients.map(client =>
26
- refreshLua(client, [key, limit, identifier, lockTimeout, now])
27
- .then(result => +result)
28
- .catch(() => 0)
29
- )
30
- const results = await Promise.all(promises)
31
- debug('results', results)
32
- const refreshedCount = results.reduce(smartSum, 0)
33
- if (refreshedCount >= quorum) {
34
- debug(key, identifier, 'refreshed')
35
- if (refreshedCount < clients.length) {
36
- debug(key, identifier, 'try to acquire on failed nodes')
37
- const promises = results
38
- .reduce<RedisClient[]>((failedClients, result, index) => {
39
- if (!result) {
40
- failedClients.push(clients[index])
41
- }
42
- return failedClients
43
- }, [])
44
- .map(client =>
45
- acquireLua(client, [key, limit, identifier, lockTimeout, now])
46
- .then(result => +result)
47
- .catch(() => 0)
48
- )
49
- const acquireResults = await Promise.all(promises)
50
- debug(key, identifier, 'acquire on failed nodes results', acquireResults)
51
- }
52
- return true
53
- } else {
54
- const promises = clients.map(client =>
55
- client.zrem(key, identifier).catch(() => 0)
56
- )
57
- await Promise.all(promises)
58
- return false
59
- }
60
- }
@@ -1,18 +0,0 @@
1
- import createDebug from 'debug'
2
-
3
- import type { RedisClient } from '../types'
4
-
5
- const debug = createDebug('redis-semaphore:redlock-mutex:release')
6
-
7
- export async function releaseRedlockSemaphore(
8
- clients: RedisClient[],
9
- key: string,
10
- identifier: string
11
- ): Promise<void> {
12
- debug(key, identifier)
13
- const promises = clients.map(client =>
14
- client.zrem(key, identifier).catch(() => 0)
15
- )
16
- const results = await Promise.all(promises)
17
- debug('results', results)
18
- }
@@ -1,52 +0,0 @@
1
- import createDebug from 'debug'
2
- import { RedisClient } from '../../types'
3
- import { delay } from '../../utils'
4
- import { acquireLua } from './lua'
5
-
6
- const debug = createDebug('redis-semaphore:semaphore:acquire')
7
-
8
- export interface Options {
9
- identifier: string
10
- lockTimeout: number
11
- acquireTimeout: number
12
- acquireAttemptsLimit: number
13
- retryInterval: number
14
- }
15
-
16
- export async function acquireSemaphore(
17
- client: RedisClient,
18
- key: string,
19
- limit: number,
20
- options: Options
21
- ): Promise<boolean> {
22
- const {
23
- identifier,
24
- lockTimeout,
25
- acquireTimeout,
26
- acquireAttemptsLimit,
27
- retryInterval
28
- } = options
29
- let attempt = 0
30
- const end = Date.now() + acquireTimeout
31
- let now
32
- while ((now = Date.now()) < end && ++attempt <= acquireAttemptsLimit) {
33
- debug(key, identifier, limit, lockTimeout, 'attempt', attempt)
34
- const result = await acquireLua(client, [
35
- key,
36
- limit,
37
- identifier,
38
- lockTimeout,
39
- now
40
- ])
41
- debug(key, 'result', typeof result, result)
42
- // support options.stringNumbers
43
- if (+result === 1) {
44
- debug(key, identifier, 'acquired')
45
- return true
46
- } else {
47
- await delay(retryInterval)
48
- }
49
- }
50
- debug(key, identifier, limit, lockTimeout, 'timeout or reach limit')
51
- return false
52
- }
@@ -1,25 +0,0 @@
1
- import { createEval } from '../../utils/index'
2
-
3
- export const acquireLua = createEval<
4
- [string, number, string, number, number],
5
- 0 | 1
6
- >(
7
- `
8
- local key = KEYS[1]
9
- local limit = tonumber(ARGV[1])
10
- local identifier = ARGV[2]
11
- local lockTimeout = tonumber(ARGV[3])
12
- local now = tonumber(ARGV[4])
13
- local expiredTimestamp = now - lockTimeout
14
-
15
- redis.call('zremrangebyscore', key, '-inf', expiredTimestamp)
16
-
17
- if redis.call('zcard', key) < limit then
18
- redis.call('zadd', key, now, identifier)
19
- redis.call('pexpire', key, lockTimeout)
20
- return 1
21
- else
22
- return 0
23
- end`,
24
- 1
25
- )
@@ -1,31 +0,0 @@
1
- import createDebug from 'debug'
2
- import { RedisClient } from '../../types'
3
- import { refreshLua } from './lua'
4
-
5
- const debug = createDebug('redis-semaphore:semaphore:refresh')
6
-
7
- export interface Options {
8
- identifier: string
9
- lockTimeout: number
10
- }
11
-
12
- export async function refreshSemaphore(
13
- client: RedisClient,
14
- key: string,
15
- limit: number,
16
- options: Options
17
- ): Promise<boolean> {
18
- const { identifier, lockTimeout } = options
19
- const now = Date.now()
20
- debug(key, identifier, now)
21
- const result = await refreshLua(client, [
22
- key,
23
- limit,
24
- identifier,
25
- lockTimeout,
26
- now
27
- ])
28
- debug('result', typeof result, result)
29
- // support options.stringNumbers
30
- return +result === 1
31
- }