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,22 @@
|
|
|
1
|
+
import createDebugger from "debug";
|
|
2
|
+
import { Job, JobAttributesData } from "../job";
|
|
3
|
+
import { Agenda } from ".";
|
|
4
|
+
|
|
5
|
+
const debug = createDebugger("agenda:create");
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Given a name and some data, create a new job
|
|
9
|
+
* @name Agenda#create
|
|
10
|
+
* @function
|
|
11
|
+
* @param name name of job
|
|
12
|
+
* @param data data to set for job
|
|
13
|
+
*/
|
|
14
|
+
export const create = function<T extends JobAttributesData> (this: Agenda, name: string, data: T): Job {
|
|
15
|
+
debug("Agenda.create(%s, [Object])", name);
|
|
16
|
+
const priority = this._definitions[name]
|
|
17
|
+
? this._definitions[name].priority
|
|
18
|
+
: 0;
|
|
19
|
+
const shouldSaveResult = this._definitions[name] ? this._definitions[name].shouldSaveResult || false : false
|
|
20
|
+
const job = new Job({ name, data, type: "normal", priority, shouldSaveResult, agenda: this });
|
|
21
|
+
return job;
|
|
22
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import createDebugger from "debug";
|
|
2
|
+
import { AnyError, Collection, MongoClient, MongoClientOptions } from "mongodb";
|
|
3
|
+
import { Agenda } from ".";
|
|
4
|
+
import { hasMongoProtocol } from "./has-mongo-protocol";
|
|
5
|
+
|
|
6
|
+
const debug = createDebugger("agenda:database");
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Connect to the spec'd MongoDB server and database.
|
|
10
|
+
*
|
|
11
|
+
* NOTE:
|
|
12
|
+
* If `url` includes auth details then `options` must specify: { 'uri_decode_auth': true }. This does Auth on
|
|
13
|
+
* the specified database, not the Admin database. If you are using Auth on the Admin DB and not on the Agenda DB,
|
|
14
|
+
* then you need to authenticate against the Admin DB and then pass the MongoDB instance into the constructor
|
|
15
|
+
* or use Agenda.mongo(). If your app already has a MongoDB connection then use that. ie. specify config.mongo in
|
|
16
|
+
* the constructor or use Agenda.mongo().
|
|
17
|
+
* @name Agenda#database
|
|
18
|
+
* @function
|
|
19
|
+
* @param url MongoDB server URI
|
|
20
|
+
* @param [collection] name of collection to use. Defaults to `agendaJobs`
|
|
21
|
+
* @param [options] options for connecting
|
|
22
|
+
* @param [cb] callback of MongoDB connection
|
|
23
|
+
*/
|
|
24
|
+
export const database = function (
|
|
25
|
+
this: Agenda,
|
|
26
|
+
url: string,
|
|
27
|
+
collection?: string,
|
|
28
|
+
options: MongoClientOptions = {},
|
|
29
|
+
cb?: (error: AnyError | undefined, collection: Collection<any> | null) => void
|
|
30
|
+
): Agenda | void {
|
|
31
|
+
if (!hasMongoProtocol(url)) {
|
|
32
|
+
url = "mongodb://" + url;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
collection = collection || "agendaJobs";
|
|
36
|
+
|
|
37
|
+
MongoClient.connect(url, options, (error, client) => {
|
|
38
|
+
if (error) {
|
|
39
|
+
debug("error connecting to MongoDB using collection: [%s]", collection);
|
|
40
|
+
if (cb) {
|
|
41
|
+
cb(error, null);
|
|
42
|
+
} else {
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
debug(
|
|
50
|
+
"successful connection to MongoDB using collection: [%s]",
|
|
51
|
+
collection
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
if (client) {
|
|
55
|
+
this._db = client;
|
|
56
|
+
this._mdb = client.db();
|
|
57
|
+
this.db_init(collection, cb);
|
|
58
|
+
} else {
|
|
59
|
+
throw new Error("Mongo Client is undefined");
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return this;
|
|
63
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import createDebugger from "debug";
|
|
2
|
+
import { AnyError, Collection } from "mongodb";
|
|
3
|
+
import { Agenda } from ".";
|
|
4
|
+
|
|
5
|
+
const debug = createDebugger("agenda:db_init");
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Setup and initialize the collection used to manage Jobs.
|
|
9
|
+
* @name Agenda#dbInit
|
|
10
|
+
* @function
|
|
11
|
+
* @param collection name or undefined for default 'agendaJobs'
|
|
12
|
+
* @param [cb] called when the db is initialized
|
|
13
|
+
*/
|
|
14
|
+
export const dbInit = function (
|
|
15
|
+
this: Agenda,
|
|
16
|
+
collection = "agendaJobs",
|
|
17
|
+
cb?: (error: AnyError | undefined, collection: Collection<any> | null) => void
|
|
18
|
+
): void {
|
|
19
|
+
debug("init database collection using name [%s]", collection);
|
|
20
|
+
this._collection = this._mdb.collection(collection);
|
|
21
|
+
if (this._disableAutoIndex) {
|
|
22
|
+
debug("skipping auto index creation");
|
|
23
|
+
this.emit("ready");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
debug("attempting index creation");
|
|
28
|
+
this._collection.createIndex(
|
|
29
|
+
this._indices,
|
|
30
|
+
{ name: "findAndLockNextJobIndex" },
|
|
31
|
+
(error) => {
|
|
32
|
+
if (error) {
|
|
33
|
+
debug("index creation failed");
|
|
34
|
+
this.emit("error", error);
|
|
35
|
+
} else {
|
|
36
|
+
debug("index creation success");
|
|
37
|
+
this.emit("ready");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (cb) {
|
|
41
|
+
cb(error, this._collection);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Agenda } from ".";
|
|
2
|
+
import createDebugger from "debug";
|
|
3
|
+
|
|
4
|
+
const debug = createDebugger("agenda:defaultConcurrency");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Set the default concurrency for each job
|
|
8
|
+
* @name Agenda#defaultConcurrency
|
|
9
|
+
* @function
|
|
10
|
+
* @param concurrency default concurrency
|
|
11
|
+
*/
|
|
12
|
+
export const defaultConcurrency = function (
|
|
13
|
+
this: Agenda,
|
|
14
|
+
concurrency: number
|
|
15
|
+
): Agenda {
|
|
16
|
+
debug("Agenda.defaultConcurrency(%d)", concurrency);
|
|
17
|
+
this._defaultConcurrency = concurrency;
|
|
18
|
+
return this;
|
|
19
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Agenda } from ".";
|
|
2
|
+
import createDebugger from "debug";
|
|
3
|
+
|
|
4
|
+
const debug = createDebugger("agenda:defaultLockLifetime");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Set the default lock time (in ms)
|
|
8
|
+
* Default is 10 * 60 * 1000 ms (10 minutes)
|
|
9
|
+
* @name Agenda#defaultLockLifetime
|
|
10
|
+
* @function
|
|
11
|
+
* @param {Number} ms time in ms to set default lock
|
|
12
|
+
*/
|
|
13
|
+
export const defaultLockLifetime = function (this: Agenda, ms: number): Agenda {
|
|
14
|
+
debug("Agenda.defaultLockLifetime(%d)", ms);
|
|
15
|
+
this._defaultLockLifetime = ms;
|
|
16
|
+
return this;
|
|
17
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Agenda } from ".";
|
|
2
|
+
import createDebugger from "debug";
|
|
3
|
+
|
|
4
|
+
const debug = createDebugger("agenda:defaultLockLimit");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Set default lock limit per job type
|
|
8
|
+
* @name Agenda#defaultLockLimit
|
|
9
|
+
* @function
|
|
10
|
+
* @param {Number} num Lock limit per job
|
|
11
|
+
* @returns {Agenda} agenda instance
|
|
12
|
+
*/
|
|
13
|
+
export const defaultLockLimit = function (this: Agenda, times: number): Agenda {
|
|
14
|
+
debug("Agenda.defaultLockLimit(%d)", times);
|
|
15
|
+
this._defaultLockLimit = times;
|
|
16
|
+
return this;
|
|
17
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Agenda } from ".";
|
|
2
|
+
import createDebugger from "debug";
|
|
3
|
+
import { Job } from "../job";
|
|
4
|
+
|
|
5
|
+
const debug = createDebugger("agenda:define");
|
|
6
|
+
|
|
7
|
+
export enum JobPriority {
|
|
8
|
+
highest = 20,
|
|
9
|
+
high = 10,
|
|
10
|
+
normal = 0,
|
|
11
|
+
low = -10,
|
|
12
|
+
lowest = -20,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface DefineOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Maximum number of that job that can be running at once (per instance of agenda)
|
|
18
|
+
*/
|
|
19
|
+
concurrency?: number;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Maximum number of that job that can be locked at once (per instance of agenda)
|
|
23
|
+
*/
|
|
24
|
+
lockLimit?: number;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Interval in ms of how long the job stays locked for (see multiple job processors for more info). A job will
|
|
28
|
+
* automatically unlock if done() is called.
|
|
29
|
+
*/
|
|
30
|
+
lockLifetime?: number;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* (lowest|low|normal|high|highest|number) specifies the priority of the job. Higher priority jobs will run
|
|
34
|
+
* first.
|
|
35
|
+
*/
|
|
36
|
+
priority?: JobPriority;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Should the return value of the job be persisted
|
|
40
|
+
*/
|
|
41
|
+
shouldSaveResult?: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type Processor<T> =
|
|
45
|
+
| ((job: Job<T>) => Promise<void>)
|
|
46
|
+
| ((job: Job<T>, done: () => void) => void);
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Setup definition for job
|
|
50
|
+
* Method is used by consumers of lib to setup their functions
|
|
51
|
+
* @name Agenda#define
|
|
52
|
+
* @function
|
|
53
|
+
* @param name name of job
|
|
54
|
+
* @param options options for job to run
|
|
55
|
+
* @param [processor] function to be called to run actual job
|
|
56
|
+
*/
|
|
57
|
+
export const define = function<T> (
|
|
58
|
+
this: Agenda,
|
|
59
|
+
name: string,
|
|
60
|
+
options: DefineOptions | Processor<T>,
|
|
61
|
+
processor?: Processor<T>
|
|
62
|
+
): void {
|
|
63
|
+
if (processor === undefined) {
|
|
64
|
+
processor = options as Processor<T>;
|
|
65
|
+
options = {};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this._definitions[name] = {
|
|
69
|
+
fn: processor,
|
|
70
|
+
concurrency:
|
|
71
|
+
(options as DefineOptions).concurrency || this._defaultConcurrency, // `null` is per interface definition of DefineOptions not valid
|
|
72
|
+
lockLimit: (options as DefineOptions).lockLimit || this._defaultLockLimit,
|
|
73
|
+
priority: (options as DefineOptions).priority || JobPriority.normal,
|
|
74
|
+
lockLifetime:
|
|
75
|
+
(options as DefineOptions).lockLifetime || this._defaultLockLifetime,
|
|
76
|
+
running: 0,
|
|
77
|
+
locked: 0,
|
|
78
|
+
shouldSaveResult: (options as DefineOptions).shouldSaveResult || false
|
|
79
|
+
};
|
|
80
|
+
debug(
|
|
81
|
+
"job [%s] defined with following options: \n%O",
|
|
82
|
+
name,
|
|
83
|
+
this._definitions[name]
|
|
84
|
+
);
|
|
85
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import createDebugger from "debug";
|
|
2
|
+
import { Filter } from "mongodb";
|
|
3
|
+
import { Agenda } from ".";
|
|
4
|
+
const debug = createDebugger("agenda:disable");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Disables any jobs matching the passed MongoDB query by setting the `disabled` flag to `true`
|
|
8
|
+
* @name Agenda#disable
|
|
9
|
+
* @function
|
|
10
|
+
* @param query MongoDB query to use when enabling
|
|
11
|
+
* @returns {Promise<number>} Resolved with the number of disabled job instances.
|
|
12
|
+
*/
|
|
13
|
+
export const disable = async function (
|
|
14
|
+
this: Agenda,
|
|
15
|
+
query: Filter<unknown> = {}
|
|
16
|
+
): Promise<number> {
|
|
17
|
+
debug("attempting to disable all jobs matching query", query);
|
|
18
|
+
try {
|
|
19
|
+
const { modifiedCount } = await this._collection.updateMany(query, {
|
|
20
|
+
$set: { disabled: true },
|
|
21
|
+
});
|
|
22
|
+
debug("%s jobs disabled");
|
|
23
|
+
return modifiedCount;
|
|
24
|
+
} catch (error) {
|
|
25
|
+
debug("error trying to mark jobs as `disabled`");
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import createDebugger from "debug";
|
|
2
|
+
import { Agenda } from ".";
|
|
3
|
+
|
|
4
|
+
const debug = createDebugger("agenda:drain");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Clear the interval that processes the jobs
|
|
8
|
+
* @name Agenda#drain
|
|
9
|
+
* @function
|
|
10
|
+
* @returns resolves when all running jobs completes
|
|
11
|
+
*/
|
|
12
|
+
export const drain = async function (this: Agenda): Promise<void> {
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
debug("Agenda.drain called, clearing interval for processJobs()");
|
|
15
|
+
clearInterval(this._processInterval);
|
|
16
|
+
this._processInterval = undefined;
|
|
17
|
+
|
|
18
|
+
if (this._runningJobs.length === 0) {
|
|
19
|
+
resolve();
|
|
20
|
+
} else {
|
|
21
|
+
debug("Agenda.drain waiting for jobs to finish");
|
|
22
|
+
this.on('complete', () => {
|
|
23
|
+
// running jobs are removed after the event
|
|
24
|
+
if (this._runningJobs.length === 1) {
|
|
25
|
+
resolve();
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import createDebugger from "debug";
|
|
2
|
+
import { Filter } from "mongodb";
|
|
3
|
+
import { Agenda } from ".";
|
|
4
|
+
const debug = createDebugger("agenda:enable");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Enables any jobs matching the passed MongoDB query by setting the `disabled` flag to `false`
|
|
8
|
+
* @name Agenda#enable
|
|
9
|
+
* @function
|
|
10
|
+
* @param query MongoDB query to use when enabling
|
|
11
|
+
* @caller client code, Agenda.purge(), Job.remove()
|
|
12
|
+
* @returns {Promise<Number>} A promise that contains the number of removed documents when fulfilled.
|
|
13
|
+
*/
|
|
14
|
+
export const enable = async function (
|
|
15
|
+
this: Agenda,
|
|
16
|
+
query: Filter<unknown> = {}
|
|
17
|
+
): Promise<number> {
|
|
18
|
+
debug("attempting to enable all jobs matching query", query);
|
|
19
|
+
try {
|
|
20
|
+
const { modifiedCount } = await this._collection.updateMany(query, {
|
|
21
|
+
$set: { disabled: false },
|
|
22
|
+
});
|
|
23
|
+
debug("%s jobs enabled", modifiedCount);
|
|
24
|
+
return modifiedCount;
|
|
25
|
+
} catch (error) {
|
|
26
|
+
debug("error trying to mark jobs as `enabled`");
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import createDebugger from "debug";
|
|
2
|
+
import { Agenda } from ".";
|
|
3
|
+
import { Job, JobAttributesData } from "../job";
|
|
4
|
+
import { JobOptions } from "../job/repeat-every";
|
|
5
|
+
|
|
6
|
+
const debug = createDebugger("agenda:every");
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Creates a scheduled job with given interval and name/names of the job to run
|
|
10
|
+
* @name Agenda#every
|
|
11
|
+
* @function
|
|
12
|
+
* @param interval - run every X interval
|
|
13
|
+
* @param names - String or strings of jobs to schedule
|
|
14
|
+
* @param data - data to run for job
|
|
15
|
+
* @param options - options to run job for
|
|
16
|
+
* @returns Job/s created. Resolves when schedule fails or passes
|
|
17
|
+
*/
|
|
18
|
+
export const every = async function<T extends JobAttributesData> (
|
|
19
|
+
this: Agenda,
|
|
20
|
+
interval: string,
|
|
21
|
+
names: string | string[],
|
|
22
|
+
data?: T,
|
|
23
|
+
options?: JobOptions
|
|
24
|
+
): Promise<any> {
|
|
25
|
+
/**
|
|
26
|
+
* Internal method to setup job that gets run every interval
|
|
27
|
+
* @param interval run every X interval
|
|
28
|
+
* @param name String job to schedule
|
|
29
|
+
* @param [data] data to run for job
|
|
30
|
+
* @param [options] options to run job for
|
|
31
|
+
* @returns instance of job
|
|
32
|
+
*/
|
|
33
|
+
const createJob = async<T extends JobAttributesData> (
|
|
34
|
+
interval: string,
|
|
35
|
+
name: string,
|
|
36
|
+
data?: T,
|
|
37
|
+
options?: JobOptions
|
|
38
|
+
): Promise<Job> => {
|
|
39
|
+
const job = this.create(name, data || {});
|
|
40
|
+
|
|
41
|
+
job.attrs.type = "single";
|
|
42
|
+
job.repeatEvery(interval, options);
|
|
43
|
+
return job.save();
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Internal helper method that uses createJob to create jobs for an array of names
|
|
48
|
+
* @param interval run every X interval
|
|
49
|
+
* @param names Strings of jobs to schedule
|
|
50
|
+
* @param [data] data to run for job
|
|
51
|
+
* @param [options] options to run job for
|
|
52
|
+
* @return array of jobs created
|
|
53
|
+
*/
|
|
54
|
+
const createJobs = async (
|
|
55
|
+
interval: string,
|
|
56
|
+
names: string[],
|
|
57
|
+
data?: T,
|
|
58
|
+
options?: JobOptions
|
|
59
|
+
): Promise<Job[] | undefined> => {
|
|
60
|
+
try {
|
|
61
|
+
const jobs: Array<Promise<Job>> = [];
|
|
62
|
+
names.map((name) => jobs.push(createJob(interval, name, data, options)));
|
|
63
|
+
|
|
64
|
+
debug("every() -> all jobs created successfully");
|
|
65
|
+
|
|
66
|
+
return Promise.all(jobs);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
// @TODO: catch - ignore :O
|
|
69
|
+
debug("every() -> error creating one or more of the jobs", error);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
if (typeof names === "string") {
|
|
74
|
+
debug("Agenda.every(%s, %O, %O)", interval, names, options);
|
|
75
|
+
const jobs = await createJob(interval, names, data, options);
|
|
76
|
+
|
|
77
|
+
return jobs;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (Array.isArray(names)) {
|
|
81
|
+
debug("Agenda.every(%s, %s, %O)", interval, names, options);
|
|
82
|
+
const jobs = await createJobs(interval, names, data, options);
|
|
83
|
+
|
|
84
|
+
return jobs;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import createDebugger from "debug";
|
|
2
|
+
import { createJob } from "../utils";
|
|
3
|
+
import { Agenda } from ".";
|
|
4
|
+
import { Job } from "../job";
|
|
5
|
+
import { ReturnDocument } from "mongodb";
|
|
6
|
+
|
|
7
|
+
const debug = createDebugger("agenda:internal:_findAndLockNextJob");
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Find and lock jobs
|
|
11
|
+
* @name Agenda#findAndLockNextJob
|
|
12
|
+
* @function
|
|
13
|
+
* @param jobName name of job to try to lock
|
|
14
|
+
* @param definition definition used to tell how job is run
|
|
15
|
+
* @access protected
|
|
16
|
+
* @caller jobQueueFilling() only
|
|
17
|
+
*/
|
|
18
|
+
export const findAndLockNextJob = async function (
|
|
19
|
+
this: Agenda,
|
|
20
|
+
jobName: string,
|
|
21
|
+
definition: any
|
|
22
|
+
): Promise<Job | undefined> {
|
|
23
|
+
const now = new Date();
|
|
24
|
+
const lockDeadline = new Date(Date.now().valueOf() - definition.lockLifetime);
|
|
25
|
+
debug("_findAndLockNextJob(%s, [Function])", jobName);
|
|
26
|
+
|
|
27
|
+
const JOB_PROCESS_WHERE_QUERY = {
|
|
28
|
+
$and: [
|
|
29
|
+
{
|
|
30
|
+
name: jobName,
|
|
31
|
+
disabled: { $ne: true },
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
$or: [
|
|
35
|
+
{
|
|
36
|
+
lockedAt: { $eq: null },
|
|
37
|
+
nextRunAt: { $lte: this._nextScanAt },
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
lockedAt: { $lte: lockDeadline },
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Query used to set a job as locked
|
|
49
|
+
* @type {{$set: {lockedAt: Date}}}
|
|
50
|
+
*/
|
|
51
|
+
const JOB_PROCESS_SET_QUERY = { $set: { lockedAt: now } };
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Query used to affect what gets returned
|
|
55
|
+
* @type {{returnOriginal: boolean, sort: object}}
|
|
56
|
+
*/
|
|
57
|
+
const JOB_RETURN_QUERY = { returnDocument: ReturnDocument.AFTER, sort: this._sort };
|
|
58
|
+
|
|
59
|
+
// Find ONE and ONLY ONE job and set the 'lockedAt' time so that job begins to be processed
|
|
60
|
+
const result = await this._collection.findOneAndUpdate(
|
|
61
|
+
JOB_PROCESS_WHERE_QUERY,
|
|
62
|
+
JOB_PROCESS_SET_QUERY,
|
|
63
|
+
JOB_RETURN_QUERY
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
let job: Job | undefined = undefined;
|
|
67
|
+
if (result.value) {
|
|
68
|
+
debug(
|
|
69
|
+
"found a job available to lock, creating a new job on Agenda with id [%s]",
|
|
70
|
+
result.value._id
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// @ts-ignore
|
|
74
|
+
job = createJob(this, result.value);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return job;
|
|
78
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Given a mongo connection url will check if it contains the mongo
|
|
3
|
+
* @param url URL to be tested
|
|
4
|
+
* @returns whether or not the url is a valid mongo URL
|
|
5
|
+
*/
|
|
6
|
+
export const hasMongoProtocol = function (url: string): boolean {
|
|
7
|
+
return /mongodb(?:\+srv)?:\/\/.*/.exec(url) !== null;
|
|
8
|
+
};
|