keuss 1.7.4 → 2.0.1

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 (65) hide show
  1. package/Pipeline/Queue.js +0 -1
  2. package/QFactory.js +49 -17
  3. package/Queue.js +1 -4
  4. package/README.md +2 -1
  5. package/TODO +0 -9
  6. package/backends/bucket-mongo-safe.js +11 -11
  7. package/backends/intraorder.js +13 -11
  8. package/backends/mongo.js +12 -9
  9. package/backends/pl-mongo.js +8 -5
  10. package/backends/postgres.js +380 -0
  11. package/backends/ps-mongo.js +11 -8
  12. package/backends/redis-list.js +8 -8
  13. package/backends/redis-oq.js +8 -3
  14. package/backends/stream-mongo.js +10 -15
  15. package/package.json +12 -8
  16. package/stats/mem.js +0 -1
  17. package/.github/workflows/codeql-analysis.yml +0 -72
  18. package/bench/all-mongo.js +0 -108
  19. package/bench/multi-q.js +0 -85
  20. package/bench/redis-oq-consumer-producer.js +0 -52
  21. package/bench/redis-oq-consumer.js +0 -40
  22. package/bench/redis-oq-producer.js +0 -43
  23. package/docker-compose/docker-compose.yaml +0 -18
  24. package/docker-compose.yaml +0 -18
  25. package/examples/pipelines/builder/index.js +0 -99
  26. package/examples/pipelines/fromRecipe/index.js +0 -127
  27. package/examples/pipelines/simplest/index.js +0 -38
  28. package/examples/pipelines/simulation-fork/index.js +0 -115
  29. package/examples/snippets/01-simplest-pop-push.js +0 -49
  30. package/examples/snippets/02-simplest-reserve-rollback-commit.js +0 -44
  31. package/examples/snippets/03-simplest-producer-consumer-loops.js +0 -77
  32. package/examples/snippets/04-bucket-mongo-safe-insert-reserve-commit.js +0 -78
  33. package/examples/snippets/05-insert-reserve-rollback-deadletter.js +0 -105
  34. package/examples/snippets/06-random-consumer-producer.js +0 -270
  35. package/examples/snippets/07-stream-simple.js +0 -53
  36. package/examples/snippets/redislabs-consumer-producer.js +0 -44
  37. package/examples/snippets/with-redis-stats-and-signaller-consumer-producer.js +0 -52
  38. package/examples/webhooks/README.md +0 -36
  39. package/examples/webhooks/app.js +0 -70
  40. package/examples/webhooks/consumer.js +0 -98
  41. package/examples/webhooks/index.js +0 -55
  42. package/examples/webhooks/package-lock.json +0 -500
  43. package/examples/webhooks/package.json +0 -23
  44. package/examples/webhooks/wh-payload.json +0 -38
  45. package/playground/irc.js +0 -53
  46. package/playground/pl-rollback.js +0 -55
  47. package/playground/pl1.js +0 -74
  48. package/playground/q1.js +0 -34
  49. package/playground/simple-pl.js +0 -42
  50. package/playground/stream-loops.js +0 -114
  51. package/test/backends_bucket-at-least-once.js +0 -302
  52. package/test/backends_deadletter.js +0 -227
  53. package/test/backends_payload.js +0 -542
  54. package/test/backends_push-pop.js +0 -170
  55. package/test/backends_remove.js +0 -320
  56. package/test/backends_reserve-commit-rollback.js +0 -1033
  57. package/test/intraorder.js +0 -325
  58. package/test/pause.js +0 -220
  59. package/test/pipeline-Builder.js +0 -285
  60. package/test/pipeline-ChoiceLink.js +0 -241
  61. package/test/pipeline-DirectLink.js +0 -376
  62. package/test/pipeline-Sink.js +0 -175
  63. package/test/signal.js +0 -196
  64. package/test/stats.js +0 -296
  65. package/test/stream-mongo.js +0 -166
package/Pipeline/Queue.js CHANGED
@@ -37,7 +37,6 @@ class PipelinedMongoQueue extends Queue {
37
37
 
38
38
  this._col.insertOne (entry, {}, (err, result) => {
39
39
  if (err) return callback (err);
40
- // TODO result.insertedCount must be 1
41
40
  callback (null, result.insertedId);
42
41
  });
43
42
  }
