keuss 1.7.3 → 2.0.0

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 +11 -6
  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 +14 -10
  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
@@ -1,99 +0,0 @@
1
- const Chance = require ('chance');
2
- const chance = new Chance();
3
-
4
- const MQ = require ('../../../backends/pl-mongo');
5
-
6
- function loop (n, fn, cb) {
7
- if (n == 0) return cb ();
8
- fn (n, err => {
9
- if (err) return cb (err);
10
- setImmediate (() => loop (n-1, fn, cb));
11
- });
12
- }
13
-
14
- const factory_opts = {
15
- url: 'mongodb://localhost/qeus'
16
- };
17
-
18
- function get_a_delay (min, max) {
19
- return chance.integer ({min, max});
20
- }
21
-
22
- const num_elems = 37;
23
- let processed = 0;
24
-
25
- function sink_process (elem, done) {
26
- setTimeout (() => {
27
- console.log ('%s: sunk elem [a %d, choice %d, tries %d]', this.name(), elem.payload.a, elem.payload.choice, elem.payload.choice_try);
28
- done();
29
-
30
- processed++;
31
- if (processed == num_elems) {
32
- setTimeout (() =>{
33
- console.log ('processing done, exiting');
34
- process.exit (0);
35
- }, 1000);
36
- }
37
- }, get_a_delay (10, 20));
38
- }
39
-
40
- function dl_process (elem, done) {
41
- // pass element to next queue, set payload.passed to true
42
- done (null, {
43
- update: {
44
- $set: {stamp_0: 'passed'}
45
- }
46
- });
47
- }
48
-
49
- function choice_process (elem, done) {
50
- setTimeout (() => {
51
- if (chance.bool ({likelihood: 9})) {
52
- console.log ('%s: failing on elem %o on try [%d]', this.name(), elem.payload, elem.tries);
53
- return done ({e: 'cl1 induced a failure'});
54
- }
55
-
56
- const idx = chance.pickone([0, 1, 2]);
57
- console.log ('%s: passing elem %o to %d on try [%d]', this.name(), elem.payload, idx, elem.tries);
58
- done (null, {
59
- dst: idx,
60
- update: {
61
- $set: {stamp_1: 'passed', choice: idx, choice_try: elem.tries}
62
- }
63
- });
64
- }, get_a_delay (10, 20));
65
- }
66
-
67
- // initialize factory
68
- MQ (factory_opts, (err, factory) => {
69
- if (err) return console.error (err);
70
-
71
- const q_opts = {};
72
-
73
- factory
74
- .builder ()
75
- .pipeline ('the-pipeline')
76
- .queue ('test_pl_1', q_opts)
77
- .queue ('test_pl_2', q_opts)
78
- .queue ('test_pl_3', q_opts)
79
- .queue ('test_pl_4', q_opts)
80
- .queue ('test_pl_5', q_opts)
81
- .directLink ('test_pl_1', 'test_pl_2', dl_process)
82
- .choiceLink ('test_pl_2', ['test_pl_3', 'test_pl_4', 'test_pl_5'], choice_process)
83
- .sink ('test_pl_3', sink_process)
84
- .sink ('test_pl_4', sink_process)
85
- .sink ('test_pl_5', sink_process)
86
- .onError (console.log)
87
- .done ((err, pl) => {
88
- if (err) return console.error (err);
89
- console.log ('pipeline IS READY')
90
- pl.start ();
91
- console.log ('pipeline IS RUNNING, inserting load')
92
-
93
- loop (
94
- num_elems,
95
- (n, next) => setTimeout (() => pl.queues()['test_pl_1'].push ({a:n, b:'see it fail...'}, next), chance.integer ({min:0, max: 20})),
96
- err => console.log (err || 'done')
97
- );
98
- });
99
- });
@@ -1,127 +0,0 @@
1
- const Chance = require ('chance');
2
-
3
-
4
- const chance = new Chance();
5
-
6
- const MQ = require ('../../../backends/pl-mongo');
7
-
8
- function loop (n, fn, cb) {
9
- if (n == 0) return cb ();
10
- fn (n, err => {
11
- if (err) return cb (err);
12
- setImmediate (() => loop (n-1, fn, cb));
13
- });
14
- }
15
-
16
- const factory_opts = {
17
- url: 'mongodb://localhost/qeus'
18
- };
19
-
20
- const bs_src_array = [
21
- `
22
- const Chance = require ('chance');
23
- const chance = new Chance();
24
- `,
25
- `
26
- function get_a_delay (min, max) {
27
- return chance.integer ({min, max});
28
- }
29
- `,
30
- `
31
- function sink_process (elem, done) {
32
- setTimeout (() => {
33
- console.log ('%s: sunk elem [a %d, choice %d, tries %d]', this.name(), elem.payload.a, elem.payload.choice, elem.payload.choice_try);
34
- done();
35
-
36
- processed++;
37
- if (processed == num_elems) {
38
- setTimeout (() =>{
39
- console.log ('processing done, exiting');
40
- process.exit (0);
41
- }, 1000);
42
- }
43
-
44
- }, get_a_delay (10, 20));
45
- }
46
-
47
- function dl_process (elem, done) {
48
- // pass element to next queue, set payload.passed to true
49
- done (null, {
50
- update: {
51
- $set: {stamp_0: 'passed'}
52
- }
53
- });
54
- }
55
-
56
- function choice_process (elem, done) {
57
- setTimeout (() => {
58
- if (chance.bool ({likelihood: 9})) {
59
- console.log ('%s: failing on elem %o on try [%d]', this.name(), elem.payload, elem.tries);
60
- return done ({e: 'cl1 induced a failure'});
61
- }
62
-
63
- const idx = chance.pickone([0, 1, 2]);
64
- console.log ('%s: passing elem %o to %d on try [%d]', this.name(), elem.payload, idx, elem.tries);
65
- done (null, {
66
- dst: idx,
67
- update: {
68
- $set: {stamp_1: 'passed', choice: idx, choice_try: elem.tries}
69
- }
70
- });
71
- }, get_a_delay (10, 20));
72
- }
73
- `
74
- ];
75
-
76
- const setup_src_array = [
77
- `
78
- const q_opts = {};
79
-
80
- builder
81
- .queue ('test_pl_1', q_opts)
82
- .queue ('test_pl_2', q_opts)
83
- .queue ('test_pl_3', q_opts)
84
- .queue ('test_pl_4', q_opts)
85
- .queue ('test_pl_5', q_opts)
86
- .directLink ('test_pl_1', 'test_pl_2', dl_process)
87
- .choiceLink ('test_pl_2', ['test_pl_3', 'test_pl_4', 'test_pl_5'], choice_process)
88
- .sink ('test_pl_3', sink_process)
89
- .sink ('test_pl_4', sink_process)
90
- .sink ('test_pl_5', sink_process)
91
- .onError (console.log)
92
- .done (done);
93
- `
94
- ];
95
-
96
- const num_elems = 3;
97
- let processed = 0;
98
-
99
- // initialize factory
100
- MQ (factory_opts, (err, factory) => {
101
- if (err) return console.error (err);
102
-
103
- factory.pipelineFromRecipe (
104
- 'a_test_etcher',
105
- bs_src_array,
106
- setup_src_array,
107
- {
108
- context: {
109
- num_elems,
110
- processed,
111
- process,
112
- console
113
- }
114
- }, (err, pl) => {
115
- if (err) return console.error (err);
116
- console.log ('pipeline IS READY')
117
- pl.start ();
118
- console.log ('pipeline IS RUNNING, inserting load')
119
-
120
- loop (
121
- num_elems,
122
- (n, next) => setTimeout (() => pl.queues()['test_pl_1'].push ({a:n, b:'see it fail...'}, next), chance.integer ({min:0, max: 20})),
123
- err => console.log (err || 'done')
124
- );
125
- }
126
- );
127
- });
@@ -1,38 +0,0 @@
1
- var MQ = require ('../../../backends/pl-mongo');
2
- var PDL = require ('../../../Pipeline/DirectLink');
3
- var async = require ('async');
4
-
5
- var factory_opts = {
6
- url: 'mongodb://localhost/qeus'
7
- };
8
-
9
- // initialize factory
10
- MQ (factory_opts, (err, factory) => {
11
- if (err) return console.error (err);
12
-
13
- // factory ready, create 2 queues on default pipeline
14
- var q_opts = {};
15
- var q1 = factory.queue ('test_pl_1', q_opts);
16
- var q2 = factory.queue ('test_pl_2', q_opts);
17
-
18
- // tie them up, q1 -> q2
19
- var pdl = new PDL (q1, q2);
20
-
21
- pdl.start (function (elem, done) {
22
- // pass element to next queue, set payload.passed to true
23
- done (null, {
24
- update: {
25
- $set: {passed: true}
26
- }
27
- });
28
- });
29
-
30
- // insert elements in the entry queue
31
- async.timesLimit (3, 3, (n, next) => q1.push ({a:n, b:'see it spin...'}, next));
32
-
33
- // read elements at the outer end
34
- async.timesLimit (3, 3, (n, next) => q2.pop ('exit', (err, res) => {
35
- console.log ('end point get', res);
36
- next ();
37
- }));
38
- });
@@ -1,115 +0,0 @@
1
- // mongodb: create a consumer and a producer
2
- const Chance = require ('chance');
3
-
4
- const MQ = require ('../../../backends/pl-mongo');
5
- const DCT = require ('../../../Pipeline/DirectLink');
6
- const SNK = require ('../../../Pipeline/Sink');
7
- const CHC = require ('../../../Pipeline/ChoiceLink');
8
-
9
-
10
- const chance = new Chance();
11
-
12
- const num_elems = 100;
13
- let processed = 0;
14
-
15
-
16
- function get_a_delay (min, max) {
17
- return chance.integer ({min, max});
18
- }
19
-
20
- function loop (n, fn, cb) {
21
- if (n == 0) return cb ();
22
- fn (n, err => {
23
- if (err) return cb (err);
24
- setImmediate (() => loop (n-1, fn, cb));
25
- });
26
- }
27
-
28
- function sink_process (elem, done) {
29
- setTimeout (() => {
30
- console.log ('%s: sunk elem [a %d, choice %d]', this.name(), elem.payload.a, elem.payload.choice);
31
- done();
32
-
33
- processed++;
34
- if (processed == num_elems) {
35
- setTimeout (() =>{
36
- console.log ('processing done, exiting');
37
- process.exit (0);
38
- }, 1000);
39
- }
40
-
41
- }, get_a_delay (10, 20));
42
- }
43
-
44
-
45
- const factory_opts = {
46
- url: 'mongodb://localhost/qeus_pl',
47
- options: { useNewUrlParser: true },
48
- deadletter: {
49
- max_ko: 3
50
- }
51
- };
52
-
53
- // initialize factory
54
- MQ (factory_opts, (err, factory) => {
55
- if (err) return console.error (err);
56
-
57
- // factory ready, create queues on default pipeline
58
- const q_opts = {aaa: 666, b: 'yy'};
59
- const q1 = factory.queue ('pl_many_q_1', q_opts);
60
- const q2 = factory.queue ('pl_many_q_2', q_opts);
61
- const q3 = factory.queue ('pl_many_q_3', q_opts);
62
- const q4 = factory.queue ('pl_many_q_4', q_opts);
63
- const q5 = factory.queue ('pl_many_q_5', q_opts);
64
-
65
- // tie them up:
66
- const dl1 = new DCT (q1, q2);
67
- const cl1 = new CHC (q2, [q3, q4, q5]);
68
- const sk1 = new SNK (q3);
69
- const sk2 = new SNK (q4);
70
- const sk3 = new SNK (q5);
71
-
72
- sk1.on_data (sink_process);
73
- sk2.on_data (sink_process);
74
- sk3.on_data (sink_process);
75
-
76
- cl1.on_data (function (elem, done) {
77
- setTimeout (() => {
78
- if (chance.bool ({likelihood: 90})) {
79
- return done ({e: 'cl1 induced a failure'});
80
- }
81
-
82
- const idx = chance.pickone([0, 1, 2]);
83
- console.log ('%s: passing elem %o to %d on try [%d]', this.name(), elem.payload, idx, elem.tries);
84
- done (null, {
85
- dst: idx,
86
- update: {
87
- $set: {stamp_1: 'passed', choice: idx}
88
- }
89
- });
90
- }, get_a_delay (10, 100));
91
- });
92
-
93
- dl1.on_data (function (elem, done) {
94
- setTimeout (() => {
95
- console.log ('%s: passing elem %o', this.name(), elem.payload);
96
- done (null, {
97
- update: {
98
- $set: {stamp_0: 'passed'}
99
- }
100
- });
101
- }, get_a_delay (10, 100));
102
- });
103
-
104
- sk1.start ();
105
- sk2.start ();
106
- sk3.start ();
107
- cl1.start ();
108
- dl1.start ();
109
-
110
- loop (
111
- num_elems,
112
- (n, next) => setTimeout (() => q1.push ({a:n, b:'see it fail...'}, next), chance.integer ({min:0, max: 20})),
113
- err => console.log (err || 'done')
114
- );
115
- });
@@ -1,49 +0,0 @@
1
- /*
2
- *
3
- * very simple example of push & pop: an element is pushed, and then popped
4
- *
5
- */
6
-
7
- const async = require ('async');
8
- const MQ = require ('../../backends/mongo');
9
-
10
- // initialize factory
11
- MQ ({
12
- url: 'mongodb://localhost/keuss_test'
13
- }, (err, factory) => {
14
- if (err) return console.error(err);
15
-
16
- // factory ready, create one queue
17
- const q = factory.queue ('test_queue', {});
18
-
19
- async.series([
20
- // push element
21
- cb => q.push (
22
- {elem: 1, headline: 'something something', tags: {a: 1, b: 2}}, // this is the payload
23
- {
24
- hdrs: {h1: 'aaa', h2: 12, h3: false} // let's add some headers too
25
- },
26
- cb
27
- ),
28
- // pop element
29
- cb => q.pop ('consumer-1', cb)
30
- ], (err, res) => {
31
- if (err) {
32
- console.error (err);
33
- }
34
- else {
35
- console.log (res[1]);
36
- // this should print something like:
37
- // {
38
- // _id: <some id>,
39
- // mature: <some date>,
40
- // payload: { elem: 1, headline: 'something something', tags: { a: 1, b: 2 } },
41
- // tries: 0
42
- // hdrs: {h1: 'aaa', h2: 12, h3: false}
43
- // }
44
- }
45
-
46
- factory.close ();
47
- });
48
- });
49
-
@@ -1,44 +0,0 @@
1
- /*
2
- *
3
- * very simple example of push-reserve-rollback-reserve-commit: one element is pushed,
4
- * then reserved, then rolled back (that is, rejected ad back to queue with a delay)
5
- * Then, it is reserved again and then, finally, committed (and removed fro the queue)
6
- *
7
- */
8
-
9
- const async = require ('async');
10
- const MQ = require ('../../backends/mongo');
11
-
12
- // initialize factory
13
- MQ ({
14
- url: 'mongodb://localhost/keuss_test'
15
- }, (err, factory) => {
16
- if (err) return console.error(err);
17
-
18
- // factory ready, create one queue
19
- const q = factory.queue ('test_queue', {});
20
-
21
- async.waterfall ([
22
- // element is pushed to queue
23
- cb => q.push ({elem: 1, headline: 'something something', tags: {a: 1, b: 2}}, cb),
24
- // element is reserved...
25
- (item_id, cb) => q.pop ('consumer-1', {reserve: true}, cb),
26
- // ... and rejected back to queue with a delay of 1.5 sec
27
- (item, cb) => {
28
- console.log ('%s: got %o', new Date().toString (), item);
29
- const next_t = new Date().getTime () + 1500;
30
- q.ko (item, next_t, cb);
31
- },
32
- // Element is reserved gain. It will not finish until 1.5 secs have passed
33
- (ko_res, cb) => q.pop ('consumer-1', {reserve: true}, cb),
34
- // and finally, it is committed
35
- (item, cb) => {
36
- console.log ('%s: got %o', new Date().toString (), item);
37
- q.ok (item, cb);
38
- },
39
- ], (err, res) => {
40
- if (err) console.error (err);
41
- factory.close ();
42
- });
43
- });
44
-
@@ -1,77 +0,0 @@
1
- /*
2
- *
3
- * simplest-possible producer and consumer loops: a loop of parallel producers push N elements in a queue;
4
- * another loop of parallel consumers pop the elements out of the queue
5
- *
6
- * Queue stats are also shown every second
7
- *
8
- */
9
-
10
-
11
- const async = require ('async');
12
-
13
- // choice of backend
14
- const MQ = require ('../../backends/bucket-mongo-safe');
15
- //const MQ = require ('../../backends/redis-oq');
16
- //const MQ = require ('../../backends/mongo');
17
- //const MQ = require ('../../backends/ps-mongo');
18
-
19
- // initialize factory
20
- MQ ({
21
- url: 'mongodb://localhost/keuss_test'
22
- }, (err, factory) => {
23
- if (err) return console.error(err);
24
-
25
- const consumers = 3;
26
- const producers = 3;
27
- const msgs = 100000;
28
-
29
- // factory ready, create one queue
30
- const q = factory.queue ('test_queue', {});
31
-
32
- // show stats every sec
33
- const timer = setInterval (() => {
34
- q.stats ((err, res) => console.log (' --> stats now: %o', res));
35
- }, 1000);
36
-
37
- async.parallel ([
38
- // producers' loop, with 'producers' parallel producers
39
- cb => async.timesLimit (msgs, producers, (n, next) => {
40
- q.push ({elem: n, headline: 'something something', tags: {a: 1, b: 2}}, next);
41
- }, err => {
42
- console.log ('producer loop ended');
43
- cb (err);
44
- }),
45
- // consumers' loop, with 'consumers' parallel consumers
46
- cb => async.timesLimit (msgs, consumers, (n, next) => {
47
- q.pop ('theconsumer', {reserve: true}, (err, item) => {
48
- if (err) return cb (err);
49
- q.ok (item, next);
50
- });
51
- }, err => {
52
- console.log ('consumer loop ended');
53
- cb (err);
54
- })
55
- ], err => {
56
- if (err) return console.error (err);
57
-
58
- clearInterval (timer);
59
-
60
- // all loops completed, cleanup & show stats
61
- async.series ([
62
- cb => q.drain (cb),
63
- cb => q.stats (cb),
64
- cb => setTimeout (cb, 1000),
65
- cb => q.stats (cb),
66
- ], (err, res) => {
67
- if (err) console.error (err);
68
- else {
69
- console.log ('stats right after drain: %o', res[1]);
70
- console.log ('stats once dust settled: %o', res[3]);
71
- }
72
-
73
- factory.close ();
74
- });
75
- });
76
- });
77
-
@@ -1,78 +0,0 @@
1
- /*
2
- *
3
- * simple sequence of insert, reserve, rollback and commits over a bucket-mongo-safe queue
4
- * every now and then queue stats are shown; a delay is added to ensure stats' flow happens
5
- *
6
- */
7
-
8
- const async = require('async');
9
- const MQ = require('../../backends/bucket-mongo-safe');
10
-
11
- const factory_opts = {
12
- url: 'mongodb://localhost/qeus',
13
- reserve_delay: 7
14
- };
15
-
16
- // initialize factory
17
- MQ(factory_opts, (err, factory) => {
18
- if (err) return console.error(err);
19
-
20
- // factory ready, create one queue
21
- const q = factory.queue('test_queue_rcr', {});
22
-
23
- let id = null;
24
-
25
- async.series([
26
- cb => q.push({ elem: 1, pl: 'twetrwte' }, cb),
27
- cb => q.push({ elem: 2, pl: 'twetrwte' }, cb),
28
- cb => q.push({ elem: 3, pl: 'twetrwte' }, cb),
29
- cb => setTimeout (cb, 500),
30
- cb => q.stats ((err, res) => {
31
- console.log('queue stats now: %o', res);
32
- cb(err);
33
- }),
34
- cb => q.pop ('c1', {reserve: true}, (err, res) => {
35
- id = res._id;
36
- console.log('reserved element %o, id is %s', res, id)
37
- cb(err);
38
- }),
39
- cb => setTimeout (cb, 500),
40
- cb => q.stats ((err, res) => {
41
- console.log('queue stats now: %o', res);
42
- cb(err);
43
- }),
44
- cb => q.ko(id, (err, res) => {
45
- console.log('rolled back element %s -> %s', id, res);
46
- cb();
47
- }),
48
- cb => setTimeout (cb, 500),
49
- cb => q.stats ((err, res) => {
50
- console.log('queue stats now: %o', res);
51
- cb(err);
52
- }),
53
- cb => q.pop ('c1', {reserve: true}, (err, res) => {
54
- id = res._id;
55
- console.log('reserved element %o, id is %s', res, id)
56
- cb(err);
57
- }),
58
- cb => setTimeout (cb, 500),
59
- cb => q.stats ((err, res) => {
60
- console.log('queue stats now: %o', res);
61
- cb(err);
62
- }),
63
- cb => q.ok (id, (err, res) => {
64
- console.log('commited element %s -> %s', id, res);
65
- cb();
66
- }),
67
- cb => setTimeout (cb, 1000),
68
- cb => q.stats ((err, res) => {
69
- console.log('queue stats now: %o', res);
70
- cb(err);
71
- }),
72
- cb => q.drain (cb),
73
- cb => {factory.close(); cb ();},
74
- ], err => {
75
- // all done
76
- if (err) console.log ('error: ', err)
77
- });
78
- });