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.
- package/Pipeline/Queue.js +0 -1
- package/QFactory.js +49 -17
- package/Queue.js +1 -4
- package/README.md +2 -1
- package/TODO +0 -9
- package/backends/bucket-mongo-safe.js +11 -11
- package/backends/intraorder.js +13 -11
- package/backends/mongo.js +12 -9
- package/backends/pl-mongo.js +8 -5
- package/backends/postgres.js +380 -0
- package/backends/ps-mongo.js +11 -8
- package/backends/redis-list.js +8 -8
- package/backends/redis-oq.js +8 -3
- package/backends/stream-mongo.js +10 -15
- package/package.json +12 -8
- package/stats/mem.js +0 -1
- package/.github/workflows/codeql-analysis.yml +0 -72
- package/bench/all-mongo.js +0 -108
- package/bench/multi-q.js +0 -85
- package/bench/redis-oq-consumer-producer.js +0 -52
- package/bench/redis-oq-consumer.js +0 -40
- package/bench/redis-oq-producer.js +0 -43
- package/docker-compose/docker-compose.yaml +0 -18
- package/docker-compose.yaml +0 -18
- package/examples/pipelines/builder/index.js +0 -99
- package/examples/pipelines/fromRecipe/index.js +0 -127
- package/examples/pipelines/simplest/index.js +0 -38
- package/examples/pipelines/simulation-fork/index.js +0 -115
- package/examples/snippets/01-simplest-pop-push.js +0 -49
- package/examples/snippets/02-simplest-reserve-rollback-commit.js +0 -44
- package/examples/snippets/03-simplest-producer-consumer-loops.js +0 -77
- package/examples/snippets/04-bucket-mongo-safe-insert-reserve-commit.js +0 -78
- package/examples/snippets/05-insert-reserve-rollback-deadletter.js +0 -105
- package/examples/snippets/06-random-consumer-producer.js +0 -270
- package/examples/snippets/07-stream-simple.js +0 -53
- package/examples/snippets/redislabs-consumer-producer.js +0 -44
- package/examples/snippets/with-redis-stats-and-signaller-consumer-producer.js +0 -52
- package/examples/webhooks/README.md +0 -36
- package/examples/webhooks/app.js +0 -70
- package/examples/webhooks/consumer.js +0 -98
- package/examples/webhooks/index.js +0 -55
- package/examples/webhooks/package-lock.json +0 -500
- package/examples/webhooks/package.json +0 -23
- package/examples/webhooks/wh-payload.json +0 -38
- package/playground/irc.js +0 -53
- package/playground/pl-rollback.js +0 -55
- package/playground/pl1.js +0 -74
- package/playground/q1.js +0 -34
- package/playground/simple-pl.js +0 -42
- package/playground/stream-loops.js +0 -114
- package/test/backends_bucket-at-least-once.js +0 -302
- package/test/backends_deadletter.js +0 -227
- package/test/backends_payload.js +0 -542
- package/test/backends_push-pop.js +0 -170
- package/test/backends_remove.js +0 -320
- package/test/backends_reserve-commit-rollback.js +0 -1033
- package/test/intraorder.js +0 -325
- package/test/pause.js +0 -220
- package/test/pipeline-Builder.js +0 -285
- package/test/pipeline-ChoiceLink.js +0 -241
- package/test/pipeline-DirectLink.js +0 -376
- package/test/pipeline-Sink.js +0 -175
- package/test/signal.js +0 -196
- package/test/stats.js +0 -296
- package/test/stream-mongo.js +0 -166
package/Pipeline/Queue.js
CHANGED
package/QFactory.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
const async = require ('async');
|
|
2
|
+
const _ = require ('lodash');
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
const LocalSignal = require ('./signal/local');
|
|
5
|
+
const MemStats = require ('./stats/mem');
|
|
6
6
|
|
|
7
|
-
|
|
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
|
-
|
|
26
|
-
|
|
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
|
-
|
|
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
|
-
|
|
57
|
-
|
|
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
|
-
|
|
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
|
-
|
|
136
|
+
async.parallel (tasks, cb);
|
|
107
137
|
});
|
|
108
138
|
}
|
|
109
139
|
|
|
140
|
+
|
|
141
|
+
/////////////////////////////////////////////////////////////////////////////
|
|
110
142
|
to_descriptor_obj () {
|
|
111
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
919
|
+
|
|
920
|
+
const q = new BucketMongoSafeQueue (name, this, full_opts, opts);
|
|
921
|
+
q._ensureIndexes (cb);
|
|
922
922
|
}
|
|
923
923
|
|
|
924
924
|
close (cb) {
|
package/backends/intraorder.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
233
|
+
|
|
234
|
+
const q = new SimpleMongoQueue (name, this, full_opts, opts);
|
|
235
|
+
q._ensureIndexes (cb);
|
|
233
236
|
}
|
|
234
237
|
|
|
235
238
|
close (cb) {
|
package/backends/pl-mongo.js
CHANGED
|
@@ -119,18 +119,21 @@ class Factory extends QFactory_MongoDB_defaults {
|
|
|
119
119
|
|
|
120
120
|
|
|
121
121
|
///////////////////////////////////////////////////////////
|
|
122
|
-
queue (name, opts) {
|
|
123
|
-
if (!
|
|
122
|
+
queue (name, opts, cb) {
|
|
123
|
+
if (!cb) {
|
|
124
|
+
cb = opts;
|
|
125
|
+
opts = {};
|
|
126
|
+
}
|
|
124
127
|
|
|
125
|
-
|
|
126
|
-
|
|
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
|
|