bullmq 1.54.5 → 1.56.0

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 (56) hide show
  1. package/README.md +1 -1
  2. package/dist/classes/backoffs.js.map +1 -1
  3. package/dist/classes/child-pool.js +4 -7
  4. package/dist/classes/child-pool.js.map +1 -1
  5. package/dist/classes/child-processor.js +8 -8
  6. package/dist/classes/child-processor.js.map +1 -1
  7. package/dist/classes/flow-producer.js +2 -2
  8. package/dist/classes/flow-producer.js.map +1 -1
  9. package/dist/classes/index.js +14 -14
  10. package/dist/classes/index.js.map +1 -1
  11. package/dist/classes/job.d.ts +5 -1
  12. package/dist/classes/job.js +13 -9
  13. package/dist/classes/job.js.map +1 -1
  14. package/dist/classes/master.js +2 -2
  15. package/dist/classes/master.js.map +1 -1
  16. package/dist/classes/queue-events.js +6 -6
  17. package/dist/classes/queue-events.js.map +1 -1
  18. package/dist/classes/queue-getters.js.map +1 -1
  19. package/dist/classes/queue-scheduler.js +3 -3
  20. package/dist/classes/queue-scheduler.js.map +1 -1
  21. package/dist/classes/queue.js +7 -7
  22. package/dist/classes/queue.js.map +1 -1
  23. package/dist/classes/redis-connection.d.ts +0 -1
  24. package/dist/classes/redis-connection.js +3 -6
  25. package/dist/classes/redis-connection.js.map +1 -1
  26. package/dist/classes/repeat.js +2 -2
  27. package/dist/classes/repeat.js.map +1 -1
  28. package/dist/classes/sandbox.js +1 -1
  29. package/dist/classes/sandbox.js.map +1 -1
  30. package/dist/classes/scripts.js +12 -8
  31. package/dist/classes/scripts.js.map +1 -1
  32. package/dist/classes/timer-manager.js +1 -1
  33. package/dist/classes/timer-manager.js.map +1 -1
  34. package/dist/classes/worker.d.ts +1 -1
  35. package/dist/classes/worker.js +16 -14
  36. package/dist/classes/worker.js.map +1 -1
  37. package/dist/commands/addJob-9.lua +3 -3
  38. package/dist/commands/index.d.ts +4 -3
  39. package/dist/commands/index.js +8 -72
  40. package/dist/commands/index.js.map +1 -1
  41. package/dist/commands/moveStalledJobsToWait-8.lua +2 -2
  42. package/dist/commands/moveToFinished-8.lua +17 -13
  43. package/dist/commands/removeJob-1.lua +3 -3
  44. package/dist/commands/script-loader.d.ts +120 -0
  45. package/dist/commands/script-loader.js +400 -0
  46. package/dist/commands/script-loader.js.map +1 -0
  47. package/dist/enums/index.js +1 -1
  48. package/dist/enums/index.js.map +1 -1
  49. package/dist/index.js +5 -5
  50. package/dist/index.js.map +1 -1
  51. package/dist/interfaces/index.js +19 -19
  52. package/dist/interfaces/index.js.map +1 -1
  53. package/dist/interfaces/jobs-options.d.ts +2 -0
  54. package/dist/utils.js +7 -5
  55. package/dist/utils.js.map +1 -1
  56. package/package.json +14 -12
