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.
Files changed (89) hide show
  1. package/History.md +12 -3
  2. package/README.md +38 -9
  3. package/dist/agenda/create.d.ts +2 -2
  4. package/dist/agenda/create.d.ts.map +1 -1
  5. package/dist/agenda/create.js.map +1 -1
  6. package/dist/agenda/define.d.ts +2 -2
  7. package/dist/agenda/define.d.ts.map +1 -1
  8. package/dist/agenda/define.js.map +1 -1
  9. package/dist/agenda/drain.d.ts +9 -0
  10. package/dist/agenda/drain.d.ts.map +1 -0
  11. package/dist/agenda/drain.js +46 -0
  12. package/dist/agenda/drain.js.map +1 -0
  13. package/dist/agenda/every.d.ts +2 -1
  14. package/dist/agenda/every.d.ts.map +1 -1
  15. package/dist/agenda/every.js +1 -1
  16. package/dist/agenda/every.js.map +1 -1
  17. package/dist/agenda/find-and-lock-next-job.d.ts.map +1 -1
  18. package/dist/agenda/find-and-lock-next-job.js +3 -4
  19. package/dist/agenda/find-and-lock-next-job.js.map +1 -1
  20. package/dist/agenda/index.d.ts +2 -0
  21. package/dist/agenda/index.d.ts.map +1 -1
  22. package/dist/agenda/index.js +2 -0
  23. package/dist/agenda/index.js.map +1 -1
  24. package/dist/agenda/now.d.ts +2 -2
  25. package/dist/agenda/now.d.ts.map +1 -1
  26. package/dist/agenda/now.js.map +1 -1
  27. package/dist/agenda/schedule.d.ts +3 -3
  28. package/dist/agenda/schedule.d.ts.map +1 -1
  29. package/dist/agenda/schedule.js.map +1 -1
  30. package/dist/job/compute-next-run-at.js +2 -2
  31. package/dist/job/compute-next-run-at.js.map +1 -1
  32. package/dist/job/index.d.ts +6 -3
  33. package/dist/job/index.d.ts.map +1 -1
  34. package/dist/job/index.js.map +1 -1
  35. package/lib/agenda/cancel.ts +28 -0
  36. package/lib/agenda/close.ts +37 -0
  37. package/lib/agenda/create.ts +22 -0
  38. package/lib/agenda/database.ts +63 -0
  39. package/lib/agenda/db-init.ts +45 -0
  40. package/lib/agenda/default-concurrency.ts +19 -0
  41. package/lib/agenda/default-lock-lifetime.ts +17 -0
  42. package/lib/agenda/default-lock-limit.ts +17 -0
  43. package/lib/agenda/define.ts +85 -0
  44. package/lib/agenda/disable.ts +28 -0
  45. package/lib/agenda/drain.ts +30 -0
  46. package/lib/agenda/enable.ts +29 -0
  47. package/lib/agenda/every.ts +86 -0
  48. package/lib/agenda/find-and-lock-next-job.ts +78 -0
  49. package/lib/agenda/has-mongo-protocol.ts +8 -0
  50. package/lib/agenda/index.ts +227 -0
  51. package/lib/agenda/job-processing-queue.ts +99 -0
  52. package/lib/agenda/jobs.ts +31 -0
  53. package/lib/agenda/lock-limit.ts +17 -0
  54. package/lib/agenda/max-concurrency.ts +20 -0
  55. package/lib/agenda/mongo.ts +21 -0
  56. package/lib/agenda/name.ts +16 -0
  57. package/lib/agenda/now.ts +31 -0
  58. package/lib/agenda/process-every.ts +18 -0
  59. package/lib/agenda/purge.ts +19 -0
  60. package/lib/agenda/save-job.ts +185 -0
  61. package/lib/agenda/schedule.ts +79 -0
  62. package/lib/agenda/sort.ts +17 -0
  63. package/lib/agenda/start.ts +30 -0
  64. package/lib/agenda/stop.ts +49 -0
  65. package/lib/cjs.ts +5 -0
  66. package/lib/index.ts +11 -0
  67. package/lib/job/compute-next-run-at.ts +191 -0
  68. package/lib/job/disable.ts +11 -0
  69. package/lib/job/enable.ts +11 -0
  70. package/lib/job/fail.ts +29 -0
  71. package/lib/job/index.ts +221 -0
  72. package/lib/job/is-running.ts +29 -0
  73. package/lib/job/priority.ts +11 -0
  74. package/lib/job/remove.ts +10 -0
  75. package/lib/job/repeat-at.ts +12 -0
  76. package/lib/job/repeat-every.ts +40 -0
  77. package/lib/job/run.ts +125 -0
  78. package/lib/job/save.ts +11 -0
  79. package/lib/job/schedule.ts +15 -0
  80. package/lib/job/set-shouldsaveresult.ts +10 -0
  81. package/lib/job/to-json.ts +36 -0
  82. package/lib/job/touch.ts +11 -0
  83. package/lib/job/unique.ts +18 -0
  84. package/lib/utils/create-job.ts +13 -0
  85. package/lib/utils/index.ts +3 -0
  86. package/lib/utils/parse-priority.ts +37 -0
  87. package/lib/utils/process-jobs.ts +379 -0
  88. package/package.json +14 -12
  89. package/tsconfig.json +72 -0
