bullmq 3.13.4 → 3.14.1

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 (92) hide show
  1. package/dist/cjs/classes/job.js +1 -1
  2. package/dist/cjs/classes/worker.js.map +1 -1
  3. package/dist/cjs/commands/addJob-8.lua +2 -2
  4. package/dist/cjs/commands/changeDelay-3.lua +2 -3
  5. package/dist/cjs/commands/getRanges-1.lua +1 -1
  6. package/dist/cjs/commands/includes/addDelayMarkerIfNeeded.lua +3 -3
  7. package/dist/cjs/commands/includes/cleanSet.lua +2 -2
  8. package/dist/cjs/commands/includes/getRateLimitTTL.lua +1 -1
  9. package/dist/cjs/commands/includes/promoteDelayedJobs.lua +4 -9
  10. package/dist/cjs/commands/includes/updateParentDepsIfNeeded.lua +0 -1
  11. package/dist/cjs/commands/isFinished-3.lua +3 -3
  12. package/dist/cjs/commands/moveToActive-9.lua +51 -46
  13. package/dist/cjs/commands/moveToDelayed-8.lua +22 -23
  14. package/dist/cjs/commands/moveToFinished-12.lua +3 -1
  15. package/dist/cjs/commands/pause-4.lua +8 -8
  16. package/dist/cjs/commands/promote-6.lua +7 -3
  17. package/dist/cjs/commands/removeRepeatable-2.lua +3 -0
  18. package/dist/cjs/commands/reprocessJob-6.lua +1 -1
  19. package/dist/cjs/commands/retryJob-8.lua +4 -5
  20. package/dist/cjs/commands/saveStacktrace-1.lua +2 -3
  21. package/dist/cjs/commands/updateData-1.lua +6 -2
  22. package/dist/cjs/commands/updateProgress-2.lua +6 -2
  23. package/dist/cjs/scripts/addJob-8.js +5 -5
  24. package/dist/cjs/scripts/changeDelay-3.js +2 -2
  25. package/dist/cjs/scripts/getRanges-1.js +1 -1
  26. package/dist/cjs/scripts/isFinished-3.js +3 -3
  27. package/dist/cjs/scripts/moveToActive-9.js +76 -76
  28. package/dist/cjs/scripts/moveToDelayed-8.js +29 -32
  29. package/dist/cjs/scripts/moveToDelayed-8.js.map +1 -1
  30. package/dist/cjs/scripts/moveToFinished-12.js +21 -23
  31. package/dist/cjs/scripts/moveToFinished-12.js.map +1 -1
  32. package/dist/cjs/scripts/pause-4.js +8 -8
  33. package/dist/cjs/scripts/promote-6.js +6 -3
  34. package/dist/cjs/scripts/promote-6.js.map +1 -1
  35. package/dist/cjs/scripts/removeRepeatable-2.js +2 -0
  36. package/dist/cjs/scripts/removeRepeatable-2.js.map +1 -1
  37. package/dist/cjs/scripts/reprocessJob-6.js +1 -1
  38. package/dist/cjs/scripts/retryJob-8.js +7 -10
  39. package/dist/cjs/scripts/retryJob-8.js.map +1 -1
  40. package/dist/cjs/scripts/saveStacktrace-1.js +1 -1
  41. package/dist/cjs/scripts/updateData-1.js +4 -1
  42. package/dist/cjs/scripts/updateData-1.js.map +1 -1
  43. package/dist/cjs/scripts/updateProgress-2.js +3 -0
  44. package/dist/cjs/scripts/updateProgress-2.js.map +1 -1
  45. package/dist/cjs/tsconfig-cjs.tsbuildinfo +1 -1
  46. package/dist/esm/classes/job.js +1 -1
  47. package/dist/esm/classes/worker.d.ts +2 -2
  48. package/dist/esm/classes/worker.js.map +1 -1
  49. package/dist/esm/commands/addJob-8.lua +2 -2
  50. package/dist/esm/commands/changeDelay-3.lua +2 -3
  51. package/dist/esm/commands/getRanges-1.lua +1 -1
  52. package/dist/esm/commands/includes/addDelayMarkerIfNeeded.lua +3 -3
  53. package/dist/esm/commands/includes/cleanSet.lua +2 -2
  54. package/dist/esm/commands/includes/getRateLimitTTL.lua +1 -1
  55. package/dist/esm/commands/includes/promoteDelayedJobs.lua +4 -9
  56. package/dist/esm/commands/includes/updateParentDepsIfNeeded.lua +0 -1
  57. package/dist/esm/commands/isFinished-3.lua +3 -3
  58. package/dist/esm/commands/moveToActive-9.lua +51 -46
  59. package/dist/esm/commands/moveToDelayed-8.lua +22 -23
  60. package/dist/esm/commands/moveToFinished-12.lua +3 -1
  61. package/dist/esm/commands/pause-4.lua +8 -8
  62. package/dist/esm/commands/promote-6.lua +7 -3
  63. package/dist/esm/commands/removeRepeatable-2.lua +3 -0
  64. package/dist/esm/commands/reprocessJob-6.lua +1 -1
  65. package/dist/esm/commands/retryJob-8.lua +4 -5
  66. package/dist/esm/commands/saveStacktrace-1.lua +2 -3
  67. package/dist/esm/commands/updateData-1.lua +6 -2
  68. package/dist/esm/commands/updateProgress-2.lua +6 -2
  69. package/dist/esm/scripts/addJob-8.js +5 -5
  70. package/dist/esm/scripts/changeDelay-3.js +2 -2
  71. package/dist/esm/scripts/getRanges-1.js +1 -1
  72. package/dist/esm/scripts/isFinished-3.js +3 -3
  73. package/dist/esm/scripts/moveToActive-9.js +76 -76
  74. package/dist/esm/scripts/moveToDelayed-8.js +29 -32
  75. package/dist/esm/scripts/moveToDelayed-8.js.map +1 -1
  76. package/dist/esm/scripts/moveToFinished-12.js +21 -23
  77. package/dist/esm/scripts/moveToFinished-12.js.map +1 -1
  78. package/dist/esm/scripts/pause-4.js +8 -8
  79. package/dist/esm/scripts/promote-6.js +6 -3
  80. package/dist/esm/scripts/promote-6.js.map +1 -1
  81. package/dist/esm/scripts/removeRepeatable-2.js +2 -0
  82. package/dist/esm/scripts/removeRepeatable-2.js.map +1 -1
  83. package/dist/esm/scripts/reprocessJob-6.js +1 -1
  84. package/dist/esm/scripts/retryJob-8.js +7 -10
  85. package/dist/esm/scripts/retryJob-8.js.map +1 -1
  86. package/dist/esm/scripts/saveStacktrace-1.js +1 -1
  87. package/dist/esm/scripts/updateData-1.js +4 -1
  88. package/dist/esm/scripts/updateData-1.js.map +1 -1
  89. package/dist/esm/scripts/updateProgress-2.js +3 -0
  90. package/dist/esm/scripts/updateProgress-2.js.map +1 -1
  91. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  92. package/package.json +1 -1