@@ -1,74 +1,10 @@
1
- /**
2
- * Load redis lua scripts.
3
- * The name of the script must have the following format:
4
- *
5
- * cmdName-numKeys.lua
6
- *
7
- * cmdName must be in camel case format.
8
- *
9
- * For example:
10
- * moveToFinish-3.lua
11
- *
12
- */
13
- 'use strict';
1
+ "use strict";
14
2
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.loadIncludes = exports.load = void 0;
16
- const lodash_1 = require("lodash");
17
- const path = require("path");
18
- const fs = require("fs");
19
- const util = require("util");
20
- const readdir = util.promisify(fs.readdir);
21
- const readFile = util.promisify(fs.readFile);
22
- const exists = util.promisify(fs.exists);
23
- exports.load = async function (client, pathname, extraIncludes) {
24
- const scripts = await loadScripts(pathname, extraIncludes);
25
- scripts.forEach((command) => {
26
- // Only define the command if not already defined
27
- if (!client[command.name]) {
28
- client.defineCommand(command.name, command.options);
29
- }
30
- });
31
- };
32
- async function loadScripts(dir, extraIncludes) {
33
- const files = await readdir(dir);
34
- const includes = await exports.loadIncludes(dir, extraIncludes);
35
- const luaFiles = files.filter((file) => path.extname(file) === '.lua');
36
- if (luaFiles.length === 0) {
37
- /**
38
- * To prevent unclarified runtime error "updateDelayset is not a function
39
- * @see https://github.com/OptimalBits/bull/issues/920
40
- */
41
- throw new Error('No .lua files found!');
42
- }
43
- const commands = [];
44
- for (let i = 0; i < luaFiles.length; i++) {
45
- const file = luaFiles[i];
46
- if (path.extname(file) === '.lua') {
47
- const longName = path.basename(file, '.lua');
48
- const name = longName.split('-')[0];
49
- const numberOfKeys = parseInt(longName.split('-')[1]);
50
- const lua = (await readFile(path.join(dir, file))).toString();
51
- const compiled = lodash_1.template(lua);
52
- commands.push({
53
- name,
54
- options: { numberOfKeys, lua: compiled(includes) },
55
- });
56
- }
57
- }
58
- return commands;
59
- }
60
- exports.loadIncludes = async function (dir, extraIncludes) {
61
- const includes = extraIncludes || {};
62
- const includesDir = path.join(dir, 'includes');
63
- if (await exists(includesDir)) {
64
- const includesFiles = await readdir(includesDir);
65
- for (let i = 0; i < includesFiles.length; i++) {
66
- const file = includesFiles[i];
67
- const lua = await readFile(path.join(includesDir, file));
68
- const name = path.basename(file, '.lua');
69
- includes[name] = lua.toString();
70
- }
71
- }
72
- return includes;
73
- };
3
+ exports.scriptLoader = exports.ScriptLoader = exports.ScriptLoaderError = void 0;
4
+ const script_loader_1 = require("./script-loader");
5
+ Object.defineProperty(exports, "ScriptLoader", { enumerable: true, get: function () { return script_loader_1.ScriptLoader; } });
6
+ var script_loader_2 = require("./script-loader");
7
+ Object.defineProperty(exports, "ScriptLoaderError", { enumerable: true, get: function () { return script_loader_2.ScriptLoaderError; } });
8
+ const scriptLoader = new script_loader_1.ScriptLoader();
9
+ exports.scriptLoader = scriptLoader;
74
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":";;;AAAA,mDAA+C;AAKtC,6FALA,4BAAY,OAKA;AAJrB,iDAA6E;AAA3C,kHAAA,iBAAiB,OAAA;AAEnD,MAAM,YAAY,GAAG,IAAI,4BAAY,EAAE,CAAC;AAEjB,oCAAY"}
@@ -75,8 +75,8 @@ if (#stalling > 0) then
75
75
  if (stalledCount > MAX_STALLED_JOB_COUNT) then
76
76
  local failedReason = "job stalled more than allowable limit"
77
77
  rcall("ZADD", KEYS[4], ARGV[3], jobId)
78
- rcall("HSET", jobKey, "failedReason",
79
- failedReason)
78
+ rcall("HMSET", jobKey, "failedReason",
79
+ failedReason, "finishedOn", ARGV[3])
80
80
  rcall("XADD", KEYS[8], "*", "event", "failed", "jobId",
81
81
  jobId, 'prev', 'active', 'failedReason',
82
82
  failedReason)
@@ -42,8 +42,8 @@
42
42
  local rcall = redis.call
43
43
 
44
44
  -- Includes
45
- <%= updateParentDepsIfNeeded %>
46
- <%= destructureJobKey %>
45
+ --- @include "includes/updateParentDepsIfNeeded"
46
+ --- @include "includes/destructureJobKey"
47
47
 
48
48
  local jobIdKey = KEYS[3]
49
49
  if rcall("EXISTS",jobIdKey) == 1 then -- // Make sure job exists
@@ -70,8 +70,16 @@ if rcall("EXISTS",jobIdKey) == 1 then -- // Make sure job exists
70
70
  if(numRemovedElements < 1) then
71
71
  return -3
72
72
  end
73
-
74
- -- If job has a parent we need to
73
+
74
+
75
+ -- Trim events before emiting them to avoid trimming events emitted in this script
76
+ local maxEvents = rcall("HGET", KEYS[7], "opts.maxLenEvents")
77
+ if (maxEvents == false) then
78
+ maxEvents = 10000
79
+ end
80
+ rcall("XTRIM", KEYS[6], "MAXLEN", "~", maxEvents)
81
+
82
+ -- If job has a parent we need to
75
83
  -- 1) remove this job id from parents dependencies
