qdone 2.0.14-alpha → 2.0.16-alpha
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/commonjs/src/consumer.js +6 -4
- package/commonjs/src/scheduler/jobExecutor.js +4 -4
- package/commonjs/src/scheduler/queueManager.js +6 -1
- package/commonjs/src/sentry.js +111 -0
- package/package.json +1 -1
- package/src/consumer.js +6 -6
- package/src/scheduler/jobExecutor.js +4 -6
- package/src/scheduler/queueManager.js +2 -1
- package/src/sentry.js +17 -4
package/commonjs/src/consumer.js
CHANGED
|
@@ -134,7 +134,7 @@ function processMessages(queues, callback, options) {
|
|
|
134
134
|
lastLatency = latency;
|
|
135
135
|
});
|
|
136
136
|
jobExecutor = new jobExecutor_js_1.JobExecutor(opt);
|
|
137
|
-
queueManager = new queueManager_js_1.QueueManager(opt, queues);
|
|
137
|
+
queueManager = new queueManager_js_1.QueueManager(opt, queues, 60);
|
|
138
138
|
delay = function (ms) { return new Promise(function (resolve) {
|
|
139
139
|
delayTimeout = setTimeout(resolve, ms);
|
|
140
140
|
}); };
|
|
@@ -206,15 +206,17 @@ function processMessages(queues, callback, options) {
|
|
|
206
206
|
_c.label = 1;
|
|
207
207
|
case 1:
|
|
208
208
|
if (!!shutdownRequested) return [3 /*break*/, 3];
|
|
209
|
-
allowedJobs = opt.maxConcurrentJobs - jobExecutor.activeJobCount() - maxReturnCount;
|
|
209
|
+
allowedJobs = Math.max(0, opt.maxConcurrentJobs - jobExecutor.activeJobCount() - maxReturnCount);
|
|
210
210
|
maxLatency = 100;
|
|
211
|
-
latency = systemMonitor.getLatency()
|
|
211
|
+
latency = systemMonitor.getLatency() || 10;
|
|
212
212
|
latencyFactor = 1 - Math.abs(Math.min(latency / maxLatency, 1)) // 0 if latency is at max, 1 if latency 0
|
|
213
213
|
;
|
|
214
214
|
targetJobs = Math.round(allowedJobs * latencyFactor);
|
|
215
215
|
jobsLeft = targetJobs;
|
|
216
|
+
debug({ jobCount: jobExecutor.activeJobCount(), maxReturnCount: maxReturnCount, allowedJobs: allowedJobs, maxLatency: maxLatency, latency: latency, latencyFactor: latencyFactor, targetJobs: targetJobs, activeQrls: activeQrls });
|
|
216
217
|
for (_i = 0, _a = queueManager.getPairs(); _i < _a.length; _i++) {
|
|
217
218
|
_b = _a[_i], qname = _b.qname, qrl = _b.qrl;
|
|
219
|
+
debug({ evaluating: { qname: qname, qrl: qrl, jobsLeft: jobsLeft, activeQrlsHasQrl: activeQrls.has(qrl) } });
|
|
218
220
|
if (jobsLeft <= 0 || activeQrls.has(qrl))
|
|
219
221
|
continue;
|
|
220
222
|
maxMessages = Math.min(10, jobsLeft);
|
|
@@ -223,7 +225,7 @@ function processMessages(queues, callback, options) {
|
|
|
223
225
|
if (opt.verbose) {
|
|
224
226
|
console.error(chalk_1.default.blue('Listening on: '), qname);
|
|
225
227
|
}
|
|
226
|
-
|
|
228
|
+
debug({ listenedTo: { qname: qname, maxMessages: maxMessages, jobsLeft: jobsLeft } });
|
|
227
229
|
}
|
|
228
230
|
return [4 /*yield*/, delay(1000)];
|
|
229
231
|
case 2:
|
|
@@ -47,6 +47,7 @@ exports.JobExecutor = void 0;
|
|
|
47
47
|
var client_sqs_1 = require("@aws-sdk/client-sqs");
|
|
48
48
|
var chalk_1 = __importDefault(require("chalk"));
|
|
49
49
|
var debug_1 = __importDefault(require("debug"));
|
|
50
|
+
var sentry_js_1 = require("../sentry.js");
|
|
50
51
|
var sqs_js_1 = require("../sqs.js");
|
|
51
52
|
var debug = (0, debug_1.default)('qdone:jobExecutor');
|
|
52
53
|
var maxJobSeconds = 12 * 60 * 60;
|
|
@@ -268,7 +269,7 @@ var JobExecutor = /** @class */ (function () {
|
|
|
268
269
|
};
|
|
269
270
|
JobExecutor.prototype.executeJob = function (message, callback, qname, qrl) {
|
|
270
271
|
return __awaiter(this, void 0, void 0, function () {
|
|
271
|
-
var payload, visibilityTimeout, job, oldJob, e,
|
|
272
|
+
var payload, visibilityTimeout, job, oldJob, e, queue_1, result, err_1;
|
|
272
273
|
return __generator(this, function (_a) {
|
|
273
274
|
switch (_a.label) {
|
|
274
275
|
case 0:
|
|
@@ -315,8 +316,8 @@ var JobExecutor = /** @class */ (function () {
|
|
|
315
316
|
_a.label = 1;
|
|
316
317
|
case 1:
|
|
317
318
|
_a.trys.push([1, 3, , 4]);
|
|
318
|
-
|
|
319
|
-
return [4 /*yield*/, callback(
|
|
319
|
+
queue_1 = qname.slice(this.opt.prefix.length);
|
|
320
|
+
return [4 /*yield*/, (0, sentry_js_1.withSentry)(function () { return callback(queue_1, payload); }, this.opt, { job: job })];
|
|
320
321
|
case 2:
|
|
321
322
|
result = _a.sent();
|
|
322
323
|
debug('executeJob callback finished', { payload: payload, result: result });
|
|
@@ -340,7 +341,6 @@ var JobExecutor = /** @class */ (function () {
|
|
|
340
341
|
return [3 /*break*/, 4];
|
|
341
342
|
case 3:
|
|
342
343
|
err_1 = _a.sent();
|
|
343
|
-
// debug('exec.catch', err)
|
|
344
344
|
// Fail path for job execution
|
|
345
345
|
if (this.opt.verbose) {
|
|
346
346
|
console.error(chalk_1.default.red('FAILED'), message.Body);
|
|
@@ -204,7 +204,12 @@ var QueueManager = /** @class */ (function () {
|
|
|
204
204
|
return pair;
|
|
205
205
|
};
|
|
206
206
|
QueueManager.prototype.getPairs = function () {
|
|
207
|
-
|
|
207
|
+
var _this = this;
|
|
208
|
+
var now = new Date();
|
|
209
|
+
return this.selectedPairs.filter(function (_a) {
|
|
210
|
+
var qname = _a.qname, qrl = _a.qrl;
|
|
211
|
+
return !_this.keepInIcehouse(qrl, now);
|
|
212
|
+
});
|
|
208
213
|
};
|
|
209
214
|
QueueManager.prototype.shutdown = function () {
|
|
210
215
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Routines for handling Sentry instrumentation
|
|
4
|
+
*/
|
|
5
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
6
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
7
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
8
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
9
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
10
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
11
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
15
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
16
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
17
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
18
|
+
function step(op) {
|
|
19
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
20
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
21
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
22
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
23
|
+
switch (op[0]) {
|
|
24
|
+
case 0: case 1: t = op; break;
|
|
25
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
26
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
27
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
28
|
+
default:
|
|
29
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
30
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
31
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
32
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
33
|
+
if (t[2]) _.ops.pop();
|
|
34
|
+
_.trys.pop(); continue;
|
|
35
|
+
}
|
|
36
|
+
op = body.call(thisArg, _);
|
|
37
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
38
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
42
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
43
|
+
};
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.withSentry = void 0;
|
|
46
|
+
var debug_1 = __importDefault(require("debug"));
|
|
47
|
+
var node_1 = require("@sentry/node");
|
|
48
|
+
var debug = (0, debug_1.default)('qdone:sentry');
|
|
49
|
+
var sentryWasInit = false;
|
|
50
|
+
function withSentry(callback, opt, contexts) {
|
|
51
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
52
|
+
var result, err_1;
|
|
53
|
+
return __generator(this, function (_a) {
|
|
54
|
+
switch (_a.label) {
|
|
55
|
+
case 0:
|
|
56
|
+
debug({ withSentry: { callback: callback, opt: opt, contexts: contexts } });
|
|
57
|
+
// Bail if sentry isn't enabled
|
|
58
|
+
if (!opt.sentryDsn)
|
|
59
|
+
return [2 /*return*/, callback()
|
|
60
|
+
// Init sentry if it's not already
|
|
61
|
+
];
|
|
62
|
+
// Init sentry if it's not already
|
|
63
|
+
if (!sentryWasInit) {
|
|
64
|
+
(0, node_1.init)({ dsn: opt.sentryDsn, traceSampleRate: 0 });
|
|
65
|
+
sentryWasInit = true;
|
|
66
|
+
}
|
|
67
|
+
_a.label = 1;
|
|
68
|
+
case 1:
|
|
69
|
+
_a.trys.push([1, 3, , 5]);
|
|
70
|
+
return [4 /*yield*/, callback()];
|
|
71
|
+
case 2:
|
|
72
|
+
result = _a.sent();
|
|
73
|
+
debug({ result: result });
|
|
74
|
+
return [2 /*return*/, result];
|
|
75
|
+
case 3:
|
|
76
|
+
err_1 = _a.sent();
|
|
77
|
+
debug({ err: err_1 });
|
|
78
|
+
return [4 /*yield*/, (0, node_1.withScope)(function (scope) {
|
|
79
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
80
|
+
var key, stdout, stderr, sentryResult;
|
|
81
|
+
return __generator(this, function (_a) {
|
|
82
|
+
switch (_a.label) {
|
|
83
|
+
case 0:
|
|
84
|
+
scope.setContext('opt', opt);
|
|
85
|
+
if (contexts instanceof Object) {
|
|
86
|
+
for (key in contexts)
|
|
87
|
+
scope.setContext(key, contexts[key]);
|
|
88
|
+
if (err_1.stdout && err_1.stderr) {
|
|
89
|
+
stdout = err_1.stdout, stderr = err_1.stderr;
|
|
90
|
+
scope.setContext('IO', { stdout: stdout, stderr: stderr });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return [4 /*yield*/, (0, node_1.captureException)(err_1)];
|
|
94
|
+
case 1:
|
|
95
|
+
sentryResult = _a.sent();
|
|
96
|
+
debug({ sentryResult: sentryResult });
|
|
97
|
+
return [2 /*return*/];
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
})];
|
|
102
|
+
case 4:
|
|
103
|
+
_a.sent();
|
|
104
|
+
throw err_1;
|
|
105
|
+
case 5: return [2 /*return*/];
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
exports.withSentry = withSentry;
|
|
111
|
+
debug('loaded');
|
package/package.json
CHANGED
package/src/consumer.js
CHANGED
|
@@ -60,7 +60,7 @@ export async function processMessages (queues, callback, options) {
|
|
|
60
60
|
lastLatency = latency
|
|
61
61
|
})
|
|
62
62
|
const jobExecutor = new JobExecutor(opt)
|
|
63
|
-
const queueManager = new QueueManager(opt, queues)
|
|
63
|
+
const queueManager = new QueueManager(opt, queues, 60)
|
|
64
64
|
// debug({ systemMonitor, jobExecutor, queueManager })
|
|
65
65
|
|
|
66
66
|
// This delay function keeps a timeout reference around so it can be
|
|
@@ -113,15 +113,15 @@ export async function processMessages (queues, callback, options) {
|
|
|
113
113
|
|
|
114
114
|
while (!shutdownRequested) { // eslint-disable-line
|
|
115
115
|
// Figure out how we are running
|
|
116
|
-
const allowedJobs = opt.maxConcurrentJobs - jobExecutor.activeJobCount() - maxReturnCount
|
|
116
|
+
const allowedJobs = Math.max(0, opt.maxConcurrentJobs - jobExecutor.activeJobCount() - maxReturnCount)
|
|
117
117
|
const maxLatency = 100
|
|
118
|
-
const latency = systemMonitor.getLatency()
|
|
118
|
+
const latency = systemMonitor.getLatency() || 10
|
|
119
119
|
const latencyFactor = 1 - Math.abs(Math.min(latency / maxLatency, 1)) // 0 if latency is at max, 1 if latency 0
|
|
120
120
|
const targetJobs = Math.round(allowedJobs * latencyFactor)
|
|
121
|
-
// debug({ allowedJobs, maxLatency, latency, latencyFactor, targetJobs, activeQrls })
|
|
122
|
-
|
|
123
121
|
let jobsLeft = targetJobs
|
|
122
|
+
debug({ jobCount: jobExecutor.activeJobCount(), maxReturnCount, allowedJobs, maxLatency, latency, latencyFactor, targetJobs, activeQrls })
|
|
124
123
|
for (const { qname, qrl } of queueManager.getPairs()) {
|
|
124
|
+
debug({ evaluating: { qname, qrl, jobsLeft, activeQrlsHasQrl: activeQrls.has(qrl) } })
|
|
125
125
|
if (jobsLeft <= 0 || activeQrls.has(qrl)) continue
|
|
126
126
|
const maxMessages = Math.min(10, jobsLeft)
|
|
127
127
|
listen(qname, qrl, maxMessages)
|
|
@@ -129,7 +129,7 @@ export async function processMessages (queues, callback, options) {
|
|
|
129
129
|
if (opt.verbose) {
|
|
130
130
|
console.error(chalk.blue('Listening on: '), qname)
|
|
131
131
|
}
|
|
132
|
-
|
|
132
|
+
debug({ listenedTo: { qname, maxMessages, jobsLeft } })
|
|
133
133
|
}
|
|
134
134
|
await delay(1000)
|
|
135
135
|
}
|
|
@@ -3,13 +3,12 @@
|
|
|
3
3
|
* their visibility timeouts and deleting them when they are successful.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
DeleteMessageBatchCommand
|
|
9
|
-
} from '@aws-sdk/client-sqs'
|
|
6
|
+
import { ChangeMessageVisibilityBatchCommand, DeleteMessageBatchCommand } from '@aws-sdk/client-sqs'
|
|
7
|
+
|
|
10
8
|
import chalk from 'chalk'
|
|
11
9
|
import Debug from 'debug'
|
|
12
10
|
|
|
11
|
+
import { withSentry } from '../sentry.js'
|
|
13
12
|
import { getSQSClient } from '../sqs.js'
|
|
14
13
|
|
|
15
14
|
const debug = Debug('qdone:jobExecutor')
|
|
@@ -243,7 +242,7 @@ export class JobExecutor {
|
|
|
243
242
|
// Execute job
|
|
244
243
|
try {
|
|
245
244
|
const queue = qname.slice(this.opt.prefix.length)
|
|
246
|
-
const result = await callback(queue, payload)
|
|
245
|
+
const result = await withSentry(() => callback(queue, payload), this.opt, { job })
|
|
247
246
|
debug('executeJob callback finished', { payload, result })
|
|
248
247
|
if (this.opt.verbose) {
|
|
249
248
|
console.error(chalk.green('SUCCESS'), message.Body)
|
|
@@ -263,7 +262,6 @@ export class JobExecutor {
|
|
|
263
262
|
}
|
|
264
263
|
this.stats.jobsSucceeded++
|
|
265
264
|
} catch (err) {
|
|
266
|
-
// debug('exec.catch', err)
|
|
267
265
|
// Fail path for job execution
|
|
268
266
|
if (this.opt.verbose) {
|
|
269
267
|
console.error(chalk.red('FAILED'), message.Body)
|
package/src/sentry.js
CHANGED
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import Debug from 'debug'
|
|
6
|
-
import { init, captureException } from '@sentry/node'
|
|
6
|
+
import { init, withScope, captureException } from '@sentry/node'
|
|
7
7
|
|
|
8
8
|
const debug = Debug('qdone:sentry')
|
|
9
9
|
|
|
10
10
|
let sentryWasInit = false
|
|
11
|
-
export async function withSentry (callback, opt) {
|
|
11
|
+
export async function withSentry (callback, opt, contexts) {
|
|
12
|
+
debug({ withSentry: { callback, opt, contexts } })
|
|
12
13
|
// Bail if sentry isn't enabled
|
|
13
14
|
if (!opt.sentryDsn) return callback()
|
|
14
15
|
|
|
@@ -23,8 +24,20 @@ export async function withSentry (callback, opt) {
|
|
|
23
24
|
return result
|
|
24
25
|
} catch (err) {
|
|
25
26
|
debug({ err })
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
await withScope(async function (scope) {
|
|
28
|
+
scope.setContext('opt', opt)
|
|
29
|
+
if (contexts instanceof Object) {
|
|
30
|
+
for (const key in contexts) scope.setContext(key, contexts[key])
|
|
31
|
+
if (err.stdout && err.stderr) {
|
|
32
|
+
const { stdout, stderr } = err
|
|
33
|
+
scope.setContext('IO', { stdout, stderr })
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const sentryResult = await captureException(err)
|
|
37
|
+
debug({ sentryResult })
|
|
38
|
+
})
|
|
28
39
|
throw err
|
|
29
40
|
}
|
|
30
41
|
}
|
|
42
|
+
|
|
43
|
+
debug('loaded')
|