@@ -7,29 +7,29 @@
7
7
  so that no other worker picks this job again.
8
8
 
9
9
  Input:
10
- KEYS[1] wait key
11
- KEYS[2] active key
12
- KEYS[3] priority key
13
- KEYS[4] stream events key
14
- KEYS[5] stalled key
10
+ KEYS[1] wait key
11
+ KEYS[2] active key
12
+ KEYS[3] priority key
13
+ KEYS[4] stream events key
14
+ KEYS[5] stalled key
15
15
 
16
- -- Rate limiting
17
- KEYS[6] rate limiter key
18
- KEYS[7] delayed key
16
+ -- Rate limiting
17
+ KEYS[6] rate limiter key
18
+ KEYS[7] delayed key
19
19
 
20
- -- Promote delayed jobs
21
- KEYS[8] paused key
22
- KEYS[9] meta key
20
+ -- Promote delayed jobs
21
+ KEYS[8] paused key
22
+ KEYS[9] meta key
23
23
 
24
- -- Arguments
25
- ARGV[1] key prefix
26
- ARGV[2] timestamp
27
- ARGV[3] optional job ID
28
- ARGV[4] opts
24
+ -- Arguments
25
+ ARGV[1] key prefix
26
+ ARGV[2] timestamp
27
+ ARGV[3] optional job ID
28
+ ARGV[4] opts
29
29
 
30
- opts - token - lock token
31
- opts - lockDuration
32
- opts - limiter
30
+ opts - token - lock token
31
+ opts - lockDuration
32
+ opts - limiter
33
33
  ]]