@@ -0,0 +1,79 @@
1
+ import createDebugger from "debug";
2
+ import { Agenda } from ".";
3
+ import { Job, JobAttributesData } from "../job";
4
+
5
+ const debug = createDebugger("agenda:schedule");
6
+
7
+ /**
8
+ * Schedule a job or jobs at a specific time
9
+ * @name Agenda#schedule
10
+ * @function
11
+ * @param when when the job gets run
12
+ * @param names array of job names to run
13
+ * @param data data to send to job
14
+ * @returns job or jobs created
15
+ */
16
+ export function schedule<T extends JobAttributesData>(this: Agenda, when: string | Date, names: string, data: T): Promise<Job>;
17
+ export function schedule<T extends JobAttributesData>(this: Agenda, when: string | Date, names: string[], data: T): Promise<Job[]>;
18
+ export function schedule<T extends JobAttributesData> (
19
+ this: Agenda,
20
+ when: string | Date,
21
+ names: string | string[],
22
+ data: T,
23
+ ): Promise<Job | Job[]> {
24
+ /**
25
+ * Internal method that creates a job with given date
26
+ * @param when when the job gets run
27
+ * @param name of job to run
28
+ * @param data data to send to job
29
+ * @returns instance of new job
30
+ */
31
+ const createJob = async (
32
+ when: string | Date,
33
+ name: string,
34
+ data: any
35
+ ): Promise<Job> => {
36
+ const job = this.create(name, data);
37
+
38
+ await job.schedule(when).save();
39
+
40
+ return job;
41
+ };
42
+
43
+ /**
44
+ * Internal helper method that calls createJob on a names array
45
+ * @param when when the job gets run
46
+ * @param names names of jobs to run
47
+ * @param data data to send to job
48
+ * @returns jobs that were created
49
+ */
50
+ const createJobs = async (
51
+ when: string | Date,
52
+ names: string[],
53
+ data: any
54
+ ): Promise<Job[]> => {
55
+ try {
56
+ const createJobList: Array<Promise<Job>> = [];
57
+ names.map((name) => createJobList.push(createJob(when, name, data)));
58
+ debug("Agenda.schedule()::createJobs() -> all jobs created successfully");
59
+ return Promise.all(createJobList);
60
+ } catch (error) {
61
+ debug(
62
+ "Agenda.schedule()::createJobs() -> error creating one or more of the jobs"
63
+ );
64
+ throw error;
65
+ }
66
+ };
67
+
68
+ if (typeof names === "string") {
69
+ debug("Agenda.schedule(%s, %O, [%O], cb)", when, names);
70
+ return createJob(when, names, data);
71
+ }
72
+
73
+ if (Array.isArray(names)) {
74
+ debug("Agenda.schedule(%s, %O, [%O])", when, names);
75
+ return createJobs(when, names, data);
76
+ }
77
+
78
+ throw new TypeError("Name must be string or array of strings")
79
+ };
@@ -0,0 +1,17 @@
1
+ import createDebugger from "debug";
2
+ import { Agenda } from ".";
3
+
4
+ const debug = createDebugger("agenda:sort");
5
+
6
+ /**
7
+ * Set the sort query for finding next job
8
+ * Default is { nextRunAt: 1, priority: -1 }
9
+ * @name Agenda#sort
10
+ * @function
11
+ * @param query sort query object for MongoDB
12
+ */
13
+ export const sort = function (this: Agenda, query: any): Agenda {
14
+ debug("Agenda.sort([Object])");
15
+ this._sort = query;
16
+ return this;
17
+ };
@@ -0,0 +1,30 @@
1
+ import createDebugger from "debug";
2
+ import { Agenda } from ".";
3
+ import { processJobs } from "../utils";
4
+
5
+ const debug = createDebugger("agenda:start");
6
+
7
+ /**
8
+ * Starts processing jobs using processJobs() methods, storing an interval ID
9
+ * This method will only resolve if a db has been set up beforehand.
10
+ * @name Agenda#start
11
+ * @function
12
+ * @returns resolves if db set beforehand, returns undefined otherwise
13
+ */
14
+ export const start = async function (this: Agenda): Promise<void | unknown> {
15
+ if (this._processInterval) {
16
+ debug("Agenda.start was already called, ignoring");
17
+ return this._ready;
18
+ }
19
+
20
+ await this._ready;
21
+ debug(
22
+ "Agenda.start called, creating interval to call processJobs every [%dms]",
23
+ this._processEvery
24
+ );
25
+ this._processInterval = setInterval(
26
+ processJobs.bind(this),
27
+ this._processEvery
28
+ );
29
+ process.nextTick(processJobs.bind(this));
30
+ };
@@ -0,0 +1,49 @@
1
+ import createDebugger from "debug";
2
+ import { Agenda } from ".";
3
+
4
+ const debug = createDebugger("agenda:stop");
5
+
6
+ /**
7
+ * Clear the interval that processes the jobs
8
+ * @name Agenda#stop
9
+ * @function
10
+ * @returns resolves when job unlocking fails or passes
11
+ */
12
+ export const stop = async function (this: Agenda): Promise<void> {
13
+ /**
14
+ * Internal method to unlock jobs so that they can be re-run
15
+ * NOTE: May need to update what properties get set here, since job unlocking seems to fail
16
+ * @access private
17
+ * @returns resolves when job unlocking fails or passes
18
+ */
19
+ const _unlockJobs = async (): Promise<void> => {
20
+ return new Promise((resolve, reject) => {
21
+ debug("Agenda._unlockJobs()");
22
+ const jobIds = this._lockedJobs.map((job) => job.attrs._id);
23
+
24
+ if (jobIds.length === 0) {
25
+ debug("no jobs to unlock");
26
+ resolve();
27
+ }
28
+
29
+ debug("about to unlock jobs with ids: %O", jobIds);
30
+ this._collection.updateMany(
31
+ { _id: { $in: jobIds } },
32
+ { $set: { lockedAt: null } },
33
+ (error) => {
34
+ if (error) {
35
+ reject(error);
36
+ }
37
+
38
+ this._lockedJobs = [];
39
+ resolve();
40
+ }
41
+ );
42
+ });
43
+ };
44
+
45
+ debug("Agenda.stop called, clearing interval for processJobs()");
46
+ clearInterval(this._processInterval);
47
+ this._processInterval = undefined;
48
+ return _unlockJobs();
49
+ };
package/lib/cjs.ts ADDED
@@ -0,0 +1,5 @@
1
+ // old common js export (see index.ts for module exports)
2
+
3
+ import { Agenda } from "./agenda";
4
+ module.exports = Agenda;
5
+ module.exports.Agenda = Agenda;
package/lib/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ // module export, beware: cjs.ts is exported as main entry point!
2
+ export * from "./agenda";
3
+ export * from "./job";
4
+
5
+ export { DefineOptions, JobPriority, Processor } from "./agenda/define";
6
+ export { JobOptions } from "./job/repeat-every";
7
+
8
+ import { Agenda } from "./agenda";
9
+ export { Agenda };
10
+
11
+ export default Agenda;
@@ -0,0 +1,191 @@
1
+ import { Job } from ".";
2
+ import * as parser from "cron-parser";
3
+ import humanInterval from "human-interval";
4
+ import createDebugger from "debug";
5
+ import moment from "moment-timezone";
6
+ // @ts-expect-error
7
+ import date from "date.js";
8
+
9
+ const debug = createDebugger("agenda:job");
10
+
11
+ /**
12
+ * Internal method used to compute next time a job should run and sets the proper values
13
+ * @name Job#computeNextRunAt
14
+ * @function
15
+ */
16
+ export const computeNextRunAt = function (this: Job): Job {
17
+ const interval = this.attrs.repeatInterval;
18
+ const timezone = this.attrs.repeatTimezone;
19
+ const { repeatAt } = this.attrs;
20
+ const previousNextRunAt = this.attrs.nextRunAt || new Date();
21
+ this.attrs.nextRunAt = undefined;
22
+
23
+ const dateForTimezone = (date: Date): moment.Moment => {
24
+ const mdate: moment.Moment = moment(date);
25
+ if (timezone) {
26
+ mdate.tz(timezone);
27
+ }
28
+
29
+ return mdate;
30
+ };
31
+
32
+ /**
33
+ * Internal method that computes the interval
34
+ */
35
+ const computeFromInterval = () => {
36
+ debug(
37
+ "[%s:%s] computing next run via interval [%s]",
38
+ this.attrs.name,
39
+ this.attrs._id,
40
+ interval
41
+ );
42
+ const dateNow = new Date();
43
+ let lastRun: Date = this.attrs.lastRunAt || dateNow;
44
+ let { startDate, endDate, skipDays } = this.attrs;
45
+ lastRun = dateForTimezone(lastRun).toDate();
46
+ const cronOptions: any = { currentDate: lastRun };
47
+ if (timezone) {
48
+ cronOptions.tz = timezone;
49
+ }
50
+
51
+ try {
52
+ let cronTime = parser.parseExpression(interval!, cronOptions);
53
+ let nextDate: Date | null = cronTime.next().toDate();
54
+ if (
55
+ nextDate.getTime() === lastRun.getTime() ||
56
+ nextDate.getTime() <= previousNextRunAt.getTime()
57
+ ) {
58
+ // Handle cronTime giving back the same date for the next run time
59
+ cronOptions.currentDate = new Date(lastRun.getTime() + 1000);
60
+ cronTime = parser.parseExpression(interval!, cronOptions);
61
+ nextDate = cronTime.next().toDate();
62
+ }
63
+
64
+ // If start date is present, check if the nextDate should be larger or equal to startDate. If not set startDate as nextDate
65
+ if (startDate) {
66
+ startDate = moment
67
+ .tz(moment(startDate).format("YYYY-MM-DD HH:mm"), timezone!)
68
+ .toDate();
69
+ if (startDate > nextDate) {
70
+ cronOptions.currentDate = startDate;
71
+ cronTime = parser.parseExpression(interval!, cronOptions);
72
+ nextDate = cronTime.next().toDate();
73
+ }
74
+ }
75
+
76
+ // If job has run in the past and skipDays is not null, add skipDays to nextDate
77
+ if (dateNow > lastRun && skipDays !== null) {
78
+ try {
79
+ nextDate = new Date(
80
+ nextDate.getTime() + (humanInterval(skipDays) ?? 0)
81
+ );
82
+ } catch {}
83
+ }
84
+
85
+ // If endDate is less than the nextDate, set nextDate to null to stop the job from running further
86
+ if (endDate) {
87
+ const endDateDate: Date = moment
88
+ .tz(moment(endDate).format("YYYY-MM-DD HH:mm"), timezone!)
89
+ .toDate();
90
+ if (nextDate > endDateDate) {
91
+ nextDate = null;
92
+ }
93
+ }
94
+
95
+ this.attrs.nextRunAt = nextDate;
96
+ debug(
97
+ "[%s:%s] nextRunAt set to [%s]",
98
+ this.attrs.name,
99
+ this.attrs._id,
100
+ this.attrs.nextRunAt?.toISOString()
101
+ );
102
+ // Either `xo` linter or Node.js 8 stumble on this line if it isn't just ignored
103
+ } catch {
104
+ debug(
105
+ "[%s:%s] failed nextRunAt based on interval [%s]",
106
+ this.attrs.name,
107
+ this.attrs._id,
108
+ interval
109
+ );
110
+ // Nope, humanInterval then!
111
+ try {
112
+ if (!this.attrs.lastRunAt && humanInterval(interval)) {
113
+ this.attrs.nextRunAt = lastRun;
114
+ debug(
115
+ "[%s:%s] nextRunAt set to [%s]",
116
+ this.attrs.name,
117
+ this.attrs._id,
118
+ this.attrs.nextRunAt.toISOString()
119
+ );
120
+ } else {
121
+ this.attrs.nextRunAt = new Date(
122
+ lastRun.getTime() + (humanInterval(interval) ?? 0)
123
+ );
124
+ debug(
125
+ "[%s:%s] nextRunAt set to [%s]",
126
+ this.attrs.name,
127
+ this.attrs._id,
128
+ this.attrs.nextRunAt.toISOString()
129
+ );
130
+ }
131
+ // Either `xo` linter or Node.js 8 stumble on this line if it isn't just ignored
132
+ } catch {}
133
+ } finally {
134
+ if (!this.attrs.nextRunAt?.getTime()) {
135
+ this.attrs.nextRunAt = undefined;
136
+ debug(
137
+ "[%s:%s] failed to calculate nextRunAt due to invalid repeat interval",
138
+ this.attrs.name,
139
+ this.attrs._id
140
+ );
141
+ this.fail(
142
+ "failed to calculate nextRunAt due to invalid repeat interval"
143
+ );
144
+ }
145
+ }
146
+ };
147
+
148
+ /**
149
+ * Internal method to compute next run time from the repeat string
150
+ */
151
+ const computeFromRepeatAt = () => {
152
+ const lastRun = this.attrs.lastRunAt || new Date();
153
+ const nextDate: Date = date(repeatAt);
154
+
155
+ // If you do not specify offset date for below test it will fail for ms
156
+ const offset = Date.now();
157
+ if (offset === date(repeatAt, offset).getTime()) {
158
+ this.attrs.nextRunAt = undefined;
159
+ debug(
160
+ "[%s:%s] failed to calculate repeatAt due to invalid format",
161
+ this.attrs.name,
162
+ this.attrs._id
163
+ );
164
+ this.fail("failed to calculate repeatAt time due to invalid format");
165
+ } else if (nextDate.getTime() === lastRun.getTime()) {
166
+ this.attrs.nextRunAt = date("tomorrow at ", repeatAt);
167
+ debug(
168
+ "[%s:%s] nextRunAt set to [%s]",
169
+ this.attrs.name,
170
+ this.attrs._id,
171
+ this.attrs.nextRunAt?.toISOString()
172
+ );
173
+ } else {
174
+ this.attrs.nextRunAt = date(repeatAt);
175
+ debug(
176
+ "[%s:%s] nextRunAt set to [%s]",
177
+ this.attrs.name,
178
+ this.attrs._id,
179
+ this.attrs.nextRunAt?.toISOString()
180
+ );
181
+ }
182
+ };
183
+
184
+ if (interval) {
185
+ computeFromInterval();
186
+ } else if (repeatAt) {
187
+ computeFromRepeatAt();
188
+ }
189
+
190
+ return this;
191
+ };
@@ -0,0 +1,11 @@
1
+ import { Job } from ".";
2
+
3
+ /**
4
+ * Prevents the job type from running
5
+ * @name Job#disable
6
+ * @function
7
+ */
8
+ export const disable = function (this: Job): Job {
9
+ this.attrs.disabled = true;
10
+ return this;
11
+ };
@@ -0,0 +1,11 @@
1
+ import { Job } from ".";
2
+
3
+ /**
4
+ * Allows job type to run
5
+ * @name Job#enable
6
+ * @function
7
+ */
8
+ export const enable = function (this: Job): Job {
9
+ this.attrs.disabled = false;
10
+ return this;
11
+ };
@@ -0,0 +1,29 @@
1
+ import createDebugger from "debug";
2
+ import { Job } from ".";
3
+
4
+ const debug = createDebugger("agenda:job");
5
+
6
+ /**
7
+ * Fails the job with a reason (error) specified
8
+ * @name Job#fail
9
+ * @function
10
+ * @param reason reason job failed
11
+ */
12
+ export const fail = function (this: Job, reason: string | Error): Job {
13
+ if (reason instanceof Error) {
14
+ reason = reason.message;
15
+ }
16
+
17
+ this.attrs.failReason = reason;
18
+ this.attrs.failCount = (this.attrs.failCount || 0) + 1;
19
+ const now = new Date();
20
+ this.attrs.failedAt = now;
21
+ this.attrs.lastFinishedAt = now;
22
+ debug(
23
+ "[%s:%s] fail() called [%d] times so far",
24
+ this.attrs.name,
25
+ this.attrs._id,
26
+ this.attrs.failCount
27
+ );
28
+ return this;
29
+ };
@@ -0,0 +1,221 @@
1
+ import { toJson } from "./to-json";
2
+ import { computeNextRunAt } from "./compute-next-run-at";
3
+ import { repeatEvery } from "./repeat-every";
4
+ import { repeatAt } from "./repeat-at";
5
+ import { disable } from "./disable";
6
+ import { enable } from "./enable";
7
+ import { unique } from "./unique";
8
+ import { schedule } from "./schedule";
9
+ import { priority } from "./priority";
10
+ import { fail } from "./fail";
11
+ import { run } from "./run";
12
+ import { isRunning } from "./is-running";
13
+ import { save } from "./save";
14
+ import { remove } from "./remove";
15
+ import { touch } from "./touch";
16
+ import { setShouldSaveResult } from "./set-shouldsaveresult";
17
+ import { parsePriority } from "../utils";
18
+ import { Agenda } from "../agenda";
19
+ import { JobPriority } from "../agenda/define";
20
+ import * as mongodb from "mongodb";
21
+
22
+ type Modify<T, R> = Omit<T, keyof R> & R
23
+
24
+ export interface JobAttributesData {
25
+ [key: string]: any;
26
+ }
27
+ export interface JobAttributes<
28
+ T extends JobAttributesData = JobAttributesData
29
+ > {
30
+ /**
31
+ * The record identity.
32
+ */
33
+ _id: mongodb.ObjectId;
34
+
35
+ agenda: Agenda;
36
+
37
+ /**
38
+ * The type of the job (single|normal).
39
+ */
40
+ type: string;
41
+
42
+ /**
43
+ * The name of the job.
44
+ */
45
+ name: string;
46
+
47
+ /**
48
+ * Job's state
49
+ */
50
+ disabled?: boolean;
51
+
52
+ /**
53
+ * Date/time the job will run next.
54
+ */
55
+ nextRunAt?: Date | null;
56
+
57
+ /**
58
+ * Date/time the job was locked.
59
+ */
60
+ lockedAt?: Date | null;
61
+
62
+ /**
63
+ * The priority of the job.
64
+ */
65
+ priority: number | string;
66
+
67
+ /**
68
+ * The job details.
69
+ */
70
+ data: T;
71
+
72
+ unique?: any;
73
+ uniqueOpts?: {
74
+ insertOnly: boolean;
75
+ };
76
+
77
+ /**
78
+ * How often the job is repeated using a human-readable or cron format.
79
+ */
80
+ repeatInterval?: string;
81
+
82
+ /**
83
+ * The timezone that conforms to [moment-timezone](http://momentjs.com/timezone/).
84
+ */
85
+ repeatTimezone?: string | null;
86
+
87
+ repeatAt?: string;
88
+
89
+ /**
90
+ * Date/time the job was last run.
91
+ */
92
+ lastRunAt?: Date;
93
+
94
+ /**
95
+ * Date/time the job last finished running.
96
+ */
97
+ lastFinishedAt?: Date;
98
+
99
+ startDate?: Date | number | null;
100
+ endDate?: Date | number | null;
101
+ skipDays?: string | null;
102
+
103
+ /**
104
+ * The reason the job failed.
105
+ */
106
+ failReason?: string;
107
+
108
+ /**
109
+ * The number of times the job has failed.
110
+ */
111
+ failCount?: number;
112
+
113
+ /**
114
+ * The date/time the job last failed.
115
+ */
116
+ failedAt?: Date;
117
+
118
+ /**
119
+ * Date/time the job was last modified.
120
+ */
121
+ lastModifiedBy?: string;
122
+
123
+ /**
124
+ * Should the return value of the job be persisted.
125
+ */
126
+ shouldSaveResult?: boolean;
127
+
128
+ /**
129
+ * Result of the finished job.
130
+ */
131
+ result?: unknown;
132
+ }
133
+
134
+ /**
135
+ * @class
136
+ * @param {Object} args - Job Options
137
+ * @property {Object} agenda - The Agenda instance
138
+ * @property {Object} attrs
139
+ */
140
+ class Job<T extends JobAttributesData = JobAttributesData> {
141
+ /**
142
+ * The agenda that created the job.
143
+ */
144
+ agenda: Agenda;
145
+
146
+ /**
147
+ * The database record associated with the job.
148
+ */
149
+ attrs: JobAttributes<T>;
150
+
151
+ toJSON!: typeof toJson;
152
+ computeNextRunAt!: typeof computeNextRunAt;
153
+ repeatEvery!: typeof repeatEvery;
154
+ repeatAt!: typeof repeatAt;
155
+ disable!: typeof disable;
156
+ enable!: typeof enable;
157
+ unique!: typeof unique;
158
+ schedule!: typeof schedule;
159
+ priority!: typeof priority;
160
+ fail!: typeof fail;
161
+ run!: typeof run;
162
+ isRunning!: typeof isRunning;
163
+ save!: typeof save;
164
+ remove!: typeof remove;
165
+ touch!: typeof touch;
166
+ setShouldSaveResult!: typeof setShouldSaveResult;
167
+
168
+ constructor(options: Modify<JobAttributes<T>, { _id?: mongodb.ObjectId; }>) {
169
+ const { agenda, type, nextRunAt, ...args } = options ?? {};
170
+
171
+ // Save Agenda instance
172
+ this.agenda = agenda;
173
+
174
+ // Set priority
175
+ args.priority =
176
+ args.priority === undefined
177
+ ? JobPriority.normal
178
+ : parsePriority(args.priority);
179
+
180
+ // Set shouldSaveResult option
181
+ args.shouldSaveResult = args.shouldSaveResult || false
182
+
183
+ // Set attrs to args
184
+ const attrs: any = {};
185
+ for (const key in args) {
186
+ if ({}.hasOwnProperty.call(args, key)) {
187
+ // @ts-expect-error
188
+ attrs[key] = args[key];
189
+ }
190
+ }
191
+
192
+ // Set defaults if undefined
193
+ this.attrs = {
194
+ ...attrs,
195
+ // NOTE: What is the difference between 'once' here and 'single' in agenda/index.js?
196
+ name: attrs.name || "",
197
+ priority: attrs.priority,
198
+ type: type || "once",
199
+ nextRunAt: nextRunAt || new Date(),
200
+ };
201
+ }
202
+ }
203
+
204
+ Job.prototype.toJSON = toJson;
205
+ Job.prototype.computeNextRunAt = computeNextRunAt;
206
+ Job.prototype.repeatEvery = repeatEvery;
207
+ Job.prototype.repeatAt = repeatAt;
208
+ Job.prototype.disable = disable;
209
+ Job.prototype.enable = enable;
210
+ Job.prototype.unique = unique;
211
+ Job.prototype.schedule = schedule;
212
+ Job.prototype.priority = priority;
213
+ Job.prototype.fail = fail;
214
+ Job.prototype.run = run;
215
+ Job.prototype.isRunning = isRunning;
216
+ Job.prototype.save = save;
217
+ Job.prototype.remove = remove;
218
+ Job.prototype.touch = touch;
219
+ Job.prototype.setShouldSaveResult = setShouldSaveResult;
220
+
221
+ export { Job };
@@ -0,0 +1,29 @@
1
+ import { Job } from ".";
2
+
3
+ /**
4
+ * A job is running if:
5
+ * (lastRunAt exists AND lastFinishedAt does not exist)
6
+ * OR
7
+ * (lastRunAt exists AND lastFinishedAt exists but the lastRunAt is newer [in time] than lastFinishedAt)
8
+ * @name Job#isRunning
9
+ * @function
10
+ * @returns Whether or not job is running at the moment (true for running)
11
+ */
12
+ export const isRunning = function (this: Job): boolean {
13
+ if (!this.attrs.lastRunAt) {
14
+ return false;
15
+ }
16
+
17
+ if (!this.attrs.lastFinishedAt) {
18
+ return true;
19
+ }
20
+
21
+ if (
22
+ this.attrs.lockedAt &&
23
+ this.attrs.lastRunAt.getTime() > this.attrs.lastFinishedAt.getTime()
24
+ ) {
25
+ return true;
26
+ }
27
+
28
+ return false;
29
+ };
@@ -0,0 +1,11 @@
1
+ import { Job } from ".";
2
+ import { parsePriority } from "../utils";
3
+
4
+ /**
5
+ * Sets priority of the job
6
+ * @param priority priority of when job should be queued
7
+ */
8
+ export const priority = function (this: Job, priority: string): Job {
9
+ this.attrs.priority = parsePriority(priority);
10
+ return this;
11
+ };