bullmq 5.34.6 → 5.34.8

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 (47) hide show
  1. package/dist/cjs/classes/job-scheduler.js +34 -38
  2. package/dist/cjs/classes/job-scheduler.js.map +1 -1
  3. package/dist/cjs/classes/job.js.map +1 -1
  4. package/dist/cjs/classes/scripts.js +35 -5
  5. package/dist/cjs/classes/scripts.js.map +1 -1
  6. package/dist/cjs/commands/addDelayedJob-6.lua +4 -18
  7. package/dist/cjs/commands/{addJobScheduler-2.lua → addJobScheduler-6.lua} +44 -15
  8. package/dist/cjs/commands/includes/addDelayedJob.lua +28 -0
  9. package/dist/cjs/commands/updateJobScheduler-6.lua +61 -0
  10. package/dist/cjs/scripts/addDelayedJob-6.js +74 -64
  11. package/dist/cjs/scripts/addDelayedJob-6.js.map +1 -1
  12. package/dist/cjs/scripts/{addJobScheduler-2.js → addJobScheduler-6.js} +144 -16
  13. package/dist/cjs/scripts/addJobScheduler-6.js.map +1 -0
  14. package/dist/cjs/scripts/index.js +2 -1
  15. package/dist/cjs/scripts/index.js.map +1 -1
  16. package/dist/cjs/scripts/updateJobScheduler-6.js +164 -0
  17. package/dist/cjs/scripts/updateJobScheduler-6.js.map +1 -0
  18. package/dist/cjs/tsconfig-cjs.tsbuildinfo +1 -1
  19. package/dist/cjs/version.js +1 -1
  20. package/dist/esm/classes/job-scheduler.d.ts +1 -1
  21. package/dist/esm/classes/job-scheduler.js +34 -38
  22. package/dist/esm/classes/job-scheduler.js.map +1 -1
  23. package/dist/esm/classes/job.js.map +1 -1
  24. package/dist/esm/classes/scripts.d.ts +3 -3
  25. package/dist/esm/classes/scripts.js +35 -5
  26. package/dist/esm/classes/scripts.js.map +1 -1
  27. package/dist/esm/commands/addDelayedJob-6.lua +4 -18
  28. package/dist/esm/commands/{addJobScheduler-2.lua → addJobScheduler-6.lua} +44 -15
  29. package/dist/esm/commands/includes/addDelayedJob.lua +28 -0
  30. package/dist/esm/commands/updateJobScheduler-6.lua +61 -0
  31. package/dist/esm/scripts/addDelayedJob-6.js +74 -64
  32. package/dist/esm/scripts/addDelayedJob-6.js.map +1 -1
  33. package/dist/esm/scripts/{addJobScheduler-2.js → addJobScheduler-6.js} +144 -16
  34. package/dist/esm/scripts/addJobScheduler-6.js.map +1 -0
  35. package/dist/esm/scripts/index.d.ts +2 -1
  36. package/dist/esm/scripts/index.js +2 -1
  37. package/dist/esm/scripts/index.js.map +1 -1
  38. package/dist/esm/scripts/updateJobScheduler-6.d.ts +5 -0
  39. package/dist/esm/scripts/updateJobScheduler-6.js +161 -0
  40. package/dist/esm/scripts/updateJobScheduler-6.js.map +1 -0
  41. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  42. package/dist/esm/version.d.ts +1 -1
  43. package/dist/esm/version.js +1 -1
  44. package/package.json +1 -1
  45. package/dist/cjs/scripts/addJobScheduler-2.js.map +0 -1
  46. package/dist/esm/scripts/addJobScheduler-2.js.map +0 -1
  47. /package/dist/esm/scripts/{addJobScheduler-2.d.ts → addJobScheduler-6.d.ts} +0 -0
@@ -2,8 +2,12 @@
2
2
  Adds a job scheduler, i.e. a job factory that creates jobs based on a given schedule (repeat options).
3
3
 
4
4
  Input:
5
- KEYS[1] 'repeat' key
6
- KEYS[2] 'delayed' key
5
+ KEYS[1] 'marker',
6
+ KEYS[2] 'meta'
7
+ KEYS[3] 'id'
8
+ KEYS[4] 'delayed'
9
+ KEYS[5] events stream key
10
+ KEYS[6] 'repeat' key
7
11
 
8
12
  ARGV[1] next milliseconds
9
13
  ARGV[2] msgpacked options
@@ -14,27 +18,31 @@
14
18
  [5] every?
15
19
  ARGV[3] jobs scheduler id
16
20
  ARGV[4] Json stringified template data
17
- ARGV[5] mspacked template opts
18
- ARGV[6] prefix key
21
+ ARGV[5] msgpacked template opts
22
+ ARGV[6] msgpacked delayed opts
23
+ ARGV[7] timestamp
24
+ ARGV[8] prefix key
25
+ ARGV[9] producer key
19
26
 
20
27
  Output:
21
- repeatableKey - OK
28
+ next delayed job id - OK
22
29
  ]]
23
30
  local rcall = redis.call
24
- local repeatKey = KEYS[1]
25
- local delayedKey = KEYS[2]
26
-
31
+ local repeatKey = KEYS[6]
32
+ local delayedKey = KEYS[4]
33
+ local timestamp = ARGV[7]
27
34
  local nextMillis = ARGV[1]
28
35
  local jobSchedulerId = ARGV[3]
29
36
  local templateOpts = cmsgpack.unpack(ARGV[5])
30
- local prefixKey = ARGV[6]
37
+ local prefixKey = ARGV[8]
31
38
 
32
39
  -- Includes
40
+ --- @include "includes/addDelayedJob"
41
+ --- @include "includes/getOrSetMaxEvents"
33
42
  --- @include "includes/removeJob"
34
43
 
35
- local function storeRepeatableJob(schedulerId, repeatKey, nextMillis, rawOpts, templateData, templateOpts)
44
+ local function storeRepeatableJob(schedulerId, schedulerKey, repeatKey, nextMillis, opts, templateData, templateOpts)
36
45
  rcall("ZADD", repeatKey, nextMillis, schedulerId)
37
- local opts = cmsgpack.unpack(rawOpts)
38
46
 
39
47
  local optionalValues = {}
40
48
  if opts['tz'] then