34
34
  local jobId
35
35
  local rcall = redis.call
@@ -37,47 +37,52 @@ local rcall = redis.call
37
37
  -- Includes
38
38
  --- @include "includes/moveJobFromWaitToActive"
39
39
  --- @include "includes/getNextDelayedTimestamp"
40
- --- @include "includes/promoteDelayedJobs"
41
40
  --- @include "includes/getRateLimitTTL"
41
+ --- @include "includes/getTargetQueueList"
42
+ --- @include "includes/promoteDelayedJobs"
43
+
44
+ local target = getTargetQueueList(KEYS[9], KEYS[1], KEYS[8])
42
45
 
43
46
  -- Check if there are delayed jobs that we can move to wait.
44
- promoteDelayedJobs(KEYS[7], KEYS[1], KEYS[3], KEYS[8], KEYS[9], KEYS[4], ARGV[1], ARGV[2])
47
+ promoteDelayedJobs(KEYS[7], target, KEYS[3], KEYS[4], ARGV[1], ARGV[2])
45
48
 
46
49
  local opts
47
50
  if (ARGV[3] ~= "") then
48
- jobId = ARGV[3]
49
- -- clean stalled key
50
- rcall("SREM", KEYS[5], jobId)
51
+ jobId = ARGV[3]
52
+ -- clean stalled key
53
+ rcall("SREM", KEYS[5], jobId)
51
54
  else
52
- -- Check if we are rate limited first.
53
- opts = cmsgpack.unpack(ARGV[4])
54
- local pttl = getRateLimitTTL(opts, KEYS[6])
55
- if pttl > 0 then
56
- return { 0, 0, pttl }
57
- end
55
+ -- Check if we are rate limited first.
56
+ opts = cmsgpack.unpack(ARGV[4])
57
+ local pttl = getRateLimitTTL(opts, KEYS[6])
58
+ if pttl > 0 then
59
+ return { 0, 0, pttl }
60
+ end
58
61
 
59
- -- no job ID, try non-blocking move from wait to active
60
- jobId = rcall("RPOPLPUSH", KEYS[1], KEYS[2])
62
+ -- no job ID, try non-blocking move from wait to active
63
+ jobId = rcall("RPOPLPUSH", KEYS[1], KEYS[2])
61
64
  end
62
65
 
63
66
  -- If jobId is special ID 0:delay, then there is no job to process
64
- if jobId then
65
- if string.sub(jobId, 1, 2) == "0:" then
66
- rcall("LREM", KEYS[2], 1, jobId)
67
- -- Move again since we just got the marker job.
68
- jobId = rcall("RPOPLPUSH", KEYS[1], KEYS[2])
67
+ if jobId then
68
+ if string.sub(jobId, 1, 2) == "0:" then
69
+ rcall("LREM", KEYS[2], 1, jobId)
70
+ -- Move again since we just got the marker job.
71
+ jobId = rcall("RPOPLPUSH", KEYS[1], KEYS[2])
69
72
 
70
- if jobId and string.sub(jobId, 1, 2) == "0:" then
71
- rcall("LREM", KEYS[2], 1, jobId)
72
- jobId = nil
73
- end
73
+ -- Since it is possible that between a call to BRPOPLPUSH and moveToActive
74
+ -- another script puts a new maker in wait, we need to check again.
75
+ if jobId and string.sub(jobId, 1, 2) == "0:" then
76
+ rcall("LREM", KEYS[2], 1, jobId)
77
+ jobId = rcall("RPOPLPUSH", KEYS[1], KEYS[2])
74
78
  end
79
+ end
75
80
 
76
- if jobId then
77
- opts = opts or cmsgpack.unpack(ARGV[4])
78
- -- this script is not really moving, it is preparing the job for processing
79
- return moveJobFromWaitToActive(KEYS, ARGV[1], jobId, ARGV[2], opts)
80
- end
81
+ if jobId then
82
+ opts = opts or cmsgpack.unpack(ARGV[4])
83
+ -- this script is not really moving, it is preparing the job for processing
84
+ return moveJobFromWaitToActive(KEYS, ARGV[1], jobId, ARGV[2], opts)
85
+ end
81
86
  end
82
87
 
83
88
  -- Return the timestamp for the next delayed job if any.
@@ -35,34 +35,33 @@ local rcall = redis.call
35
35
 
36
36
  local jobKey = KEYS[5]
