215 lines
5.7 KiB
JavaScript
215 lines
5.7 KiB
JavaScript
|
"use strict";
|
||
|
|
||
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
||
|
|
||
|
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
||
|
|
||
|
var BottleneckError, DEFAULT_PRIORITY, Job, NUM_PRIORITIES, parser;
|
||
|
NUM_PRIORITIES = 10;
|
||
|
DEFAULT_PRIORITY = 5;
|
||
|
parser = require("./parser");
|
||
|
BottleneckError = require("./BottleneckError");
|
||
|
Job = class Job {
|
||
|
constructor(task, args, options, jobDefaults, rejectOnDrop, Events, _states, Promise) {
|
||
|
this.task = task;
|
||
|
this.args = args;
|
||
|
this.rejectOnDrop = rejectOnDrop;
|
||
|
this.Events = Events;
|
||
|
this._states = _states;
|
||
|
this.Promise = Promise;
|
||
|
this.options = parser.load(options, jobDefaults);
|
||
|
this.options.priority = this._sanitizePriority(this.options.priority);
|
||
|
|
||
|
if (this.options.id === jobDefaults.id) {
|
||
|
this.options.id = `${this.options.id}-${this._randomIndex()}`;
|
||
|
}
|
||
|
|
||
|
this.promise = new this.Promise((_resolve, _reject) => {
|
||
|
this._resolve = _resolve;
|
||
|
this._reject = _reject;
|
||
|
});
|
||
|
this.retryCount = 0;
|
||
|
}
|
||
|
|
||
|
_sanitizePriority(priority) {
|
||
|
var sProperty;
|
||
|
sProperty = ~~priority !== priority ? DEFAULT_PRIORITY : priority;
|
||
|
|
||
|
if (sProperty < 0) {
|
||
|
return 0;
|
||
|
} else if (sProperty > NUM_PRIORITIES - 1) {
|
||
|
return NUM_PRIORITIES - 1;
|
||
|
} else {
|
||
|
return sProperty;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_randomIndex() {
|
||
|
return Math.random().toString(36).slice(2);
|
||
|
}
|
||
|
|
||
|
doDrop({
|
||
|
error,
|
||
|
message = "This job has been dropped by Bottleneck"
|
||
|
} = {}) {
|
||
|
if (this._states.remove(this.options.id)) {
|
||
|
if (this.rejectOnDrop) {
|
||
|
this._reject(error != null ? error : new BottleneckError(message));
|
||
|
}
|
||
|
|
||
|
this.Events.trigger("dropped", {
|
||
|
args: this.args,
|
||
|
options: this.options,
|
||
|
task: this.task,
|
||
|
promise: this.promise
|
||
|
});
|
||
|
return true;
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_assertStatus(expected) {
|
||
|
var status;
|
||
|
status = this._states.jobStatus(this.options.id);
|
||
|
|
||
|
if (!(status === expected || expected === "DONE" && status === null)) {
|
||
|
throw new BottleneckError(`Invalid job status ${status}, expected ${expected}. Please open an issue at https://github.com/SGrondin/bottleneck/issues`);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
doReceive() {
|
||
|
this._states.start(this.options.id);
|
||
|
|
||
|
return this.Events.trigger("received", {
|
||
|
args: this.args,
|
||
|
options: this.options
|
||
|
});
|
||
|
}
|
||
|
|
||
|
doQueue(reachedHWM, blocked) {
|
||
|
this._assertStatus("RECEIVED");
|
||
|
|
||
|
this._states.next(this.options.id);
|
||
|
|
||
|
return this.Events.trigger("queued", {
|
||
|
args: this.args,
|
||
|
options: this.options,
|
||
|
reachedHWM,
|
||
|
blocked
|
||
|
});
|
||
|
}
|
||
|
|
||
|
doRun() {
|
||
|
if (this.retryCount === 0) {
|
||
|
this._assertStatus("QUEUED");
|
||
|
|
||
|
this._states.next(this.options.id);
|
||
|
} else {
|
||
|
this._assertStatus("EXECUTING");
|
||
|
}
|
||
|
|
||
|
return this.Events.trigger("scheduled", {
|
||
|
args: this.args,
|
||
|
options: this.options
|
||
|
});
|
||
|
}
|
||
|
|
||
|
doExecute(chained, clearGlobalState, run, free) {
|
||
|
var _this = this;
|
||
|
|
||
|
return _asyncToGenerator(function* () {
|
||
|
var error, eventInfo, passed;
|
||
|
|
||
|
if (_this.retryCount === 0) {
|
||
|
_this._assertStatus("RUNNING");
|
||
|
|
||
|
_this._states.next(_this.options.id);
|
||
|
} else {
|
||
|
_this._assertStatus("EXECUTING");
|
||
|
}
|
||
|
|
||
|
eventInfo = {
|
||
|
args: _this.args,
|
||
|
options: _this.options,
|
||
|
retryCount: _this.retryCount
|
||
|
};
|
||
|
|
||
|
_this.Events.trigger("executing", eventInfo);
|
||
|
|
||
|
try {
|
||
|
passed = yield chained != null ? chained.schedule(_this.options, _this.task, ..._this.args) : _this.task(..._this.args);
|
||
|
|
||
|
if (clearGlobalState()) {
|
||
|
_this.doDone(eventInfo);
|
||
|
|
||
|
yield free(_this.options, eventInfo);
|
||
|
|
||
|
_this._assertStatus("DONE");
|
||
|
|
||
|
return _this._resolve(passed);
|
||
|
}
|
||
|
} catch (error1) {
|
||
|
error = error1;
|
||
|
return _this._onFailure(error, eventInfo, clearGlobalState, run, free);
|
||
|
}
|
||
|
})();
|
||
|
}
|
||
|
|
||
|
doExpire(clearGlobalState, run, free) {
|
||
|
var error, eventInfo;
|
||
|
|
||
|
if (this._states.jobStatus(this.options.id === "RUNNING")) {
|
||
|
this._states.next(this.options.id);
|
||
|
}
|
||
|
|
||
|
this._assertStatus("EXECUTING");
|
||
|
|
||
|
eventInfo = {
|
||
|
args: this.args,
|
||
|
options: this.options,
|
||
|
retryCount: this.retryCount
|
||
|
};
|
||
|
error = new BottleneckError(`This job timed out after ${this.options.expiration} ms.`);
|
||
|
return this._onFailure(error, eventInfo, clearGlobalState, run, free);
|
||
|
}
|
||
|
|
||
|
_onFailure(error, eventInfo, clearGlobalState, run, free) {
|
||
|
var _this2 = this;
|
||
|
|
||
|
return _asyncToGenerator(function* () {
|
||
|
var retry, retryAfter;
|
||
|
|
||
|
if (clearGlobalState()) {
|
||
|
retry = yield _this2.Events.trigger("failed", error, eventInfo);
|
||
|
|
||
|
if (retry != null) {
|
||
|
retryAfter = ~~retry;
|
||
|
|
||
|
_this2.Events.trigger("retry", `Retrying ${_this2.options.id} after ${retryAfter} ms`, eventInfo);
|
||
|
|
||
|
_this2.retryCount++;
|
||
|
return run(retryAfter);
|
||
|
} else {
|
||
|
_this2.doDone(eventInfo);
|
||
|
|
||
|
yield free(_this2.options, eventInfo);
|
||
|
|
||
|
_this2._assertStatus("DONE");
|
||
|
|
||
|
return _this2._reject(error);
|
||
|
}
|
||
|
}
|
||
|
})();
|
||
|
}
|
||
|
|
||
|
doDone(eventInfo) {
|
||
|
this._assertStatus("EXECUTING");
|
||
|
|
||
|
this._states.next(this.options.id);
|
||
|
|
||
|
return this.Events.trigger("done", eventInfo);
|
||
|
}
|
||
|
|
||
|
};
|
||
|
module.exports = Job;
|