bullmq 5.53.0 → 5.53.2
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.
- package/dist/cjs/classes/job.js +1 -1
- package/dist/cjs/classes/job.js.map +1 -1
- package/dist/cjs/classes/scripts.js +0 -1
- package/dist/cjs/classes/scripts.js.map +1 -1
- package/dist/cjs/classes/worker.js +1 -21
- package/dist/cjs/classes/worker.js.map +1 -1
- package/dist/cjs/commands/addJobScheduler-11.lua +1 -1
- package/dist/cjs/commands/includes/storeJobScheduler.lua +1 -0
- package/dist/cjs/commands/{moveStalledJobsToWait-9.lua → moveStalledJobsToWait-8.lua} +23 -40
- package/dist/cjs/scripts/addJobScheduler-11.js +2 -1
- package/dist/cjs/scripts/addJobScheduler-11.js.map +1 -1
- package/dist/cjs/scripts/index.js +1 -1
- package/dist/cjs/scripts/moveStalledJobsToWait-8.js +171 -0
- package/dist/cjs/scripts/moveStalledJobsToWait-8.js.map +1 -0
- package/dist/cjs/tsconfig-cjs.tsbuildinfo +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/classes/job.js +1 -1
- package/dist/esm/classes/job.js.map +1 -1
- package/dist/esm/classes/scripts.d.ts +1 -1
- package/dist/esm/classes/scripts.js +0 -1
- package/dist/esm/classes/scripts.js.map +1 -1
- package/dist/esm/classes/worker.d.ts +0 -1
- package/dist/esm/classes/worker.js +1 -21
- package/dist/esm/classes/worker.js.map +1 -1
- package/dist/esm/commands/addJobScheduler-11.lua +1 -1
- package/dist/esm/commands/includes/storeJobScheduler.lua +1 -0
- package/dist/esm/commands/{moveStalledJobsToWait-9.lua → moveStalledJobsToWait-8.lua} +23 -40
- package/dist/esm/scripts/addJobScheduler-11.js +2 -1
- package/dist/esm/scripts/addJobScheduler-11.js.map +1 -1
- package/dist/esm/scripts/index.d.ts +1 -1
- package/dist/esm/scripts/index.js +1 -1
- package/dist/esm/scripts/moveStalledJobsToWait-8.js +168 -0
- package/dist/esm/scripts/moveStalledJobsToWait-8.js.map +1 -0
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +1 -1
- package/dist/cjs/scripts/moveStalledJobsToWait-9.js +0 -563
- package/dist/cjs/scripts/moveStalledJobsToWait-9.js.map +0 -1
- package/dist/esm/scripts/moveStalledJobsToWait-9.js +0 -560
- package/dist/esm/scripts/moveStalledJobsToWait-9.js.map +0 -1
- /package/dist/esm/scripts/{moveStalledJobsToWait-9.d.ts → moveStalledJobsToWait-8.d.ts} +0 -0
@@ -5,12 +5,11 @@
|
|
5
5
|
KEYS[1] 'stalled' (SET)
|
6
6
|
KEYS[2] 'wait', (LIST)
|
7
7
|
KEYS[3] 'active', (LIST)
|
8
|
-
KEYS[4] '
|
9
|
-
KEYS[5] '
|
10
|
-
KEYS[6] '
|
11
|
-
KEYS[7] '
|
12
|
-
KEYS[8] '
|
13
|
-
KEYS[9] 'event stream' (STREAM)
|
8
|
+
KEYS[4] 'stalled-check', (KEY)
|
9
|
+
KEYS[5] 'meta', (KEY)
|
10
|
+
KEYS[6] 'paused', (LIST)
|
11
|
+
KEYS[7] 'marker'
|
12
|
+
KEYS[8] 'event stream' (STREAM)
|
14
13
|
|
15
14
|
ARGV[1] Max stalled job count
|
16
15
|
ARGV[2] queue.toKey('')
|
@@ -26,27 +25,23 @@ local rcall = redis.call
|
|
26
25
|
--- @include "includes/addJobInTargetList"
|
27
26
|
--- @include "includes/batches"
|
28
27
|
--- @include "includes/getTargetQueueList"
|
29
|
-
--- @include "includes/moveChildFromDependenciesIfNeeded"
|
30
|
-
--- @include "includes/removeDeduplicationKeyIfNeededOnFinalization"
|
31
|
-
--- @include "includes/removeJobsOnFail"
|
32
28
|
--- @include "includes/trimEvents"
|
33
29
|
|
34
30
|
local stalledKey = KEYS[1]
|
35
31
|
local waitKey = KEYS[2]
|
36
32
|
local activeKey = KEYS[3]
|
37
|
-
local
|
38
|
-
local
|
39
|
-
local
|
40
|
-
local
|
41
|
-
local
|
42
|
-
local eventStreamKey = KEYS[9]
|
33
|
+
local stalledCheckKey = KEYS[4]
|
34
|
+
local metaKey = KEYS[5]
|
35
|
+
local pausedKey = KEYS[6]
|
36
|
+
local markerKey = KEYS[7]
|
37
|
+
local eventStreamKey = KEYS[8]
|
43
38
|
local maxStalledJobCount = tonumber(ARGV[1])
|
44
39
|
local queueKeyPrefix = ARGV[2]
|
45
40
|
local timestamp = ARGV[3]
|
46
41
|
local maxCheckTime = ARGV[4]
|
47
42
|
|
48
43
|
if rcall("EXISTS", stalledCheckKey) == 1 then
|
49
|
-
return {
|
44
|
+
return {}
|
50
45
|
end
|
51
46
|
|
52
47
|
rcall("SET", stalledCheckKey, timestamp, "PX", maxCheckTime)
|
@@ -57,7 +52,6 @@ trimEvents(metaKey, eventStreamKey)
|
|
57
52
|
-- Move all stalled jobs to wait
|
58
53
|
local stalling = rcall('SMEMBERS', stalledKey)
|
59
54
|
local stalled = {}
|
60
|
-
local failed = {}
|
61
55
|
if (#stalling > 0) then
|
62
56
|
rcall('DEL', stalledKey)
|
63
57
|
|
@@ -78,36 +72,25 @@ if (#stalling > 0) then
|
|
78
72
|
if (removed > 0) then
|
79
73
|
-- If this job has been stalled too many times, such as if it crashes the worker, then fail it.
|
80
74
|
local stalledCount = rcall("HINCRBY", jobKey, "stc", 1)
|
81
|
-
if
|
82
|
-
local jobAttributes = rcall("HMGET", jobKey, "opts", "parent"
|
75
|
+
if stalledCount > maxStalledJobCount then
|
76
|
+
local jobAttributes = rcall("HMGET", jobKey, "opts", "parent")
|
83
77
|
local rawOpts = jobAttributes[1]
|
84
78
|
local rawParentData = jobAttributes[2]
|
85
79
|
local opts = cjson.decode(rawOpts)
|
86
|
-
rcall("ZADD", failedKey, timestamp, jobId)
|
87
|
-
removeDeduplicationKeyIfNeededOnFinalization(queueKeyPrefix, jobAttributes[3], jobId)
|
88
80
|
|
89
81
|
local failedReason = "job stalled more than allowable limit"
|
90
|
-
rcall("
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
moveChildFromDependenciesIfNeeded(rawParentData, jobKey, failedReason, timestamp)
|
95
|
-
|
96
|
-
removeJobsOnFail(queueKeyPrefix, failedKey, jobId, opts, timestamp)
|
97
|
-
|
98
|
-
table.insert(failed, jobId)
|
99
|
-
else
|
100
|
-
local target, isPausedOrMaxed = getTargetQueueList(metaKey, activeKey, waitKey, pausedKey)
|
82
|
+
rcall("HSET", jobKey, "defa", failedReason)
|
83
|
+
end
|
84
|
+
local target, isPausedOrMaxed = getTargetQueueList(metaKey, activeKey, waitKey, pausedKey)
|
101
85
|
|
102
|
-
|
103
|
-
|
86
|
+
-- Move the job back to the wait queue, to immediately be picked up by a waiting worker.
|
87
|
+
addJobInTargetList(target, markerKey, "RPUSH", isPausedOrMaxed, jobId)
|
104
88
|
|
105
|
-
|
89
|
+
rcall("XADD", eventStreamKey, "*", "event", "waiting", "jobId", jobId, 'prev', 'active')
|
106
90
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
end
|
91
|
+
-- Emit the stalled event
|
92
|
+
rcall("XADD", eventStreamKey, "*", "event", "stalled", "jobId", jobId)
|
93
|
+
table.insert(stalled, jobId)
|
111
94
|
end
|
112
95
|
end
|
113
96
|
end
|
@@ -123,4 +106,4 @@ if (#active > 0) then
|
|
123
106
|
end
|
124
107
|
end
|
125
108
|
|
126
|
-
return
|
109
|
+
return stalled
|
@@ -394,6 +394,7 @@ local function storeJobScheduler(schedulerId, schedulerKey, repeatKey, nextMilli
|
|
394
394
|
table.insert(optionalValues, "data")
|
395
395
|
table.insert(optionalValues, templateData)
|
396
396
|
end
|
397
|
+
rcall("DEL", schedulerKey) -- remove all attributes and then re-insert new ones
|
397
398
|
rcall("HMSET", schedulerKey, "name", opts['name'], "ic", 1, unpack(optionalValues))
|
398
399
|
end
|
399
400
|
-- If we are overriding a repeatable job we must delete the delayed job for
|
@@ -405,7 +406,7 @@ local maxEvents = getOrSetMaxEvents(metaKey)
|
|
405
406
|
local function removeJobFromScheduler(prefixKey, delayedKey, prioritizedKey, waitKey, pausedKey, jobId,
|
406
407
|
metaKey, eventsKey)
|
407
408
|
if rcall("ZSCORE", delayedKey, jobId) then
|
408
|
-
removeJob(
|
409
|
+
removeJob(jobId, true, prefixKey, true --[[remove debounce key]] )
|
409
410
|
rcall("ZREM", delayedKey, jobId)
|
410
411
|
return true
|
411
412
|
elseif rcall("ZSCORE", prioritizedKey, jobId) then
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"addJobScheduler-11.js","sourceRoot":"","sources":["../../../src/scripts/addJobScheduler-11.ts"],"names":[],"mappings":";;;AAAA,MAAM,OAAO,GAAG
|
1
|
+
{"version":3,"file":"addJobScheduler-11.js","sourceRoot":"","sources":["../../../src/scripts/addJobScheduler-11.ts"],"names":[],"mappings":";;;AAAA,MAAM,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmcf,CAAC;AACW,QAAA,eAAe,GAAG;IAC7B,IAAI,EAAE,iBAAiB;IACvB,OAAO;IACP,IAAI,EAAE,EAAE;CACT,CAAC"}
|
@@ -27,7 +27,7 @@ tslib_1.__exportStar(require("./isJobInList-1"), exports);
|
|
27
27
|
tslib_1.__exportStar(require("./isMaxed-2"), exports);
|
28
28
|
tslib_1.__exportStar(require("./moveJobFromActiveToWait-9"), exports);
|
29
29
|
tslib_1.__exportStar(require("./moveJobsToWait-8"), exports);
|
30
|
-
tslib_1.__exportStar(require("./moveStalledJobsToWait-
|
30
|
+
tslib_1.__exportStar(require("./moveStalledJobsToWait-8"), exports);
|
31
31
|
tslib_1.__exportStar(require("./moveToActive-11"), exports);
|
32
32
|
tslib_1.__exportStar(require("./moveToDelayed-8"), exports);
|
33
33
|
tslib_1.__exportStar(require("./moveToFinished-14"), exports);
|
@@ -0,0 +1,171 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.moveStalledJobsToWait = void 0;
|
4
|
+
const content = `--[[
|
5
|
+
Move stalled jobs to wait.
|
6
|
+
Input:
|
7
|
+
KEYS[1] 'stalled' (SET)
|
8
|
+
KEYS[2] 'wait', (LIST)
|
9
|
+
KEYS[3] 'active', (LIST)
|
10
|
+
KEYS[4] 'stalled-check', (KEY)
|
11
|
+
KEYS[5] 'meta', (KEY)
|
12
|
+
KEYS[6] 'paused', (LIST)
|
13
|
+
KEYS[7] 'marker'
|
14
|
+
KEYS[8] 'event stream' (STREAM)
|
15
|
+
ARGV[1] Max stalled job count
|
16
|
+
ARGV[2] queue.toKey('')
|
17
|
+
ARGV[3] timestamp
|
18
|
+
ARGV[4] max check time
|
19
|
+
Events:
|
20
|
+
'stalled' with stalled job id.
|
21
|
+
]]
|
22
|
+
local rcall = redis.call
|
23
|
+
-- Includes
|
24
|
+
--[[
|
25
|
+
Function to add job in target list and add marker if needed.
|
26
|
+
]]
|
27
|
+
-- Includes
|
28
|
+
--[[
|
29
|
+
Add marker if needed when a job is available.
|
30
|
+
]]
|
31
|
+
local function addBaseMarkerIfNeeded(markerKey, isPausedOrMaxed)
|
32
|
+
if not isPausedOrMaxed then
|
33
|
+
rcall("ZADD", markerKey, 0, "0")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
local function addJobInTargetList(targetKey, markerKey, pushCmd, isPausedOrMaxed, jobId)
|
37
|
+
rcall(pushCmd, targetKey, jobId)
|
38
|
+
addBaseMarkerIfNeeded(markerKey, isPausedOrMaxed)
|
39
|
+
end
|
40
|
+
--[[
|
41
|
+
Function to loop in batches.
|
42
|
+
Just a bit of warning, some commands as ZREM
|
43
|
+
could receive a maximum of 7000 parameters per call.
|
44
|
+
]]
|
45
|
+
local function batches(n, batchSize)
|
46
|
+
local i = 0
|
47
|
+
return function()
|
48
|
+
local from = i * batchSize + 1
|
49
|
+
i = i + 1
|
50
|
+
if (from <= n) then
|
51
|
+
local to = math.min(from + batchSize - 1, n)
|
52
|
+
return from, to
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
--[[
|
57
|
+
Function to check for the meta.paused key to decide if we are paused or not
|
58
|
+
(since an empty list and !EXISTS are not really the same).
|
59
|
+
]]
|
60
|
+
local function getTargetQueueList(queueMetaKey, activeKey, waitKey, pausedKey)
|
61
|
+
local queueAttributes = rcall("HMGET", queueMetaKey, "paused", "concurrency")
|
62
|
+
if queueAttributes[1] then
|
63
|
+
return pausedKey, true
|
64
|
+
else
|
65
|
+
if queueAttributes[2] then
|
66
|
+
local activeCount = rcall("LLEN", activeKey)
|
67
|
+
if activeCount >= tonumber(queueAttributes[2]) then
|
68
|
+
return waitKey, true
|
69
|
+
else
|
70
|
+
return waitKey, false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
return waitKey, false
|
75
|
+
end
|
76
|
+
--[[
|
77
|
+
Function to trim events, default 10000.
|
78
|
+
]]
|
79
|
+
-- Includes
|
80
|
+
--[[
|
81
|
+
Function to get max events value or set by default 10000.
|
82
|
+
]]
|
83
|
+
local function getOrSetMaxEvents(metaKey)
|
84
|
+
local maxEvents = rcall("HGET", metaKey, "opts.maxLenEvents")
|
85
|
+
if not maxEvents then
|
86
|
+
maxEvents = 10000
|
87
|
+
rcall("HSET", metaKey, "opts.maxLenEvents", maxEvents)
|
88
|
+
end
|
89
|
+
return maxEvents
|
90
|
+
end
|
91
|
+
local function trimEvents(metaKey, eventStreamKey)
|
92
|
+
local maxEvents = getOrSetMaxEvents(metaKey)
|
93
|
+
if maxEvents then
|
94
|
+
rcall("XTRIM", eventStreamKey, "MAXLEN", "~", maxEvents)
|
95
|
+
else
|
96
|
+
rcall("XTRIM", eventStreamKey, "MAXLEN", "~", 10000)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
local stalledKey = KEYS[1]
|
100
|
+
local waitKey = KEYS[2]
|
101
|
+
local activeKey = KEYS[3]
|
102
|
+
local stalledCheckKey = KEYS[4]
|
103
|
+
local metaKey = KEYS[5]
|
104
|
+
local pausedKey = KEYS[6]
|
105
|
+
local markerKey = KEYS[7]
|
106
|
+
local eventStreamKey = KEYS[8]
|
107
|
+
local maxStalledJobCount = tonumber(ARGV[1])
|
108
|
+
local queueKeyPrefix = ARGV[2]
|
109
|
+
local timestamp = ARGV[3]
|
110
|
+
local maxCheckTime = ARGV[4]
|
111
|
+
if rcall("EXISTS", stalledCheckKey) == 1 then
|
112
|
+
return {}
|
113
|
+
end
|
114
|
+
rcall("SET", stalledCheckKey, timestamp, "PX", maxCheckTime)
|
115
|
+
-- Trim events before emiting them to avoid trimming events emitted in this script
|
116
|
+
trimEvents(metaKey, eventStreamKey)
|
117
|
+
-- Move all stalled jobs to wait
|
118
|
+
local stalling = rcall('SMEMBERS', stalledKey)
|
119
|
+
local stalled = {}
|
120
|
+
if (#stalling > 0) then
|
121
|
+
rcall('DEL', stalledKey)
|
122
|
+
-- Remove from active list
|
123
|
+
for i, jobId in ipairs(stalling) do
|
124
|
+
-- Markers in waitlist DEPRECATED in v5: Remove in v6.
|
125
|
+
if string.sub(jobId, 1, 2) == "0:" then
|
126
|
+
-- If the jobId is a delay marker ID we just remove it.
|
127
|
+
rcall("LREM", activeKey, 1, jobId)
|
128
|
+
else
|
129
|
+
local jobKey = queueKeyPrefix .. jobId
|
130
|
+
-- Check that the lock is also missing, then we can handle this job as really stalled.
|
131
|
+
if (rcall("EXISTS", jobKey .. ":lock") == 0) then
|
132
|
+
-- Remove from the active queue.
|
133
|
+
local removed = rcall("LREM", activeKey, 1, jobId)
|
134
|
+
if (removed > 0) then
|
135
|
+
-- If this job has been stalled too many times, such as if it crashes the worker, then fail it.
|
136
|
+
local stalledCount = rcall("HINCRBY", jobKey, "stc", 1)
|
137
|
+
if stalledCount > maxStalledJobCount then
|
138
|
+
local jobAttributes = rcall("HMGET", jobKey, "opts", "parent")
|
139
|
+
local rawOpts = jobAttributes[1]
|
140
|
+
local rawParentData = jobAttributes[2]
|
141
|
+
local opts = cjson.decode(rawOpts)
|
142
|
+
local failedReason = "job stalled more than allowable limit"
|
143
|
+
rcall("HSET", jobKey, "defa", failedReason)
|
144
|
+
end
|
145
|
+
local target, isPausedOrMaxed = getTargetQueueList(metaKey, activeKey, waitKey, pausedKey)
|
146
|
+
-- Move the job back to the wait queue, to immediately be picked up by a waiting worker.
|
147
|
+
addJobInTargetList(target, markerKey, "RPUSH", isPausedOrMaxed, jobId)
|
148
|
+
rcall("XADD", eventStreamKey, "*", "event", "waiting", "jobId", jobId, 'prev', 'active')
|
149
|
+
-- Emit the stalled event
|
150
|
+
rcall("XADD", eventStreamKey, "*", "event", "stalled", "jobId", jobId)
|
151
|
+
table.insert(stalled, jobId)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
-- Mark potentially stalled jobs
|
158
|
+
local active = rcall('LRANGE', activeKey, 0, -1)
|
159
|
+
if (#active > 0) then
|
160
|
+
for from, to in batches(#active, 7000) do
|
161
|
+
rcall('SADD', stalledKey, unpack(active, from, to))
|
162
|
+
end
|
163
|
+
end
|
164
|
+
return stalled
|
165
|
+
`;
|
166
|
+
exports.moveStalledJobsToWait = {
|
167
|
+
name: 'moveStalledJobsToWait',
|
168
|
+
content,
|
169
|
+
keys: 8,
|
170
|
+
};
|
171
|
+
//# sourceMappingURL=moveStalledJobsToWait-8.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"moveStalledJobsToWait-8.js","sourceRoot":"","sources":["../../../src/scripts/moveStalledJobsToWait-8.ts"],"names":[],"mappings":";;;AAAA,MAAM,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiKf,CAAC;AACW,QAAA,qBAAqB,GAAG;IACnC,IAAI,EAAE,uBAAuB;IAC7B,OAAO;IACP,IAAI,EAAE,CAAC;CACR,CAAC"}
|