37
37
  if rcall("EXISTS", jobKey) == 1 then
38
-
39
- local delayedKey = KEYS[4]
40
- if ARGV[5] ~= "0" then
41
- local lockKey = jobKey .. ':lock'
42
- if rcall("GET", lockKey) == ARGV[5] then
43
- rcall("DEL", lockKey)
44
- else
45
- return -2
46
- end
38
+ local delayedKey = KEYS[4]
39
+ if ARGV[5] ~= "0" then
40
+ local lockKey = jobKey .. ':lock'
41
+ if rcall("GET", lockKey) == ARGV[5] then
42
+ rcall("DEL", lockKey)
43
+ else
44
+ return -2
47
45
  end
46
+ end
48
47
 
49
- local jobId = ARGV[4]
50
- local score = tonumber(ARGV[3])
51
- local delayedTimestamp = (score / 0x1000)
48
+ local jobId = ARGV[4]
49
+ local score = tonumber(ARGV[3])
50
+ local delayedTimestamp = (score / 0x1000)
52
51
 
53
- local numRemovedElements = rcall("LREM", KEYS[2], -1, jobId)
54
- if (numRemovedElements < 1) then
55
- return -3
56
- end
52
+ local numRemovedElements = rcall("LREM", KEYS[2], -1, jobId)
53
+ if numRemovedElements < 1 then
54
+ return -3
55
+ end
57
56
 
58
- rcall("ZADD", delayedKey, score, jobId)
59
- rcall("XADD", KEYS[6], "*", "event", "delayed", "jobId", jobId, "delay", delayedTimestamp)
57
+ rcall("ZADD", delayedKey, score, jobId)
58
+ rcall("XADD", KEYS[6], "*", "event", "delayed", "jobId", jobId, "delay", delayedTimestamp)
60
59
 
61
- -- Check if we need to push a marker job to wake up sleeping workers.
62
- local target = getTargetQueueList(KEYS[8], KEYS[1], KEYS[7])
63
- addDelayMarkerIfNeeded(target, delayedKey)
60
+ -- Check if we need to push a marker job to wake up sleeping workers.
61
+ local target = getTargetQueueList(KEYS[8], KEYS[1], KEYS[7])
62
+ addDelayMarkerIfNeeded(target, delayedKey)
64
63
 
65
- return 0
64
+ return 0
66
65
  else
67
- return -1
66
+ return -1
68
67
  end
@@ -186,8 +186,10 @@ if rcall("EXISTS", jobIdKey) == 1 then -- // Make sure job exists
186
186
  -- and not rate limited.
187
187
  if (ARGV[7] == "1") then
188
188
 
189
+ local target = getTargetQueueList(KEYS[11], KEYS[1], KEYS[8])
190
+
189
191
  -- Check if there are delayed jobs that can be promoted
190
- promoteDelayedJobs(KEYS[7], KEYS[1], KEYS[3], KEYS[8], KEYS[11],
192
+ promoteDelayedJobs(KEYS[7], target, KEYS[3],
191
193
  KEYS[4], ARGV[8], timestamp)
192
194
 
193
195
  -- Check if we are rate limited first.
@@ -1,16 +1,16 @@
1
1
  --[[
2
2
  Pauses or resumes a queue globably.
3
3
 
4
- Input:
5
- KEYS[1] 'wait' or 'paused''
6
- KEYS[2] 'paused' or 'wait'
7
- KEYS[3] 'meta'
8
- KEYS[4] events stream key
4
+ Input:
5
+ KEYS[1] 'wait' or 'paused''
6
+ KEYS[2] 'paused' or 'wait'
7
+ KEYS[3] 'meta'
8
+ KEYS[4] events stream key
9
9
 
10
- ARGV[1] 'paused' or 'resumed'
10
+ ARGV[1] 'paused' or 'resumed'
11
11
 
12
- Event:
13
- publish paused or resumed event.
12
+ Event:
13
+ publish paused or resumed event.
14
14
  ]]
15
15
  local rcall = redis.call
16
16
 
@@ -1,7 +1,7 @@
1
1
  --[[
2
2
  Promotes a job that is currently "delayed" to the "waiting" state
3
3
 
4
- Input:
4
+ Input:
5
5
  KEYS[1] 'delayed'
6
6
  KEYS[2] 'wait'
7
7
  KEYS[3] 'paused'
@@ -12,10 +12,14 @@
12
12
  ARGV[1] queue.toKey('')
13
13
  ARGV[2] jobId
14
14
 
15
- Events:
15
+ Output:
16
+ 0 - OK
17
+ -3 - Job not in delayed zset.
18
+
19
+ Events:
16
20
  'waiting'
17
21
  ]]
18
- local rcall = redis.call;
22
+ local rcall = redis.call
19
23
  local jobId = ARGV[2]
20
24
 
21
25
  -- Includes
@@ -12,6 +12,9 @@
12
12
  Output:
13
13
  0 - OK
14
14
  1 - Missing repeat job
15
+
16
+ Events:
17
+ 'removed'
15
18
  ]]
