agenda 4.3.0 → 5.0.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.
- package/History.md +12 -3
- package/README.md +38 -9
- package/dist/agenda/create.d.ts +2 -2
- package/dist/agenda/create.d.ts.map +1 -1
- package/dist/agenda/create.js.map +1 -1
- package/dist/agenda/define.d.ts +2 -2
- package/dist/agenda/define.d.ts.map +1 -1
- package/dist/agenda/define.js.map +1 -1
- package/dist/agenda/drain.d.ts +9 -0
- package/dist/agenda/drain.d.ts.map +1 -0
- package/dist/agenda/drain.js +46 -0
- package/dist/agenda/drain.js.map +1 -0
- package/dist/agenda/every.d.ts +2 -1
- package/dist/agenda/every.d.ts.map +1 -1
- package/dist/agenda/every.js +1 -1
- package/dist/agenda/every.js.map +1 -1
- package/dist/agenda/find-and-lock-next-job.d.ts.map +1 -1
- package/dist/agenda/find-and-lock-next-job.js +3 -4
- package/dist/agenda/find-and-lock-next-job.js.map +1 -1
- package/dist/agenda/index.d.ts +2 -0
- package/dist/agenda/index.d.ts.map +1 -1
- package/dist/agenda/index.js +2 -0
- package/dist/agenda/index.js.map +1 -1
- package/dist/agenda/now.d.ts +2 -2
- package/dist/agenda/now.d.ts.map +1 -1
- package/dist/agenda/now.js.map +1 -1
- package/dist/agenda/schedule.d.ts +3 -3
- package/dist/agenda/schedule.d.ts.map +1 -1
- package/dist/agenda/schedule.js.map +1 -1
- package/dist/job/compute-next-run-at.js +2 -2
- package/dist/job/compute-next-run-at.js.map +1 -1
- package/dist/job/index.d.ts +6 -3
- package/dist/job/index.d.ts.map +1 -1
- package/dist/job/index.js.map +1 -1
- package/lib/agenda/cancel.ts +28 -0
- package/lib/agenda/close.ts +37 -0
- package/lib/agenda/create.ts +22 -0
- package/lib/agenda/database.ts +63 -0
- package/lib/agenda/db-init.ts +45 -0
- package/lib/agenda/default-concurrency.ts +19 -0
- package/lib/agenda/default-lock-lifetime.ts +17 -0
- package/lib/agenda/default-lock-limit.ts +17 -0
- package/lib/agenda/define.ts +85 -0
- package/lib/agenda/disable.ts +28 -0
- package/lib/agenda/drain.ts +30 -0
- package/lib/agenda/enable.ts +29 -0
- package/lib/agenda/every.ts +86 -0
- package/lib/agenda/find-and-lock-next-job.ts +78 -0
- package/lib/agenda/has-mongo-protocol.ts +8 -0
- package/lib/agenda/index.ts +227 -0
- package/lib/agenda/job-processing-queue.ts +99 -0
- package/lib/agenda/jobs.ts +31 -0
- package/lib/agenda/lock-limit.ts +17 -0
- package/lib/agenda/max-concurrency.ts +20 -0
- package/lib/agenda/mongo.ts +21 -0
- package/lib/agenda/name.ts +16 -0
- package/lib/agenda/now.ts +31 -0
- package/lib/agenda/process-every.ts +18 -0
- package/lib/agenda/purge.ts +19 -0
- package/lib/agenda/save-job.ts +185 -0
- package/lib/agenda/schedule.ts +79 -0
- package/lib/agenda/sort.ts +17 -0
- package/lib/agenda/start.ts +30 -0
- package/lib/agenda/stop.ts +49 -0
- package/lib/cjs.ts +5 -0
- package/lib/index.ts +11 -0
- package/lib/job/compute-next-run-at.ts +191 -0
- package/lib/job/disable.ts +11 -0
- package/lib/job/enable.ts +11 -0
- package/lib/job/fail.ts +29 -0
- package/lib/job/index.ts +221 -0
- package/lib/job/is-running.ts +29 -0
- package/lib/job/priority.ts +11 -0
- package/lib/job/remove.ts +10 -0
- package/lib/job/repeat-at.ts +12 -0
- package/lib/job/repeat-every.ts +40 -0
- package/lib/job/run.ts +125 -0
- package/lib/job/save.ts +11 -0
- package/lib/job/schedule.ts +15 -0
- package/lib/job/set-shouldsaveresult.ts +10 -0
- package/lib/job/to-json.ts +36 -0
- package/lib/job/touch.ts +11 -0
- package/lib/job/unique.ts +18 -0
- package/lib/utils/create-job.ts +13 -0
- package/lib/utils/index.ts +3 -0
- package/lib/utils/parse-priority.ts +37 -0
- package/lib/utils/process-jobs.ts +379 -0
- package/package.json +14 -12
- package/tsconfig.json +72 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Job } from ".";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Sets a job to repeat at a specific time
|
|
5
|
+
* @name Job#repeatAt
|
|
6
|
+
* @function
|
|
7
|
+
* @param time time to repeat job at (human readable or number)
|
|
8
|
+
*/
|
|
9
|
+
export const repeatAt = function (this: Job, time: string): Job {
|
|
10
|
+
this.attrs.repeatAt = time;
|
|
11
|
+
return this;
|
|
12
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Job } from ".";
|
|
2
|
+
|
|
3
|
+
export interface JobOptions {
|
|
4
|
+
timezone?: string;
|
|
5
|
+
startDate?: Date | number;
|
|
6
|
+
endDate?: Date | number;
|
|
7
|
+
skipDays?: string;
|
|
8
|
+
skipImmediate?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Sets a job to repeat every X amount of time
|
|
13
|
+
* @name Job#repeatEvery
|
|
14
|
+
* @function
|
|
15
|
+
* @param interval repeat every X
|
|
16
|
+
* @param options options to use for job
|
|
17
|
+
*/
|
|
18
|
+
export const repeatEvery = function (
|
|
19
|
+
this: Job,
|
|
20
|
+
interval: string,
|
|
21
|
+
options: JobOptions = {}
|
|
22
|
+
): Job {
|
|
23
|
+
this.attrs.repeatInterval = interval;
|
|
24
|
+
this.attrs.repeatTimezone = options.timezone ? options.timezone : null;
|
|
25
|
+
// Following options are added to handle start day
|
|
26
|
+
// and cases like run job every x days (skip some days)
|
|
27
|
+
this.attrs.startDate = options.startDate ?? null;
|
|
28
|
+
this.attrs.endDate = options.endDate ?? null;
|
|
29
|
+
this.attrs.skipDays = options.skipDays ?? null;
|
|
30
|
+
if (options.skipImmediate) {
|
|
31
|
+
// Set the lastRunAt time to the nextRunAt so that the new nextRunAt will be computed in reference to the current value.
|
|
32
|
+
this.attrs.lastRunAt = this.attrs.nextRunAt || new Date();
|
|
33
|
+
this.computeNextRunAt();
|
|
34
|
+
this.attrs.lastRunAt = undefined;
|
|
35
|
+
} else {
|
|
36
|
+
this.computeNextRunAt();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return this;
|
|
40
|
+
};
|
package/lib/job/run.ts
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import createDebugger from "debug";
|
|
2
|
+
import { Job } from ".";
|
|
3
|
+
|
|
4
|
+
const debug = createDebugger("agenda:job");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal method (RUN)
|
|
8
|
+
* @name Job#run
|
|
9
|
+
* @function
|
|
10
|
+
*/
|
|
11
|
+
export const run = async function (this: Job): Promise<Job> {
|
|
12
|
+
const { agenda } = this;
|
|
13
|
+
const definition = agenda._definitions[this.attrs.name];
|
|
14
|
+
|
|
15
|
+
// @TODO: this lint issue should be looked into: https://eslint.org/docs/rules/no-async-promise-executor
|
|
16
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
17
|
+
return new Promise(async (resolve, reject) => {
|
|
18
|
+
this.attrs.lastRunAt = new Date();
|
|
19
|
+
debug(
|
|
20
|
+
"[%s:%s] setting lastRunAt to: %s",
|
|
21
|
+
this.attrs.name,
|
|
22
|
+
this.attrs._id,
|
|
23
|
+
this.attrs.lastRunAt.toISOString()
|
|
24
|
+
);
|
|
25
|
+
this.computeNextRunAt();
|
|
26
|
+
await this.save();
|
|
27
|
+
|
|
28
|
+
let finished = false;
|
|
29
|
+
const jobCallback = async (error?: Error, result?: unknown) => {
|
|
30
|
+
// We don't want to complete the job multiple times
|
|
31
|
+
if (finished) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
finished = true;
|
|
36
|
+
|
|
37
|
+
if (error) {
|
|
38
|
+
this.fail(error);
|
|
39
|
+
} else {
|
|
40
|
+
this.attrs.lastFinishedAt = new Date();
|
|
41
|
+
|
|
42
|
+
if(this.attrs.shouldSaveResult && result) {
|
|
43
|
+
this.attrs.result = result;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
this.attrs.lockedAt = null;
|
|
48
|
+
|
|
49
|
+
await this.save().catch((error: Error) => {
|
|
50
|
+
debug(
|
|
51
|
+
"[%s:%s] failed to be saved to MongoDB",
|
|
52
|
+
this.attrs.name,
|
|
53
|
+
this.attrs._id
|
|
54
|
+
);
|
|
55
|
+
reject(error);
|
|
56
|
+
});
|
|
57
|
+
debug(
|
|
58
|
+
"[%s:%s] was saved successfully to MongoDB",
|
|
59
|
+
this.attrs.name,
|
|
60
|
+
this.attrs._id
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
if (error) {
|
|
64
|
+
agenda.emit("fail", error, this);
|
|
65
|
+
agenda.emit("fail:" + this.attrs.name, error, this);
|
|
66
|
+
debug(
|
|
67
|
+
"[%s:%s] has failed [%s]",
|
|
68
|
+
this.attrs.name,
|
|
69
|
+
this.attrs._id,
|
|
70
|
+
error.message
|
|
71
|
+
);
|
|
72
|
+
} else {
|
|
73
|
+
agenda.emit("success", this);
|
|
74
|
+
agenda.emit("success:" + this.attrs.name, this);
|
|
75
|
+
debug("[%s:%s] has succeeded", this.attrs.name, this.attrs._id);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
agenda.emit("complete", this);
|
|
79
|
+
agenda.emit("complete:" + this.attrs.name, this);
|
|
80
|
+
debug(
|
|
81
|
+
"[%s:%s] job finished at [%s] and was unlocked",
|
|
82
|
+
this.attrs.name,
|
|
83
|
+
this.attrs._id,
|
|
84
|
+
this.attrs.lastFinishedAt
|
|
85
|
+
);
|
|
86
|
+
// Curiously, we still resolve successfully if the job processor failed.
|
|
87
|
+
// Agenda is not equipped to handle errors originating in user code, so, we leave them to inspect the side-effects of job.fail()
|
|
88
|
+
resolve(this);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
agenda.emit("start", this);
|
|
93
|
+
agenda.emit("start:" + this.attrs.name, this);
|
|
94
|
+
debug("[%s:%s] starting job", this.attrs.name, this.attrs._id);
|
|
95
|
+
if (!definition) {
|
|
96
|
+
debug(
|
|
97
|
+
"[%s:%s] has no definition, can not run",
|
|
98
|
+
this.attrs.name,
|
|
99
|
+
this.attrs._id
|
|
100
|
+
);
|
|
101
|
+
throw new Error("Undefined job");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (definition.fn.length === 2) {
|
|
105
|
+
debug(
|
|
106
|
+
"[%s:%s] process function being called",
|
|
107
|
+
this.attrs.name,
|
|
108
|
+
this.attrs._id
|
|
109
|
+
);
|
|
110
|
+
await definition.fn(this, jobCallback);
|
|
111
|
+
} else {
|
|
112
|
+
debug(
|
|
113
|
+
"[%s:%s] process function being called",
|
|
114
|
+
this.attrs.name,
|
|
115
|
+
this.attrs._id
|
|
116
|
+
);
|
|
117
|
+
const result = await definition.fn(this);
|
|
118
|
+
await jobCallback(undefined, result);
|
|
119
|
+
}
|
|
120
|
+
} catch (error) {
|
|
121
|
+
debug("[%s:%s] unknown error occurred", this.attrs.name, this.attrs._id);
|
|
122
|
+
await jobCallback(error as Error);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
};
|
package/lib/job/save.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Job } from ".";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Saves a job into the MongoDB
|
|
5
|
+
* @name Job#
|
|
6
|
+
* @function
|
|
7
|
+
* @returns instance of Job resolved after job is saved or errors
|
|
8
|
+
*/
|
|
9
|
+
export const save = async function (this: Job): Promise<Job> {
|
|
10
|
+
return this.agenda.saveJob(this);
|
|
11
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// @ts-expect-error
|
|
2
|
+
import date from "date.js";
|
|
3
|
+
import { Job } from ".";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Schedules a job to run at specified time
|
|
7
|
+
* @name Job#schedule
|
|
8
|
+
* @function
|
|
9
|
+
* @param time schedule a job to run "then"
|
|
10
|
+
*/
|
|
11
|
+
export const schedule = function (this: Job, time: string | Date): Job {
|
|
12
|
+
const d = new Date(time);
|
|
13
|
+
this.attrs.nextRunAt = Number.isNaN(d.getTime()) ? date(time) : d;
|
|
14
|
+
return this;
|
|
15
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Job } from ".";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Sets the flag if the return value of the job should be persisted
|
|
5
|
+
* @param shouldSaveResult flag if the return value of the job should be persisted
|
|
6
|
+
*/
|
|
7
|
+
export const setShouldSaveResult = function (this: Job, shouldSaveResult: boolean): Job {
|
|
8
|
+
this.attrs.shouldSaveResult = shouldSaveResult;
|
|
9
|
+
return this;
|
|
10
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Job, JobAttributes } from ".";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Given a job, turn it into an object we can store in Mongo
|
|
5
|
+
* @name Job#toJSON
|
|
6
|
+
* @function
|
|
7
|
+
* @returns json object from Job
|
|
8
|
+
*/
|
|
9
|
+
export const toJson = function (this: Job): Partial<JobAttributes> {
|
|
10
|
+
const attrs = this.attrs || {};
|
|
11
|
+
const result = {};
|
|
12
|
+
|
|
13
|
+
for (const prop in attrs) {
|
|
14
|
+
if ({}.hasOwnProperty.call(attrs, prop)) {
|
|
15
|
+
// @ts-expect-error index signature missing
|
|
16
|
+
result[prop] = attrs[prop];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const dates = [
|
|
21
|
+
"lastRunAt",
|
|
22
|
+
"lastFinishedAt",
|
|
23
|
+
"nextRunAt",
|
|
24
|
+
"failedAt",
|
|
25
|
+
"lockedAt",
|
|
26
|
+
];
|
|
27
|
+
dates.forEach((d) => {
|
|
28
|
+
// @ts-expect-error index signature missing
|
|
29
|
+
if (result[d]) {
|
|
30
|
+
// @ts-expect-error index signature missing
|
|
31
|
+
result[d] = new Date(result[d]);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return result;
|
|
36
|
+
};
|
package/lib/job/touch.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Job } from ".";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Updates "lockedAt" time so the job does not get picked up again
|
|
5
|
+
* @name Job#touch
|
|
6
|
+
* @function
|
|
7
|
+
*/
|
|
8
|
+
export const touch = async function (this: Job): Promise<Job> {
|
|
9
|
+
this.attrs.lockedAt = new Date();
|
|
10
|
+
return this.save();
|
|
11
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Job } from ".";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Data to ensure is unique for job to be created
|
|
5
|
+
* @name Job#unique
|
|
6
|
+
* @function
|
|
7
|
+
* @param unique mongo data query for unique
|
|
8
|
+
* @param options unique options
|
|
9
|
+
*/
|
|
10
|
+
export const unique = function (
|
|
11
|
+
this: Job,
|
|
12
|
+
unique: any,
|
|
13
|
+
options?: { insertOnly: boolean }
|
|
14
|
+
): Job {
|
|
15
|
+
this.attrs.unique = unique;
|
|
16
|
+
this.attrs.uniqueOpts = options;
|
|
17
|
+
return this;
|
|
18
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Agenda } from "../agenda";
|
|
2
|
+
import { Job, JobAttributes } from "../job";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Create Job object from data
|
|
6
|
+
* @param {Object} agenda instance of Agenda
|
|
7
|
+
* @param {Object} jobData job data
|
|
8
|
+
* @returns {Job} returns created job
|
|
9
|
+
*/
|
|
10
|
+
export const createJob = (agenda: Agenda, jobData: JobAttributes): Job => {
|
|
11
|
+
jobData.agenda = agenda;
|
|
12
|
+
return new Job(jobData);
|
|
13
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { JobPriority } from "../agenda/define";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Internal method to turn priority into a number
|
|
5
|
+
* @param priority string to parse into number
|
|
6
|
+
*/
|
|
7
|
+
export const parsePriority = (priority: string | number): number => {
|
|
8
|
+
if (typeof priority === "number") {
|
|
9
|
+
return priority;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
switch (priority) {
|
|
13
|
+
case "lowest": {
|
|
14
|
+
return JobPriority.lowest;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
case "low": {
|
|
18
|
+
return JobPriority.low;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
case "normal": {
|
|
22
|
+
return JobPriority.normal;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
case "high": {
|
|
26
|
+
return JobPriority.high;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
case "highest": {
|
|
30
|
+
return JobPriority.highest;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
default: {
|
|
34
|
+
return JobPriority.normal;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|