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.
@@ -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().setTimeout;
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
- // debug({ listenedTo: { qname, maxMessages, jobsLeft } })
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, queue, result, err_1;
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
- queue = qname.slice(this.opt.prefix.length);
319
- return [4 /*yield*/, callback(queue, payload)];
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
- return this.selectedPairs;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qdone",
3
- "version": "2.0.14-alpha",
3
+ "version": "2.0.16-alpha",
4
4
  "description": "Language agnostic job queue for SQS",
5
5
  "type": "module",
6
6
  "main": "./index.js",
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().setTimeout
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
- // debug({ listenedTo: { qname, maxMessages, jobsLeft } })
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
- ChangeMessageVisibilityBatchCommand,
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)
@@ -140,7 +140,8 @@ export class QueueManager {
140
140
  }
141
141
 
142
142
  getPairs () {
143
- return this.selectedPairs
143
+ const now = new Date()
144
+ return this.selectedPairs.filter(({ qname, qrl }) => !this.keepInIcehouse(qrl, now))
144
145
  }
145
146
 
146
147
  async shutdown () {
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
- const sentryResult = await captureException(err)
27
- debug({ sentryResult })
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')