16
19
  local rcall = redis.call
17
20
  local millis = rcall("ZSCORE", KEYS[1], ARGV[2])
@@ -15,7 +15,7 @@
15
15
  ARGV[4] prev state - failed/completed
16
16
 
17
17
  Output:
18
- 1 means the operation was a success
18
+ 1 means the operation was a success
19
19
  -1 means the job does not exist
20
20
  -3 means the job was not found in the expected set.
21
21
  ]]
@@ -31,7 +31,8 @@ local rcall = redis.call
31
31
  --- @include "includes/getTargetQueueList"
32
32
  --- @include "includes/promoteDelayedJobs"
33
33
 
34
- promoteDelayedJobs(KEYS[7], KEYS[2], KEYS[8], KEYS[3], KEYS[5], KEYS[6], ARGV[1], ARGV[2])
34
+ local target = getTargetQueueList(KEYS[5], KEYS[2], KEYS[3])
35
+ promoteDelayedJobs(KEYS[7], target, KEYS[8], KEYS[6], ARGV[1], ARGV[2])
35
36
 
36
37
  if rcall("EXISTS", KEYS[4]) == 1 then
37
38
 
@@ -44,14 +45,12 @@ if rcall("EXISTS", KEYS[4]) == 1 then
44
45
  end
45
46
  end
46
47
 
47
- local target = getTargetQueueList(KEYS[5], KEYS[2], KEYS[3])
48
-
49
48
  rcall("LREM", KEYS[1], 0, ARGV[4])
50
49
  rcall(ARGV[3], target, ARGV[4])
51
50
 
52
51
  -- Emit waiting event
53
- rcall("XADD", KEYS[6], "*", "event", "waiting", "jobId", ARGV[4], "prev", "failed");
54
-
52
+ rcall("XADD", KEYS[6], "*", "event", "waiting", "jobId", ARGV[4], "prev", "failed")
53
+
55
54
  return 0
56
55
  else
57
56
  return -1
@@ -8,15 +8,14 @@
8
8
  ARGV[2] failedReason
9
9
 
10
10
  Output:
11
- 0 - OK
11
+ 0 - OK
12
12
  -1 - Missing key
13
13
  ]]
14
14
  local rcall = redis.call
15
15
 
16
16
  if rcall("EXISTS", KEYS[1]) == 1 then
17
-
18
17
  rcall("HMSET", KEYS[1], "stacktrace", ARGV[1], "failedReason", ARGV[2])
19
-
18
+
20
19
  return 0
21
20
  else
22
21
  return -1
@@ -3,8 +3,12 @@
3
3
 
4
4
  Input:
5
5
  KEYS[1] Job id key
6
-
7
- ARGV[1] data
6
+
7
+ ARGV[1] data
8
+
9
+ Output:
10
+ 0 - OK
11
+ -1 - Missing job.
8
12
  ]]
9
13
  local rcall = redis.call
10
14
 
@@ -4,10 +4,14 @@
4
4
  Input:
5
5
  KEYS[1] Job id key
6
6
  KEYS[2] event stream key
7
-
7
+
8
8
  ARGV[1] id
9
9
  ARGV[2] progress
10
-
10
+
11
+ Output:
12
+ 0 - OK
13
+ -1 - Missing job.
14
+
11
15
  Event:
12
16
  progress(jobId, progress)
13
17
  ]]
@@ -65,11 +65,11 @@ local function getNextDelayedTimestamp(delayedKey)
65
65
  return nextTimestamp
66
66
  end
67
67
  end