@@ -68,17 +76,19 @@ local function storeRepeatableJob(schedulerId, repeatKey, nextMillis, rawOpts, t
68
76
  table.insert(optionalValues, templateData)
69
77
  end
70
78
 
71
- rcall("HMSET", repeatKey .. ":" .. schedulerId, "name", opts['name'],
79
+ rcall("HMSET", schedulerKey, "name", opts['name'],
72
80
  unpack(optionalValues))
73
81
  end
74
82
 
83
+ local schedulerKey = repeatKey .. ":" .. jobSchedulerId
84
+ local nextDelayedJobId = "repeat:" .. jobSchedulerId .. ":" .. nextMillis
85
+ local nextDelayedJobKey = schedulerKey .. ":" .. nextMillis
86
+
75
87
  -- If we are overriding a repeatable job we must delete the delayed job for
76
88
  -- the next iteration.
77
89
  local prevMillis = rcall("ZSCORE", repeatKey, jobSchedulerId)
78
90
  if prevMillis ~= false then
79
91
  local delayedJobId = "repeat:" .. jobSchedulerId .. ":" .. prevMillis
80
- local nextDelayedJobId = "repeat:" .. jobSchedulerId .. ":" .. nextMillis
81
- local nextDelayedJobKey = repeatKey .. ":" .. jobSchedulerId .. ":" .. nextMillis
82
92
 
83
93
  if rcall("ZSCORE", delayedKey, delayedJobId) ~= false
84
94
  and (rcall("EXISTS", nextDelayedJobKey) ~= 1
@@ -88,4 +98,23 @@ if prevMillis ~= false then
88
98
  end
89
99
  end
90
100
 
91
- return storeRepeatableJob(jobSchedulerId, repeatKey, nextMillis, ARGV[2], ARGV[4], templateOpts)
101
+ local schedulerOpts = cmsgpack.unpack(ARGV[2])
102
+
103
+ storeRepeatableJob(jobSchedulerId, schedulerKey, repeatKey, nextMillis, schedulerOpts, ARGV[4], templateOpts)
104
+
105
+ local eventsKey = KEYS[5]
106
+ local metaKey = KEYS[2]
107
+ local maxEvents = getOrSetMaxEvents(metaKey)
108
+
109
+ rcall("INCR", KEYS[3])
110
+
111
+ local delayedOpts = cmsgpack.unpack(ARGV[6])
112
+
113
+ addDelayedJob(nextDelayedJobKey, nextDelayedJobId, delayedKey, eventsKey, schedulerOpts['name'], ARGV[4], delayedOpts,
114
+ timestamp, jobSchedulerId, maxEvents, KEYS[1], nil, nil)
115
+
116
+ if ARGV[9] ~= "" then
117
+ rcall("HSET", ARGV[9], "nrjid", nextDelayedJobId)
118
+ end
119
+
120
+ return nextDelayedJobId .. "" -- convert to string
@@ -0,0 +1,28 @@
1
+ --[[
2
+ Adds a delayed job to the queue by doing the following:
3
+ - Creates a new job key with the job data.
4
+ - adds to delayed zset.
5
+ - Emits a global event 'delayed' if the job is delayed.
6
+ ]]
7
+
8
+ -- Includes
9
+ --- @include "addDelayMarkerIfNeeded"
10
+ --- @include "getDelayedScore"
11
+ --- @include "storeJob"
12
+
13
+ local function addDelayedJob(jobIdKey, jobId, delayedKey, eventsKey, name, data, opts, timestamp, repeatJobKey,
14
+ maxEvents, markerKey, parentKey, parentData)
15
+ -- Store the job.
16
+ local delay, priority = storeJob(eventsKey, jobIdKey, jobId, name, data,
17
+ opts, timestamp, parentKey, parentData, repeatJobKey)
18
+
19
+ local score, delayedTimestamp = getDelayedScore(delayedKey, timestamp, tonumber(delay))
20
+
21
+ rcall("ZADD", delayedKey, score, jobId)
22
+ rcall("XADD", eventsKey, "MAXLEN", "~", maxEvents, "*", "event", "delayed",
23
+ "jobId", jobId, "delay", delayedTimestamp)
24
+
25
+ -- mark that a delayed job is available
26
+ addDelayMarkerIfNeeded(markerKey, delayedKey)
27
+ end
28
+
@@ -0,0 +1,61 @@
1
+ --[[
2
+ Updates a job scheduler and adds next delayed job
3
+
4
+ Input:
5
+ KEYS[1] 'marker',
6
+ KEYS[2] 'meta'
7
+ KEYS[3] 'id'
8
+ KEYS[4] 'delayed'
9
+ KEYS[5] events stream key
10
+ KEYS[6] 'repeat' key
11
+
12
+ ARGV[1] next milliseconds
13
+ ARGV[2] jobs scheduler id
14
+ ARGV[3] msgpacked delayed opts
15
+ ARGV[4] timestamp
16
+ ARGV[5] prefix key
17
+ ARGV[6] producer key
18
+
19
+ Output:
20
+ next delayed job id - OK
21
+ ]]
22
+ local rcall = redis.call
23
+ local repeatKey = KEYS[6]
24
+ local delayedKey = KEYS[4]
25
+ local timestamp = ARGV[4]
26
+ local nextMillis = ARGV[1]
27
+ local jobSchedulerId = ARGV[2]
28
+ local prefixKey = ARGV[5]
29
+
30
+ -- Includes
31
+ --- @include "includes/addDelayedJob"
32
+ --- @include "includes/getOrSetMaxEvents"
33
+
34
+ local schedulerKey = repeatKey .. ":" .. jobSchedulerId
35
+ local nextDelayedJobId = "repeat:" .. jobSchedulerId .. ":" .. nextMillis
36
+ local nextDelayedJobKey = schedulerKey .. ":" .. nextMillis
37
+
38
+ -- Validate that scheduler exists.
39
+ local prevMillis = rcall("ZSCORE", repeatKey, jobSchedulerId)
40
+ if prevMillis ~= false then
41
+ local schedulerAttributes = rcall("HMGET", schedulerKey, "name", "data")
42
+
43
+ rcall("ZADD", repeatKey, nextMillis, jobSchedulerId)
44
+
45
+ local eventsKey = KEYS[5]
46
+ local metaKey = KEYS[2]
47
+ local maxEvents = getOrSetMaxEvents(metaKey)
48
+
49
+ rcall("INCR", KEYS[3])
50
+
51
+ local delayedOpts = cmsgpack.unpack(ARGV[3])
52
+
53
+ addDelayedJob(nextDelayedJobKey, nextDelayedJobId, delayedKey, eventsKey, schedulerAttributes[1],
54
+ schedulerAttributes[2] or "{}", delayedOpts, timestamp, jobSchedulerId, maxEvents, KEYS[1], nil, nil)
55
+
56
+ if ARGV[6] ~= "" then
57
+ rcall("HSET", ARGV[6], "nrjid", nextDelayedJobId)
58
+ end
59
+
60
+ return nextDelayedJobId .. "" -- convert to string
61
+ end
@@ -48,6 +48,13 @@ local repeatJobKey = args[9]
48
48
  local deduplicationKey = args[10]
49
49
  local parentData
50
50
  -- Includes
51
+ --[[
52
+ Adds a delayed job to the queue by doing the following:
53
+ - Creates a new job key with the job data.
54
+ - adds to delayed zset.
55
+ - Emits a global event 'delayed' if the job is delayed.
56
+ ]]
57
+ -- Includes
51
58
  --[[
52
59
  Add delay marker if needed.
53
60
  ]]
@@ -72,29 +79,6 @@ local function addDelayMarkerIfNeeded(markerKey, delayedKey)
72
79
  rcall("ZADD", markerKey, nextTimestamp, "1")
73
80
  end
74
81
  end
75
- --[[
76
- Function to debounce a job.
77
- ]]
78
- local function deduplicateJob(prefixKey, deduplicationOpts, jobId, deduplicationKey, eventsKey, maxEvents)
79
- local deduplicationId = deduplicationOpts and deduplicationOpts['id']
80
- if deduplicationId then
81
- local ttl = deduplicationOpts['ttl']
82
- local deduplicationKeyExists
83
- if ttl then
84
- deduplicationKeyExists = not rcall('SET', deduplicationKey, jobId, 'PX', ttl, 'NX')
85
- else
86
- deduplicationKeyExists = not rcall('SET', deduplicationKey, jobId, 'NX')
87
- end
88
- if deduplicationKeyExists then
89
- local currentDebounceJobId = rcall('GET', deduplicationKey)
90
- rcall("XADD", eventsKey, "MAXLEN", "~", maxEvents, "*", "event",
91
- "debounced", "jobId", currentDebounceJobId, "debounceId", deduplicationId)
92
- rcall("XADD", eventsKey, "MAXLEN", "~", maxEvents, "*", "event",
93
- "deduplicated", "jobId", currentDebounceJobId, "deduplicationId", deduplicationId)
94
- return currentDebounceJobId
95
- end
96
- end
97
- end
98
82
  --[[
99
83
  Bake in the job id first 12 bits into the timestamp
100
84
  to guarantee correct execution order of delayed jobs
@@ -119,6 +103,71 @@ local function getDelayedScore(delayedKey, timestamp, delay)
119
103
  end
120
104
  return minScore, delayedTimestamp
121
105
  end
106
+ --[[
107
+ Function to store a job
108
+ ]]
109
+ local function storeJob(eventsKey, jobIdKey, jobId, name, data, opts, timestamp,
110
+ parentKey, parentData, repeatJobKey)
111
+ local jsonOpts = cjson.encode(opts)
112
+ local delay = opts['delay'] or 0
113
+ local priority = opts['priority'] or 0
114
+ local debounceId = opts['de'] and opts['de']['id']
115
+ local optionalValues = {}
116
+ if parentKey ~= nil then
117
+ table.insert(optionalValues, "parentKey")
118
+ table.insert(optionalValues, parentKey)
119
+ table.insert(optionalValues, "parent")
120
+ table.insert(optionalValues, parentData)
121
+ end
122
+ if repeatJobKey ~= nil then
123
+ table.insert(optionalValues, "rjk")
124
+ table.insert(optionalValues, repeatJobKey)
125
+ end
126
+ if debounceId then
127
+ table.insert(optionalValues, "deid")
128
+ table.insert(optionalValues, debounceId)
129
+ end
130
+ rcall("HMSET", jobIdKey, "name", name, "data", data, "opts", jsonOpts,
131
+ "timestamp", timestamp, "delay", delay, "priority", priority,
132
+ unpack(optionalValues))
133
+ rcall("XADD", eventsKey, "*", "event", "added", "jobId", jobId, "name", name)
134
+ return delay, priority
135
+ end
136
+ local function addDelayedJob(jobIdKey, jobId, delayedKey, eventsKey, name, data, opts, timestamp, repeatJobKey,
137
+ maxEvents, markerKey, parentKey, parentData)
138
+ -- Store the job.
139
+ local delay, priority = storeJob(eventsKey, jobIdKey, jobId, name, data,
140
+ opts, timestamp, parentKey, parentData, repeatJobKey)
141
+ local score, delayedTimestamp = getDelayedScore(delayedKey, timestamp, tonumber(delay))
142
+ rcall("ZADD", delayedKey, score, jobId)
143
+ rcall("XADD", eventsKey, "MAXLEN", "~", maxEvents, "*", "event", "delayed",
144
+ "jobId", jobId, "delay", delayedTimestamp)
145
+ -- mark that a delayed job is available
146
+ addDelayMarkerIfNeeded(markerKey, delayedKey)
147
+ end
148
+ --[[
149
+ Function to debounce a job.
150
+ ]]
151
+ local function deduplicateJob(prefixKey, deduplicationOpts, jobId, deduplicationKey, eventsKey, maxEvents)
152
+ local deduplicationId = deduplicationOpts and deduplicationOpts['id']
153
+ if deduplicationId then
154
+ local ttl = deduplicationOpts['ttl']
155
+ local deduplicationKeyExists
156
+ if ttl then
157
+ deduplicationKeyExists = not rcall('SET', deduplicationKey, jobId, 'PX', ttl, 'NX')
158
+ else
159
+ deduplicationKeyExists = not rcall('SET', deduplicationKey, jobId, 'NX')
160
+ end
161
+ if deduplicationKeyExists then
162
+ local currentDebounceJobId = rcall('GET', deduplicationKey)
163
+ rcall("XADD", eventsKey, "MAXLEN", "~", maxEvents, "*", "event",
164
+ "debounced", "jobId", currentDebounceJobId, "debounceId", deduplicationId)
165
+ rcall("XADD", eventsKey, "MAXLEN", "~", maxEvents, "*", "event",
166
+ "deduplicated", "jobId", currentDebounceJobId, "deduplicationId", deduplicationId)
167
+ return currentDebounceJobId
168
+ end
169
+ end
170
+ end
122
171
  --[[
123
172
  Function to get max events value or set by default 10000.
124
173
  ]]
@@ -292,36 +341,6 @@ local function handleDuplicatedJob(jobKey, jobId, currentParentKey, currentParen
292
341
  "duplicated", "jobId", jobId)
293
342
  return jobId .. "" -- convert to string
294
343
  end
295
- --[[
296
- Function to store a job
297
- ]]
298
- local function storeJob(eventsKey, jobIdKey, jobId, name, data, opts, timestamp,
299
- parentKey, parentData, repeatJobKey)
300
- local jsonOpts = cjson.encode(opts)
301
- local delay = opts['delay'] or 0
302
- local priority = opts['priority'] or 0
303
- local debounceId = opts['de'] and opts['de']['id']
304
- local optionalValues = {}
305
- if parentKey ~= nil then
306
- table.insert(optionalValues, "parentKey")
307
- table.insert(optionalValues, parentKey)
308
- table.insert(optionalValues, "parent")
309
- table.insert(optionalValues, parentData)
310
- end
311
- if repeatJobKey ~= nil then
312
- table.insert(optionalValues, "rjk")
313
- table.insert(optionalValues, repeatJobKey)
314
- end
315
- if debounceId then
316
- table.insert(optionalValues, "deid")
317
- table.insert(optionalValues, debounceId)
318
- end
319
- rcall("HMSET", jobIdKey, "name", name, "data", data, "opts", jsonOpts,
320
- "timestamp", timestamp, "delay", delay, "priority", priority,
321
- unpack(optionalValues))
322
- rcall("XADD", eventsKey, "*", "event", "added", "jobId", jobId, "name", name)
323
- return delay, priority
324
- end
325
344
  if parentKey ~= nil then
326
345
  if rcall("EXISTS", parentKey) ~= 1 then return -5 end
327
346
  parentData = cjson.encode(parent)
@@ -348,17 +367,8 @@ local deduplicationJobId = deduplicateJob(args[1], opts['de'],
348
367
  if deduplicationJobId then
349
368
  return deduplicationJobId
350
369
  end
351
- -- Store the job.
352
- local delay, priority = storeJob(eventsKey, jobIdKey, jobId, args[3], ARGV[2],
353
- opts, timestamp, parentKey, parentData,
354
- repeatJobKey)
355
- local score, delayedTimestamp = getDelayedScore(delayedKey, timestamp, tonumber(delay))
356
- rcall("ZADD", delayedKey, score, jobId)
357
- rcall("XADD", eventsKey, "MAXLEN", "~", maxEvents, "*", "event", "delayed",
358
- "jobId", jobId, "delay", delayedTimestamp)
359
- -- mark that a delayed job is available
360
- local markerKey = KEYS[1]
361
- addDelayMarkerIfNeeded(markerKey, delayedKey)
370
+ addDelayedJob(jobIdKey, jobId, delayedKey, eventsKey, args[3], ARGV[2], opts, timestamp, repeatJobKey,
371
+ maxEvents, KEYS[1], parentKey, parentData)
362
372
  -- Check if this job is a child of another job, if so add it to the parents dependencies
363
373
  if parentDependenciesKey ~= nil then
364
374
  rcall("SADD", parentDependenciesKey, jobIdKey)
@@ -1 +1 @@
1
- {"version":3,"file":"addDelayedJob-6.js","sourceRoot":"","sources":["../../../src/scripts/addDelayedJob-6.ts"],"names":[],"mappings":";;;AAAA,MAAM,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2Wf,CAAC;AACW,QAAA,aAAa,GAAG;IAC3B,IAAI,EAAE,eAAe;IACrB,OAAO;IACP,IAAI,EAAE,CAAC;CACR,CAAC"}
1
+ {"version":3,"file":"addDelayedJob-6.js","sourceRoot":"","sources":["../../../src/scripts/addDelayedJob-6.ts"],"names":[],"mappings":";;;AAAA,MAAM,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqXf,CAAC;AACW,QAAA,aAAa,GAAG;IAC3B,IAAI,EAAE,eAAe;IACrB,OAAO;IACP,IAAI,EAAE,CAAC;CACR,CAAC"}
@@ -4,8 +4,12 @@ exports.addJobScheduler = void 0;
4
4
  const content = `--[[
5
5
  Adds a job scheduler, i.e. a job factory that creates jobs based on a given schedule (repeat options).
6
6
  Input:
7
- KEYS[1] 'repeat' key
8
- KEYS[2] 'delayed' key
7
+ KEYS[1] 'marker',
8
+ KEYS[2] 'meta'
9
+ KEYS[3] 'id'
10
+ KEYS[4] 'delayed'
11
+ KEYS[5] events stream key
12
+ KEYS[6] 'repeat' key
9
13
  ARGV[1] next milliseconds
10
14
  ARGV[2] msgpacked options
11
15
  [1] name
@@ -15,19 +19,131 @@ const content = `--[[
15
19
  [5] every?
16
20
  ARGV[3] jobs scheduler id
17
21
  ARGV[4] Json stringified template data
18
- ARGV[5] mspacked template opts
19
- ARGV[6] prefix key
22
+ ARGV[5] msgpacked template opts
23
+ ARGV[6] msgpacked delayed opts
24
+ ARGV[7] timestamp
25
+ ARGV[8] prefix key
26
+ ARGV[9] producer key
20
27
  Output:
21
- repeatableKey - OK
28
+ next delayed job id - OK
22
29
  ]]
23
30
  local rcall = redis.call
24
- local repeatKey = KEYS[1]
25
- local delayedKey = KEYS[2]
31
+ local repeatKey = KEYS[6]
32
+ local delayedKey = KEYS[4]
33
+ local timestamp = ARGV[7]
26
34
  local nextMillis = ARGV[1]
27
35
  local jobSchedulerId = ARGV[3]
28
36
  local templateOpts = cmsgpack.unpack(ARGV[5])
29
- local prefixKey = ARGV[6]
37
+ local prefixKey = ARGV[8]
30
38
  -- Includes
39
+ --[[
40
+ Adds a delayed job to the queue by doing the following:
41
+ - Creates a new job key with the job data.
42
+ - adds to delayed zset.
43
+ - Emits a global event 'delayed' if the job is delayed.
44
+ ]]
45
+ -- Includes
46
+ --[[
47
+ Add delay marker if needed.
48
+ ]]
49
+ -- Includes
50
+ --[[
51
+ Function to return the next delayed job timestamp.
52
+ ]]
53
+ local function getNextDelayedTimestamp(delayedKey)
54
+ local result = rcall("ZRANGE", delayedKey, 0, 0, "WITHSCORES")
55
+ if #result then
56
+ local nextTimestamp = tonumber(result[2])
57
+ if nextTimestamp ~= nil then
58
+ return nextTimestamp / 0x1000
59
+ end
60
+ end
61
+ end
62
+ local function addDelayMarkerIfNeeded(markerKey, delayedKey)
63
+ local nextTimestamp = getNextDelayedTimestamp(delayedKey)
64
+ if nextTimestamp ~= nil then
65
+ -- Replace the score of the marker with the newest known
66
+ -- next timestamp.
67
+ rcall("ZADD", markerKey, nextTimestamp, "1")
68
+ end
69
+ end
70
+ --[[
71
+ Bake in the job id first 12 bits into the timestamp
72
+ to guarantee correct execution order of delayed jobs
73
+ (up to 4096 jobs per given timestamp or 4096 jobs apart per timestamp)
74
+ WARNING: Jobs that are so far apart that they wrap around will cause FIFO to fail
75
+ ]]
76
+ local function getDelayedScore(delayedKey, timestamp, delay)
77
+ local delayedTimestamp = (delay > 0 and (tonumber(timestamp) + delay)) or tonumber(timestamp)
78
+ local minScore = delayedTimestamp * 0x1000
79
+ local maxScore = (delayedTimestamp + 1 ) * 0x1000 - 1
80
+ local result = rcall("ZREVRANGEBYSCORE", delayedKey, maxScore,
81
+ minScore, "WITHSCORES","LIMIT", 0, 1)
82
+ if #result then
83
+ local currentMaxScore = tonumber(result[2])
84
+ if currentMaxScore ~= nil then
85
+ if currentMaxScore >= maxScore then
86
+ return maxScore, delayedTimestamp
87
+ else
88
+ return currentMaxScore + 1, delayedTimestamp
89
+ end
90
+ end
91
+ end
92
+ return minScore, delayedTimestamp
93
+ end
94
+ --[[
95
+ Function to store a job
96
+ ]]
97
+ local function storeJob(eventsKey, jobIdKey, jobId, name, data, opts, timestamp,
98
+ parentKey, parentData, repeatJobKey)
99
+ local jsonOpts = cjson.encode(opts)
100
+ local delay = opts['delay'] or 0
101
+ local priority = opts['priority'] or 0
102
+ local debounceId = opts['de'] and opts['de']['id']
103
+ local optionalValues = {}
104
+ if parentKey ~= nil then
105
+ table.insert(optionalValues, "parentKey")
106
+ table.insert(optionalValues, parentKey)
107
+ table.insert(optionalValues, "parent")
108
+ table.insert(optionalValues, parentData)
109
+ end
110
+ if repeatJobKey ~= nil then
111
+ table.insert(optionalValues, "rjk")
112
+ table.insert(optionalValues, repeatJobKey)
113
+ end
114
+ if debounceId then
115
+ table.insert(optionalValues, "deid")
116
+ table.insert(optionalValues, debounceId)
117
+ end
118
+ rcall("HMSET", jobIdKey, "name", name, "data", data, "opts", jsonOpts,
119
+ "timestamp", timestamp, "delay", delay, "priority", priority,
120
+ unpack(optionalValues))
121
+ rcall("XADD", eventsKey, "*", "event", "added", "jobId", jobId, "name", name)
122
+ return delay, priority
123
+ end
124
+ local function addDelayedJob(jobIdKey, jobId, delayedKey, eventsKey, name, data, opts, timestamp, repeatJobKey,
125
+ maxEvents, markerKey, parentKey, parentData)
126
+ -- Store the job.
127
+ local delay, priority = storeJob(eventsKey, jobIdKey, jobId, name, data,
128
+ opts, timestamp, parentKey, parentData, repeatJobKey)
129
+ local score, delayedTimestamp = getDelayedScore(delayedKey, timestamp, tonumber(delay))
130
+ rcall("ZADD", delayedKey, score, jobId)
131
+ rcall("XADD", eventsKey, "MAXLEN", "~", maxEvents, "*", "event", "delayed",
132
+ "jobId", jobId, "delay", delayedTimestamp)
133
+ -- mark that a delayed job is available
134
+ addDelayMarkerIfNeeded(markerKey, delayedKey)
135
+ end
136
+ --[[
137
+ Function to get max events value or set by default 10000.
138
+ ]]
139
+ local function getOrSetMaxEvents(metaKey)
140
+ local maxEvents = rcall("HGET", metaKey, "opts.maxLenEvents")
141
+ if not maxEvents then
142
+ maxEvents = 10000
143
+ rcall("HSET", metaKey, "opts.maxLenEvents", maxEvents)
144
+ end
145
+ return maxEvents
146
+ end
31
147
  --[[
32
148
  Function to remove job.
33
149
  ]]
@@ -181,9 +297,8 @@ local function removeJob(jobId, hard, baseKey, shouldRemoveDeduplicationKey)
181
297
  end
182
298
  removeJobKeys(jobKey)
183
299
  end
184
- local function storeRepeatableJob(schedulerId, repeatKey, nextMillis, rawOpts, templateData, templateOpts)
300
+ local function storeRepeatableJob(schedulerId, schedulerKey, repeatKey, nextMillis, opts, templateData, templateOpts)
185
301
  rcall("ZADD", repeatKey, nextMillis, schedulerId)
186
- local opts = cmsgpack.unpack(rawOpts)
187
302
  local optionalValues = {}
188
303
  if opts['tz'] then
189
304
  table.insert(optionalValues, "tz")
@@ -210,16 +325,17 @@ local function storeRepeatableJob(schedulerId, repeatKey, nextMillis, rawOpts, t
210
325
  table.insert(optionalValues, "data")
211
326
  table.insert(optionalValues, templateData)
212
327
  end
213
- rcall("HMSET", repeatKey .. ":" .. schedulerId, "name", opts['name'],
328
+ rcall("HMSET", schedulerKey, "name", opts['name'],
214
329
  unpack(optionalValues))
215
330
  end
331
+ local schedulerKey = repeatKey .. ":" .. jobSchedulerId
332
+ local nextDelayedJobId = "repeat:" .. jobSchedulerId .. ":" .. nextMillis
333
+ local nextDelayedJobKey = schedulerKey .. ":" .. nextMillis
216
334
  -- If we are overriding a repeatable job we must delete the delayed job for
217
335
  -- the next iteration.
218
336
  local prevMillis = rcall("ZSCORE", repeatKey, jobSchedulerId)
219
337
  if prevMillis ~= false then
220
338
  local delayedJobId = "repeat:" .. jobSchedulerId .. ":" .. prevMillis
221
- local nextDelayedJobId = "repeat:" .. jobSchedulerId .. ":" .. nextMillis
222
- local nextDelayedJobKey = repeatKey .. ":" .. jobSchedulerId .. ":" .. nextMillis
223
339
  if rcall("ZSCORE", delayedKey, delayedJobId) ~= false
224
340
  and (rcall("EXISTS", nextDelayedJobKey) ~= 1
225
341
  or delayedJobId == nextDelayedJobId) then
@@ -227,11 +343,23 @@ if prevMillis ~= false then
227
343
  rcall("ZREM", delayedKey, delayedJobId)
228
344
  end
229
345
  end
230
- return storeRepeatableJob(jobSchedulerId, repeatKey, nextMillis, ARGV[2], ARGV[4], templateOpts)
346
+ local schedulerOpts = cmsgpack.unpack(ARGV[2])
347
+ storeRepeatableJob(jobSchedulerId, schedulerKey, repeatKey, nextMillis, schedulerOpts, ARGV[4], templateOpts)
348
+ local eventsKey = KEYS[5]
349
+ local metaKey = KEYS[2]
350
+ local maxEvents = getOrSetMaxEvents(metaKey)
351
+ rcall("INCR", KEYS[3])
352
+ local delayedOpts = cmsgpack.unpack(ARGV[6])
353
+ addDelayedJob(nextDelayedJobKey, nextDelayedJobId, delayedKey, eventsKey, schedulerOpts['name'], ARGV[4], delayedOpts,
354
+ timestamp, jobSchedulerId, maxEvents, KEYS[1], nil, nil)
355
+ if ARGV[9] ~= "" then
356
+ rcall("HSET", ARGV[9], "nrjid", nextDelayedJobId)
357
+ end
358
+ return nextDelayedJobId .. "" -- convert to string
231
359
  `;
232
360
  exports.addJobScheduler = {
233
361
  name: 'addJobScheduler',
234
362
  content,
235
- keys: 2,
363
+ keys: 6,
236
364
  };
237
- //# sourceMappingURL=addJobScheduler-2.js.map
365
+ //# sourceMappingURL=addJobScheduler-6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addJobScheduler-6.js","sourceRoot":"","sources":["../../../src/scripts/addJobScheduler-6.ts"],"names":[],"mappings":";;;AAAA,MAAM,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmWf,CAAC;AACW,QAAA,eAAe,GAAG;IAC7B,IAAI,EAAE,iBAAiB;IACvB,OAAO;IACP,IAAI,EAAE,CAAC;CACR,CAAC"}
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  tslib_1.__exportStar(require("./addDelayedJob-6"), exports);
5
- tslib_1.__exportStar(require("./addJobScheduler-2"), exports);
5
+ tslib_1.__exportStar(require("./addJobScheduler-6"), exports);
6
6
  tslib_1.__exportStar(require("./addLog-2"), exports);
7
7
  tslib_1.__exportStar(require("./addParentJob-4"), exports);
8
8
  tslib_1.__exportStar(require("./addPrioritizedJob-8"), exports);
@@ -44,6 +44,7 @@ tslib_1.__exportStar(require("./reprocessJob-8"), exports);
44
44
  tslib_1.__exportStar(require("./retryJob-11"), exports);
45
45
  tslib_1.__exportStar(require("./saveStacktrace-1"), exports);
46
46
  tslib_1.__exportStar(require("./updateData-1"), exports);
47
+ tslib_1.__exportStar(require("./updateJobScheduler-6"), exports);
47
48
  tslib_1.__exportStar(require("./updateProgress-3"), exports);
48
49
  tslib_1.__exportStar(require("./updateRepeatableJobMillis-1"), exports);
49
50
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/scripts/index.ts"],"names":[],"mappings":";;;AAAA,4DAAkC;AAClC,8DAAoC;AACpC,qDAA2B;AAC3B,2DAAiC;AACjC,gEAAsC;AACtC,+DAAqC;AACrC,6DAAmC;AACnC,0DAAgC;AAChC,6DAAmC;AACnC,6DAAmC;AACnC,oDAA0B;AAC1B,yDAA+B;AAC/B,0DAAgC;AAChC,wDAA8B;AAC9B,mEAAyC;AACzC,8DAAoC;AACpC,wDAA8B;AAC9B,8DAAoC;AACpC,uDAA6B;AAC7B,yDAA+B;AAC/B,yDAA+B;AAC/B,0DAAgC;AAChC,sDAA4B;AAC5B,sEAA4C;AAC5C,6DAAmC;AACnC,oEAA0C;AAC1C,4DAAkC;AAClC,4DAAkC;AAClC,8DAAoC;AACpC,oEAA0C;AAC1C,yDAA+B;AAC/B,uDAA6B;AAC7B,oDAA0B;AAC1B,sDAA4B;AAC5B,0DAAgC;AAChC,oEAA0C;AAC1C,wDAA8B;AAC9B,iEAAuC;AACvC,+DAAqC;AACrC,2DAAiC;AACjC,wDAA8B;AAC9B,6DAAmC;AACnC,yDAA+B;AAC/B,6DAAmC;AACnC,wEAA8C"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/scripts/index.ts"],"names":[],"mappings":";;;AAAA,4DAAkC;AAClC,8DAAoC;AACpC,qDAA2B;AAC3B,2DAAiC;AACjC,gEAAsC;AACtC,+DAAqC;AACrC,6DAAmC;AACnC,0DAAgC;AAChC,6DAAmC;AACnC,6DAAmC;AACnC,oDAA0B;AAC1B,yDAA+B;AAC/B,0DAAgC;AAChC,wDAA8B;AAC9B,mEAAyC;AACzC,8DAAoC;AACpC,wDAA8B;AAC9B,8DAAoC;AACpC,uDAA6B;AAC7B,yDAA+B;AAC/B,yDAA+B;AAC/B,0DAAgC;AAChC,sDAA4B;AAC5B,sEAA4C;AAC5C,6DAAmC;AACnC,oEAA0C;AAC1C,4DAAkC;AAClC,4DAAkC;AAClC,8DAAoC;AACpC,oEAA0C;AAC1C,yDAA+B;AAC/B,uDAA6B;AAC7B,oDAA0B;AAC1B,sDAA4B;AAC5B,0DAAgC;AAChC,oEAA0C;AAC1C,wDAA8B;AAC9B,iEAAuC;AACvC,+DAAqC;AACrC,2DAAiC;AACjC,wDAA8B;AAC9B,6DAAmC;AACnC,yDAA+B;AAC/B,iEAAuC;AACvC,6DAAmC;AACnC,wEAA8C"}