package/QFactory.js CHANGED
@@ -1,12 +1,13 @@
1
- var async = require ('async');
2
- var _ = require ('lodash');
1
+ const async = require ('async');
2
+ const _ = require ('lodash');
3
3
 
4
- var LocalSignal = require ('./signal/local');
5
- var MemStats = require ('./stats/mem');
4
+ const LocalSignal = require ('./signal/local');
5
+ const MemStats = require ('./stats/mem');
6
6
 
7
- var debug = require('debug')('keuss:QFactory');
7
+ const debug = require('debug')('keuss:QFactory');
8
8
 
9
9
 
10
+ /////////////////////////////////////////////////////////////////////////////
10
11
  class QFactory {
11
12
  constructor (opts) {
12
13
  this._opts = opts || {};
@@ -15,6 +16,8 @@ class QFactory {
15
16
  debug ('created QFactory %s with opts %o', this._name, this._opts);
16
17
  }
17
18
 
19
+
20
+ /////////////////////////////////////////////////////////////////////////////
18
21
  async_init (cb) {
19
22
  if (!this._opts.stats) this._opts.stats = {};
20
23
  if (!this._opts.stats.opts) this._opts.stats.opts = {};
@@ -22,8 +25,8 @@ class QFactory {
22
25
  if (!this._opts.signaller) this._opts.signaller = {};
23
26
  if (!this._opts.signaller.opts) this._opts.signaller.opts = {};
24
27
 
25
- var signal_provider = this._opts.signaller.provider || LocalSignal;
26
- var stats_provider = this._opts.stats.provider || MemStats;
28
+ const signal_provider = this._opts.signaller.provider || LocalSignal;
29
+ const stats_provider = this._opts.stats.provider || MemStats;
27
30
 
28
31
  async.parallel ([
29
32
  cb => signal_provider (this._opts.signaller.opts, cb),
@@ -36,27 +39,40 @@ class QFactory {
36
39
  this._stats_factory = res[1];
37
40
 
38
41
  if (this._opts.deadletter) {
39
- this._deadletter_queue = this.queue (this._opts.deadletter.queue || '__deadletter__');
40
42
  this._max_ko = this._opts.deadletter.max_ko || 0;
41
- debug('%s: uses deadletter queue %s, max KO is %d', this._name, this._deadletter_queue.name(), this._max_ko);
43
+ const qname = this._opts.deadletter.queue || '__deadletter__';
44
+ debug('%s: uses deadletter queue %s, max KO is %d', this._name, qname, this._max_ko);
45
+ this.queue (qname, (err, dlq) => {
46
+ this._deadletter_queue = dlq;
47
+ cb (err);
48
+ });
49
+ }
50
+ else {
51
+ cb();
42
52
  }
43
-
44
- cb();
45
53
  });
46
54
  }
47
55
 
56
+
57
+ /////////////////////////////////////////////////////////////////////////////
48
58
  signaller_factory () {
49
59
  return this._signaller_factory;
50
60
  }
51
61
 
62
+
63
+ /////////////////////////////////////////////////////////////////////////////
52
64
  stats_factory () {
53
65
  return this._stats_factory;
54
66
  }
55
67
 
56
- queue (name, opts) {
57
- return null;
68
+
69
+ /////////////////////////////////////////////////////////////////////////////
70
+ queue (name, opts, cb) {
71
+ return cb ();
58
72
  }
59
73
 
74
+
75
+ /////////////////////////////////////////////////////////////////////////////
60
76
  close (cb) {
61
77
  debug ('%s: closing', this._name);
62
78
  async.parallel ([
@@ -65,50 +81,66 @@ class QFactory {
65
81
  ], cb);
66
82
  }
67
83
 
84
+
85
+ /////////////////////////////////////////////////////////////////////////////
68
86
  name () {
69
87
  return this._name;
70
88
  }
71
89
 
90
+
91
+ /////////////////////////////////////////////////////////////////////////////
72
92
  type () {
73
93
  return 'none';
74
94
  }
75
95
 
96
+
97
+ /////////////////////////////////////////////////////////////////////////////
76
98
  capabilities () {
77
99
  return {};
78
100
  }
79
101
 
102
+
103
+ /////////////////////////////////////////////////////////////////////////////
80
104
  deadletter_queue () {
81
105
  return this._deadletter_queue;
82
106
  }
83
107
 
108
+
109
+ /////////////////////////////////////////////////////////////////////////////
84
110
  max_ko () {
85
111
  return this._max_ko;
86
112
  }
87
113
 
114
+
115
+ /////////////////////////////////////////////////////////////////////////////
88
116
  list (opts, cb) {
89
117
  // use stats factory
90
118
  this._stats_factory.queues (this.name (), opts, cb);
91
119
  }
92
120
 
121
+
122
+ /////////////////////////////////////////////////////////////////////////////
93
123
  recreate_topology (cb) {
94
124
  debug ('%s: recreating topology', this._name);
95
125
 
96
126
  this.list ({full: true}, (err, ql) => {
97
127
  if (err) return cb (err);
98
128
 
99
- var ret = {};
129
+ const tasks = {};
100
130
 
101
131
  _.each (ql, (v, k) => {
102
132
  debug ('%s: recreating topology: adding queue %s with opts %o', this._name, k, v.opts);
103
- ret[k] = this.queue (k, v.opts);
133
+ ret[k] = cb => this.queue (k, v.opts, cb); // TODO fix to async
104
134
  });
105
135
 
106
- cb (null, ret);
136
+ async.parallel (tasks, cb);
107
137
  });
108
138
  }
109
139
 
140
+
141
+ /////////////////////////////////////////////////////////////////////////////
110
142
  to_descriptor_obj () {
111
- let obj = {
143
+ const obj = {
112
144
  name: this.name (),
113
145
  type: this.type (),
114
146
  opts: _.omit (this._opts, ['stats', 'signaller']),
package/Queue.js CHANGED
@@ -342,8 +342,6 @@ class Queue {
342
342
  //////////////////////////////////
343
343
  // obtain element from queue
344
344
  pop (cid, opts, callback) {
345
- // TODO fail if too many consumers?
346
-
347
345
  if (this._drained) return setImmediate (() => {
348
346
  debug ('%s: pop while drained, return error', this._name);
349
347
  if (callback) callback ('drain');
@@ -461,7 +459,7 @@ class Queue {
461
459
  if (
462
460
  (obj.tries) && // only if we got tries
463
461
  (this._factory.deadletter_queue ()) && // AND the factory has a deadletter queue
464
- (this._factory.max_ko ()) && // AND thee's a max ko attempts
462
+ (this._factory.max_ko ()) && // AND there's a max ko attempts
465
463
  (obj.tries > this._factory.max_ko ()) && // AND we got enough tries
466
464
  (this.name () != '__deadletter__') // and this queue is not deadletter already
467
465
  ) {
@@ -592,7 +590,6 @@ class Queue {
592
590
  }
593
591
  }
594
592
 
595
- // TODO eat up errors?
596
593
  if (err) {
597
594
  // get/reserve in error
598
595
  debug ('%s - tid %s: getOrReserve_cb in error: err %o', this._name, consumer.tid, err);
package/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  # Keuss
2
- Enterprise-grade Job Queues for node.js, backed by redis and/or MongoDB
2
+
3
+ Enterprise-grade Job Queues for node.js backed by redis, MongoDB or PostgreSQL
3
4
 
4
5
  * [Quickstart](https://pepmartinez.github.io/keuss/docs/quickstart)
5
6
  * [Documentation](https://pepmartinez.github.io/keuss/docs/)
package/TODO CHANGED
@@ -8,16 +8,7 @@ prio 1
8
8
  * pipelines
9
9
  + add some commonplace transforms (etl-like)
10
10
  + create a server for that, allow processor code defined externally
11
- * documentation
12
- + blog entries:
13
- - motivations on using mongodb+redis. comparatives, pros&cons
14
- - buckets
15
- - pipelines
16
- - tape
17
- - redis-oq
18
- - exotic experiments: intraorder
19
11
 
20
12
  prio 0
21
13
  -----------------------------------------------------------------
22
- * bridges?
23
14
  * signal queue creation or read queues on refresh?
@@ -96,8 +96,6 @@ class Bucket {
96
96
  elem.mature = this._mature;
97
97
  elem._id = this.id () + ':' + i;
98
98
 
99
- // TODO optimization: set this._b[i] = null
100
-
101
99
  if (is_reserve) {
102
100
  this._b_states[i] = State.Reserved;
103
101
  this._b_counts.Reserved++;
@@ -314,7 +312,6 @@ class BucketSet {
314
312
  if (bcket.exhausted ()) {
315
313
  debug ('bucket %s already exhausted, read another', bcket.id());
316
314
  this._active_bucket = null;
317
- // TODO loop internally!!!!!
318
315
  cb ();
319
316
  }
320
317
  else {
@@ -523,9 +520,7 @@ class BucketSet {
523
520
 
524
521
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
525
522
  class BucketMongoSafeQueue extends Queue {
526
-
527
523
  /*
528
-
529
524
  options:
530
525
  bucket_max_size || 1024;
531
526
  bucket_max_wait || 500;
@@ -540,9 +535,7 @@ class BucketMongoSafeQueue extends Queue {
540
535
  //////////////////////////////////////////////
541
536
  super (name, factory, opts, orig_opts);
542
537
 
543
- this._factory = factory;
544
538
  this._col = factory._db.collection (name);
545
- this._ensureIndexes (err => {});
546
539
 
547
540
  this._insert_bucket = {
548
541
  _id: new mongo.ObjectID (),
@@ -821,7 +814,7 @@ class BucketMongoSafeQueue extends Queue {
821
814
 
822
815
  /////////////////////////////////////////
823
816
  _ensureIndexes (cb) {
824
- this._col.createIndex ({mature : 1}, err => cb (err));
817
+ this._col.createIndex ({mature : 1}, err => cb (err, this));
825
818
  }
826
819
 
827
820
 
@@ -915,10 +908,17 @@ class Factory extends QFactory_MongoDB_defaults {
915
908
  this._db = mongo_conn.db();
916
909
  }
917
910
 
918
- queue (name, opts) {
919
- var full_opts = {}
911
+ queue (name, opts, cb) {
912
+ if (!cb) {
913
+ cb = opts;
914
+ opts = {};
915
+ }
916
+
917
+ const full_opts = {};
920
918
  _.merge(full_opts, this._opts, opts);
921
- return new BucketMongoSafeQueue (name, this, full_opts, opts);
919
+
920
+ const q = new BucketMongoSafeQueue (name, this, full_opts, opts);
921
+ q._ensureIndexes (cb);
922
922
  }
923
923
 
924
924
  close (cb) {
@@ -12,14 +12,10 @@ const debug = require('debug')('keuss:Queue:intraqueue');
12
12
 
13
13
 
14
14
  class IntraOrderedQueue extends Queue {
15
-
16
15
  //////////////////////////////////////////////
17
16
  constructor (name, factory, opts, orig_opts) {
18
17
  super (name, factory, opts, orig_opts);
19
-
20
- this._factory = factory;
21
18
  this._col = factory._db.collection (name);
22
- this.ensureIndexes (err => {});
23
19
  }
24
20
 
25
21
 
@@ -49,7 +45,6 @@ class IntraOrderedQueue extends Queue {
49
45
  this._col.updateOne (q, upd, opts, (err, result) => {
50
46
  debug ('insert: updateOne (%j, %j, %j) => (%j, %j)', q, upd, opts, err, result);
51
47
  if (err) return callback (err);
52
- // TODO result.insertedCount must be 1
53
48
  callback (null, result.upsertedId || q._id);
54
49
  });
55
50
  }
@@ -308,10 +303,10 @@ class IntraOrderedQueue extends Queue {
308
303
 
309
304
  //////////////////////////////////////////////////////////////////
310
305
  // create needed indexes for O(1) functioning
311
- ensureIndexes (cb) {
306
+ _ensureIndexes (cb) {
312
307
  async.series ([
313
- cb => this._col.createIndex ({mature : 1, qcnt: 1}, cb),
314
- ], cb);
308
+ cb => this._col.createIndex ({mature : 1, qcnt: 1}, err => cb (err)),
309
+ ], err => cb (err, this));
315
310
  }
316
311
  }
317
312
 
@@ -323,10 +318,17 @@ class Factory extends QFactory_MongoDB_defaults {
323
318
  this._db = mongo_conn.db();
324
319
  }
325
320
 
326
- queue (name, opts) {
327
- var full_opts = {};
321
+ queue (name, opts, cb) {
322
+ if (!cb) {
323
+ cb = opts;
324
+ opts = {};
325
+ }
326
+
327
+ const full_opts = {};
328
328
  _.merge(full_opts, this._opts, opts);
329
- return new IntraOrderedQueue (name, this, full_opts, opts);
329
+
330
+ const q = new IntraOrderedQueue (name, this, full_opts, opts);
331
+ q._ensureIndexes (cb);
330
332
  }
331
333
 
332
334
  close (cb) {
package/backends/mongo.js CHANGED
@@ -11,10 +11,7 @@ class SimpleMongoQueue extends Queue {
11
11
  //////////////////////////////////////////////
12
12
  constructor (name, factory, opts, orig_opts) {
13
13
  super (name, factory, opts, orig_opts);
14
-
15
- this._factory = factory;
16
14
  this._col = factory._db.collection (name);
17
- this.ensureIndexes (function (err) {});
18
15
  }
19
16
 
20
17
 
@@ -33,7 +30,6 @@ class SimpleMongoQueue extends Queue {
33
30
  insert (entry, callback) {
34
31
  this._col.insertOne (entry, {}, (err, result) => {
35
32
  if (err) return callback (err);
36
- // TODO result.insertedCount must be 1
37
33
  callback (null, result.insertedId);
38
34
  });
39
35
  }
@@ -213,8 +209,8 @@ class SimpleMongoQueue extends Queue {
213
209
 
214
210
  //////////////////////////////////////////////////////////////////
215
211
  // create needed indexes for O(1) functioning
216
- ensureIndexes (cb) {
217
- this._col.createIndex ({mature : 1}, err => cb (err));
212
+ _ensureIndexes (cb) {
213
+ this._col.createIndex ({mature : 1}, err => cb (err, this));
218
214
  }
219
215
  };
220
216
 
@@ -226,10 +222,17 @@ class Factory extends QFactory_MongoDB_defaults {
226
222
  this._db = mongo_conn.db();
227
223
  }
228
224
 
229
- queue (name, opts) {
230
- var full_opts = {};
225
+ queue (name, opts, cb) {
226
+ if (!cb) {
227
+ cb = opts;
228
+ opts = {};
229
+ }
230
+
231
+ const full_opts = {};
231
232
  _.merge(full_opts, this._opts, opts);
232
- return new SimpleMongoQueue (name, this, full_opts, opts);
233
+
234
+ const q = new SimpleMongoQueue (name, this, full_opts, opts);
235
+ q._ensureIndexes (cb);
233
236
  }
234
237
 
235
238
  close (cb) {
@@ -119,18 +119,21 @@ class Factory extends QFactory_MongoDB_defaults {
119
119
 
120
120
 
121
121
  ///////////////////////////////////////////////////////////
122
- queue (name, opts) {
123
- if (!opts) opts = {};
122
+ queue (name, opts, cb) {
123
+ if (!cb) {
124
+ cb = opts;
125
+ opts = {};
126
+ }
124
127
 
125
- var pl_name = opts.pipeline || 'default';
126
- var pipeline = this._pipelines[pl_name];
128
+ const pl_name = opts.pipeline || 'default';
129
+ let pipeline = this._pipelines[pl_name];
127
130
 
128
131
  if (!pipeline) {
129
132
  this._pipelines[pl_name] = new Pipeline (pl_name, this);
130
133
  pipeline = this._pipelines[pl_name];
131
134
  }
132
135
 
133
- return this._queue_from_pipeline (name, pipeline, opts);
136
+ return setImmediate (() => cb (null, this._queue_from_pipeline (name, pipeline, opts)));
134
137
  }
135
138
 
136
139