68
- local function addDelayMarkerIfNeeded(target, delayedKey)
69
- if rcall("LLEN", target) == 0 then
68
+ local function addDelayMarkerIfNeeded(targetKey, delayedKey)
69
+ if rcall("LLEN", targetKey) == 0 then
70
70
  local nextTimestamp = getNextDelayedTimestamp(delayedKey)
71
71
  if nextTimestamp ~= nil then
72
- rcall("LPUSH", target, "0:" .. nextTimestamp)
72
+ rcall("LPUSH", targetKey, "0:" .. nextTimestamp)
73
73
  end
74
74
  end
75
75
  end
@@ -172,7 +172,7 @@ else
172
172
  end
173
173
  rcall("XADD", KEYS[8], "*", "event", "duplicated", "jobId", jobId)
174
174
  return jobId .. "" -- convert to string
175
- end
175
+ end
176
176
  end
177
177
  -- Store the job.
178
178
  local jsonOpts = cjson.encode(opts)
@@ -213,7 +213,7 @@ else
213
213
  -- Standard or priority add
214
214
  if priority == 0 then
215
215
  -- LIFO or FIFO
216
- local pushCmd = opts['lifo'] and 'RPUSH' or 'LPUSH';
216
+ local pushCmd = opts['lifo'] and 'RPUSH' or 'LPUSH'
217
217
  rcall(pushCmd, target, jobId)
218
218
  else
219
219
  -- Priority add
@@ -20,12 +20,12 @@ if rcall("EXISTS", KEYS[2]) == 1 then
20
20
  local score = tonumber(ARGV[2])
21
21
  local delayedTimestamp = (score / 0x1000)
22
22
  local numRemovedElements = rcall("ZREM", KEYS[1], jobId)
23
- if (numRemovedElements < 1) then
23
+ if numRemovedElements < 1 then
24
24
  return -3
25
25
  end
26
26
  rcall("HSET", KEYS[2], "delay", tonumber(ARGV[1]))
27
27
  rcall("ZADD", KEYS[1], score, jobId)
28
- rcall("XADD", KEYS[3], "*", "event", "delayed", "jobId", jobId, "delay", delayedTimestamp);
28
+ rcall("XADD", KEYS[3], "*", "event", "delayed", "jobId", jobId, "delay", delayedTimestamp)
29
29
  return 0
30
30
  else
31
31
  return -1
@@ -7,7 +7,7 @@ const content = `--[[
7
7
  ARGV[3] asc
8
8
  ARGV[4...] types
9
9
  ]]
10
- local rcall = redis.call;
10
+ local rcall = redis.call
11
11
  local prefix = KEYS[1]
12
12
  local rangeStart = tonumber(ARGV[1])
13
13
  local rangeEnd = tonumber(ARGV[2])
@@ -10,14 +10,14 @@ const content = `--[[
10
10
  0 - Not finished.
11
11
  1 - Completed.
12
12
  2 - Failed.
13
- -5 - Missing job.
13
+ -1 - Missing job.
14
14
  ]]
15
15
  local rcall = redis.call
16
16
  if rcall("EXISTS", KEYS[3]) ~= 1 then
17
17
  if ARGV[2] == "1" then
18
- return {-5,"Missing key for job " .. KEYS[3] .. ". isFinished"}
18
+ return {-1,"Missing key for job " .. KEYS[3] .. ". isFinished"}
19
19
  end
20
- return -5
20
+ return -1
21
21
  end
22
22
  if rcall("ZSCORE", KEYS[1], ARGV[1]) ~= false then
23
23
  if ARGV[2] == "1" then