76
84
  -- 2) move the job Id to parent "processed" set
77
85
  -- 3) push the results into parent "results" list
@@ -83,15 +91,15 @@ if rcall("EXISTS",jobIdKey) == 1 then -- // Make sure job exists
83
91
  parentId = getJobIdFromKey(ARGV[14])
84
92
  parentQueueKey = getJobKeyPrefix(ARGV[14], ":" .. parentId)
85
93
  end
86
- if parentId ~= "" and ARGV[5] == "completed" then
94
+ if parentId ~= "" and ARGV[5] == "completed" then
87
95
  local parentKey = parentQueueKey .. ":" .. parentId
88
96
  local dependenciesSet = parentKey .. ":dependencies"
89
97
  local result = rcall("SREM", dependenciesSet, jobIdKey)
90
- if result == 1 then
98
+ if result == 1 then
91
99
  updateParentDepsIfNeeded(parentKey, parentQueueKey, dependenciesSet, parentId, jobIdKey, ARGV[4])
92
100
  end
93
101
  end
94
-
102
+
95
103
  -- Remove job?
96
104
  local removeJobs = tonumber(ARGV[6])
97
105
  if removeJobs ~= 1 then
@@ -140,15 +148,11 @@ if rcall("EXISTS",jobIdKey) == 1 then -- // Make sure job exists
140
148
  rcall("HSET", jobKey, "processedOn", ARGV[2])
141
149
 
142
150
  return {rcall("HGETALL", jobKey), jobId} -- get job data
151
+ else
152
+ rcall("XADD", KEYS[6], "*", "event", "drained");
143
153
  end
144
154
  end
145
155
 
146
- local maxEvents = rcall("HGET", KEYS[7], "opts.maxLenEvents")
147
- if (maxEvents == false) then
148
- maxEvents = 10000
149
- end
150
- rcall("XTRIM", KEYS[6], "MAXLEN", "~", maxEvents)
151
-
152
156
  return 0
153
157
  else
154
158
  return -1
@@ -13,7 +13,7 @@
13
13
  local rcall = redis.call
14
14
 
15
15
  -- Includes
16
- <%= destructureJobKey %>
16
+ --- @include "includes/destructureJobKey"
17
17
 
18
18
  -- recursively check if there are no locks on the
19
19
  -- jobs to be removed.
@@ -45,13 +45,13 @@ local function removeJob( prefix, jobId)
45
45
  local jobKey = prefix .. jobId;
46
46
 
47
47
  -- Check if this job has a parent. If so we will just remove it from
48
- -- the parent child list, but if it is the last child we should move the parent to "wait/paused"
48
+ -- the parent child list, but if it is the last child we should move the parent to "wait/paused"
49
49
  -- which requires code from "moveToFinished"
50
50
  local parentKey = rcall("HGET", jobKey, "parentKey")
51
51
  if( (type(parentKey) == "string") and parentKey ~= "" and (rcall("EXISTS", parentKey) == 1)) then
52
52
  local parentDependenciesKey = parentKey .. ":dependencies"
53
53
  local result = rcall("SREM", parentDependenciesKey, jobKey)
54
- if rcall("SCARD", parentDependenciesKey) == 0 then
54
+ if rcall("SCARD", parentDependenciesKey) == 0 then
55
55
  local parentId = getJobIdFromKey(parentKey)
56
56
  local parentPrefix = getJobKeyPrefix(parentKey, parentId)
57
57
 