@@ -5,25 +5,25 @@ const content = `--[[
5
5
  expiration time. The worker is responsible of keeping the lock fresh
6
6
  so that no other worker picks this job again.
7
7
  Input:
8
- KEYS[1] wait key
9
- KEYS[2] active key
10
- KEYS[3] priority key
11
- KEYS[4] stream events key
12
- KEYS[5] stalled key
13
- -- Rate limiting
14
- KEYS[6] rate limiter key
15
- KEYS[7] delayed key
16
- -- Promote delayed jobs
17
- KEYS[8] paused key
18
- KEYS[9] meta key
19
- -- Arguments
20
- ARGV[1] key prefix
21
- ARGV[2] timestamp
22
- ARGV[3] optional job ID
23
- ARGV[4] opts
24
- opts - token - lock token
25
- opts - lockDuration
26
- opts - limiter
8
+ KEYS[1] wait key
9
+ KEYS[2] active key
10
+ KEYS[3] priority key
11
+ KEYS[4] stream events key
12
+ KEYS[5] stalled key
13
+ -- Rate limiting
14
+ KEYS[6] rate limiter key
15
+ KEYS[7] delayed key
16
+ -- Promote delayed jobs
17
+ KEYS[8] paused key
18
+ KEYS[9] meta key
19
+ -- Arguments
20
+ ARGV[1] key prefix
21
+ ARGV[2] timestamp
22
+ ARGV[3] optional job ID
23
+ ARGV[4] opts
24
+ opts - token - lock token
25
+ opts - lockDuration
26
+ opts - limiter
27
27
  ]]
28
28
  local jobId
29
29
  local rcall = redis.call
@@ -93,13 +93,36 @@ local function getNextDelayedTimestamp(delayedKey)
93
93
  return nextTimestamp
94
94
  end
95
95
  end
96
+ local function getRateLimitTTL(opts, limiterKey)
97
+ local maxJobs = tonumber(opts['limiter'] and opts['limiter']['max'])
98
+ if maxJobs then
99
+ local jobCounter = tonumber(rcall("GET", limiterKey))
100
+ if jobCounter ~= nil and jobCounter >= maxJobs then
101
+ local pttl = rcall("PTTL", limiterKey)
102
+ if pttl > 0 then
103
+ return pttl
104
+ end
105
+ end
106
+ end
107
+ return 0
108
+ end
109
+ --[[
110
+ Function to check for the meta.paused key to decide if we are paused or not
111
+ (since an empty list and !EXISTS are not really the same).
112
+ ]]
113
+ local function getTargetQueueList(queueMetaKey, waitKey, pausedKey)
114
+ if rcall("HEXISTS", queueMetaKey, "paused") ~= 1 then
115
+ return waitKey
116
+ else
117
+ return pausedKey
118
+ end
119
+ end
96
120
  --[[
97
121
  Updates the delay set, by moving delayed jobs that should
98
122
  be processed now to "wait".
99
123
  Events:
100
124
  'waiting'
101
125
  ]]
102
- local rcall = redis.call
103
126
  -- Includes
104
127
  --[[
105
128
  Function to add job considering priority.
@@ -115,33 +138,20 @@ local function addJobWithPriority(priorityKey, priority, targetKey, jobId)
115
138
  rcall("RPUSH", targetKey, jobId)
116
139
  end
117
140
  end
118
- --[[
119
- Function to check for the meta.paused key to decide if we are paused or not
120
- (since an empty list and !EXISTS are not really the same).
121
- ]]
122
- local function getTargetQueueList(queueMetaKey, waitKey, pausedKey)
123
- if rcall("HEXISTS", queueMetaKey, "paused") ~= 1 then
124
- return waitKey
125
- else
126
- return pausedKey
127
- end
128
- end
129
141
  -- Try to get as much as 1000 jobs at once
130
- local function promoteDelayedJobs(delayedKey, waitKey, priorityKey, pausedKey,
131
- metaKey, eventStreamKey, prefix, timestamp)
142
+ local function promoteDelayedJobs(delayedKey, targetKey, priorityKey,
143
+ eventStreamKey, prefix, timestamp)
132
144
  local jobs = rcall("ZRANGEBYSCORE", delayedKey, 0, (timestamp + 1) * 0x1000, "LIMIT", 0, 1000)
133
145
  if (#jobs > 0) then
134
146
  rcall("ZREM", delayedKey, unpack(jobs))
135
- -- check if we need to use push in paused instead of waiting
136
- local target = getTargetQueueList(metaKey, waitKey, pausedKey)
137
147
  for _, jobId in ipairs(jobs) do
138
148
  local priority =
139
149
  tonumber(rcall("HGET", prefix .. jobId, "priority")) or 0
140
150
  if priority == 0 then
141
151
  -- LIFO or FIFO
142
- rcall("LPUSH", target, jobId)
152
+ rcall("LPUSH", targetKey, jobId)
143
153
  else
144
- addJobWithPriority(priorityKey, priority, target, jobId)
154
+ addJobWithPriority(priorityKey, priority, targetKey, jobId)
145
155
  end
146
156
  -- Emit waiting event
147
157
  rcall("XADD", eventStreamKey, "*", "event", "waiting", "jobId",
@@ -150,52 +160,42 @@ local function promoteDelayedJobs(delayedKey, waitKey, priorityKey, pausedKey,
150
160
  end
151
161
  end
152
162
  end
153
- local function getRateLimitTTL(opts, limiterKey)
154
- local maxJobs = tonumber(opts['limiter'] and opts['limiter']['max'])
155
- if maxJobs then
156
- local jobCounter = tonumber(rcall("GET", limiterKey))
157
- if jobCounter ~= nil and jobCounter >= maxJobs then
158
- local pttl = rcall("PTTL", limiterKey)
159
- if pttl > 0 then
160
- return pttl
161
- end
162
- end
163
- end
164
- return 0
165
- end
163
+ local target = getTargetQueueList(KEYS[9], KEYS[1], KEYS[8])
166
164
  -- Check if there are delayed jobs that we can move to wait.
167
- promoteDelayedJobs(KEYS[7], KEYS[1], KEYS[3], KEYS[8], KEYS[9], KEYS[4], ARGV[1], ARGV[2])
165
+ promoteDelayedJobs(KEYS[7], target, KEYS[3], KEYS[4], ARGV[1], ARGV[2])
168
166
  local opts
169
167
  if (ARGV[3] ~= "") then
170
- jobId = ARGV[3]
171
- -- clean stalled key
172
- rcall("SREM", KEYS[5], jobId)
168
+ jobId = ARGV[3]
169
+ -- clean stalled key
170
+ rcall("SREM", KEYS[5], jobId)
173
171
  else
174
- -- Check if we are rate limited first.
175
- opts = cmsgpack.unpack(ARGV[4])
176
- local pttl = getRateLimitTTL(opts, KEYS[6])
177
- if pttl > 0 then
178
- return { 0, 0, pttl }
179
- end
180
- -- no job ID, try non-blocking move from wait to active
181
- jobId = rcall("RPOPLPUSH", KEYS[1], KEYS[2])
172
+ -- Check if we are rate limited first.
173
+ opts = cmsgpack.unpack(ARGV[4])
174
+ local pttl = getRateLimitTTL(opts, KEYS[6])
175
+ if pttl > 0 then
176
+ return { 0, 0, pttl }
177
+ end
178
+ -- no job ID, try non-blocking move from wait to active
179
+ jobId = rcall("RPOPLPUSH", KEYS[1], KEYS[2])
182
180
  end
183
181
  -- If jobId is special ID 0:delay, then there is no job to process
184
- if jobId then
185
- if string.sub(jobId, 1, 2) == "0:" then
186
- rcall("LREM", KEYS[2], 1, jobId)
187
- -- Move again since we just got the marker job.
188
- jobId = rcall("RPOPLPUSH", KEYS[1], KEYS[2])
189
- if jobId and string.sub(jobId, 1, 2) == "0:" then
190
- rcall("LREM", KEYS[2], 1, jobId)
191
- jobId = nil
192
- end
193
- end
194
- if jobId then
195
- opts = opts or cmsgpack.unpack(ARGV[4])
196
- -- this script is not really moving, it is preparing the job for processing
197
- return moveJobFromWaitToActive(KEYS, ARGV[1], jobId, ARGV[2], opts)
182
+ if jobId then
183
+ if string.sub(jobId, 1, 2) == "0:" then
184
+ rcall("LREM", KEYS[2], 1, jobId)
185
+ -- Move again since we just got the marker job.
186
+ jobId = rcall("RPOPLPUSH", KEYS[1], KEYS[2])
187
+ -- Since it is possible that between a call to BRPOPLPUSH and moveToActive
188
+ -- another script puts a new maker in wait, we need to check again.
189
+ if jobId and string.sub(jobId, 1, 2) == "0:" then
190
+ rcall("LREM", KEYS[2], 1, jobId)
191
+ jobId = rcall("RPOPLPUSH", KEYS[1], KEYS[2])
198
192
  end
193
+ end
194
+ if jobId then
195
+ opts = opts or cmsgpack.unpack(ARGV[4])
196
+ -- this script is not really moving, it is preparing the job for processing
197
+ return moveJobFromWaitToActive(KEYS, ARGV[1], jobId, ARGV[2], opts)
198
+ end
199
199
  end
200
200
  -- Return the timestamp for the next delayed job if any.
201
201
  local nextTimestamp = getNextDelayedTimestamp(KEYS[7])