@@ -0,0 +1,120 @@
1
+ import { RedisClient } from '../interfaces';
2
+ export interface Command {
3
+ name: string;
4
+ options: {
5
+ numberOfKeys: number;
6
+ lua: string;
7
+ };
8
+ }
9
+ /**
10
+ * Script metadata
11
+ */
12
+ export interface ScriptMetadata {
13
+ /**
14
+ * Name of the script
15
+ */
16
+ name: string;
17
+ numberOfKeys?: number;
18
+ /**
19
+ * The path to the script. For includes, this is the normalized path,
20
+ * whereas it may not be normalized for the top-level parent
21
+ */
22
+ path: string;
23
+ /**
24
+ * The raw script content
25
+ */
26
+ content: string;
27
+ /**
28
+ * A hash of the normalized path for easy replacement in the parent
29
+ */
30
+ token: string;
31
+ /**
32
+ * Metadata on the scripts that this script includes
33
+ */
34
+ includes: ScriptMetadata[];
35
+ }
36
+ export declare class ScriptLoaderError extends Error {
37
+ readonly path: string;
38
+ /**
39
+ * The include stack
40
+ */
41
+ readonly includes: string[];
42
+ readonly line: number;
43
+ readonly position: number;
44
+ constructor(message: string, path: string, stack?: string[], line?: number, position?: number);
45
+ }
46
+ /**
47
+ * Lua script loader with include support
48
+ */
49
+ export declare class ScriptLoader {
50
+ /**
51
+ * Map an alias to a path
52
+ */
53
+ private pathMapper;
54
+ private clientScripts;
55
+ /**
56
+ * Cache commands by dir
57
+ */
58
+ private commandCache;
59
+ private rootPath;
60
+ constructor();
61
+ /**
62
+ * Add a script path mapping. Allows includes of the form "<includes>/utils.lua" where `includes` is a user
63
+ * defined path
64
+ * @param name - the name of the mapping. Note: do not include angle brackets
65
+ * @param mappedPath - if a relative path is passed, it's relative to the *caller* of this function.
66
+ * Mapped paths are also accepted, e.g. "~/server/scripts/lua" or "<base>/includes"
67
+ */
68
+ addPathMapping(name: string, mappedPath: string): void;
69
+ /**
70
+ * Resolve the script path considering path mappings
71
+ * @param scriptName - the name of the script
72
+ * @param stack - the include stack, for nicer errors
73
+ */
74
+ resolvePath(scriptName: string, stack?: string[]): string;
75
+ /**
76
+ * Recursively collect all scripts included in a file
77
+ * @param file - the parent file
78
+ * @param cache - a cache for file metadata to increase efficiency. Since a file can be included
79
+ * multiple times, we make sure to load it only once.
80
+ * @param stack - internal stack to prevent circular references
81
+ */
82
+ private resolveDependencies;
83
+ /**
84
+ * Parse a (top-level) lua script
85
+ * @param filename - the full path to the script
86
+ * @param content - the content of the script
87
+ * @param cache - cache
88
+ */
89
+ parseScript(filename: string, content: string, cache?: Map<string, ScriptMetadata>): Promise<ScriptMetadata>;
90
+ /**
91
+ * Construct the final version of a file by interpolating its includes in dependency order.
92
+ * @param file - the file whose content we want to construct
93
+ * @param processed - a cache to keep track of which includes have already been processed
94
+ */
95
+ interpolate(file: ScriptMetadata, processed?: Set<string>): string;
96
+ loadCommand(filename: string, cache?: Map<string, ScriptMetadata>): Promise<Command>;
97
+ /**
98
+ * Load redis lua scripts.
99
+ * The name of the script must have the following format:
100
+ *
101
+ * cmdName-numKeys.lua
102
+ *
103
+ * cmdName must be in camel case format.
104
+ *
105
+ * For example:
106
+ * moveToFinish-3.lua
107
+ *
108
+ */
109
+ loadScripts(dir?: string, cache?: Map<string, ScriptMetadata>): Promise<Command[]>;
110
+ /**
111
+ * Attach all lua scripts in a given directory to a client instance
112
+ * @param client - redis client to attach script to
113
+ * @param pathname - the path to the directory containing the scripts
114
+ */
115
+ load(client: RedisClient, pathname: string): Promise<void>;
116
+ /**
117
+ * Clears the command cache
118
+ */
119
+ clearCache(): void;
120
+ }