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.
- package/Pipeline/Queue.js +0 -1
- package/QFactory.js +11 -6
- 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 +14 -10
- 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
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
*
|
|
3
|
-
* deadletter simple demo: an item is repeatedly reserved and rejected, and
|
|
4
|
-
* after some rejections, the element goes to the __deadletter__ instead of
|
|
5
|
-
* going back to its queue (which is caught at the pop at line 98)
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
// var MQ = require('../../backends/bucket-mongo-safe');
|
|
10
|
-
// var MQ = require('../../backends/redis-oq');
|
|
11
|
-
var MQ = require('../../backends/ps-mongo');
|
|
12
|
-
|
|
13
|
-
var async = require('async');
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
function stats (q, cb) {
|
|
17
|
-
q.stats((err, res) => {
|
|
18
|
-
console.log('queue stats now: %o', res);
|
|
19
|
-
cb(err);
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function pop (q, stage, cb) {
|
|
24
|
-
q.pop('c1', { reserve: true }, (err, res) => {
|
|
25
|
-
stage.obj = res;
|
|
26
|
-
console.log('reserved element %o', res);
|
|
27
|
-
cb(err);
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function reject (q, stage, cb) {
|
|
32
|
-
var next_t = new Date().getTime() + 2000;
|
|
33
|
-
|
|
34
|
-
q.ko (stage.obj, next_t, (err, res) => {
|
|
35
|
-
if (err) {
|
|
36
|
-
console.error ('error in rollback of %s: %o', stage.obj._id, err);
|
|
37
|
-
return cb (err);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
console.log('rolled back element %s: %o', stage.obj._id, res);
|
|
41
|
-
cb();
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function accept (q, stage, cb) {
|
|
46
|
-
q.ok (stage.obj, (err, res) => {
|
|
47
|
-
if (err) {
|
|
48
|
-
console.error ('error in rollback of %s: %o', stage.obj._id, err);
|
|
49
|
-
return cb (err);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
console.log('commited element %s: %o', stage.obj._id, res);
|
|
53
|
-
cb();
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
var factory_opts = {
|
|
59
|
-
url: 'mongodb://localhost/qeus',
|
|
60
|
-
deadletter: {
|
|
61
|
-
max_ko: 3
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
// initialize factory
|
|
66
|
-
MQ(factory_opts, (err, factory) => {
|
|
67
|
-
if (err) return console.error(err);
|
|
68
|
-
|
|
69
|
-
// factory ready, create one queue
|
|
70
|
-
var q = factory.queue('test_queue_rcr', {});
|
|
71
|
-
|
|
72
|
-
// state is kept here
|
|
73
|
-
var stage = {};
|
|
74
|
-
|
|
75
|
-
async.series([
|
|
76
|
-
cb => q.push({ elem: 1, pl: 'twetrwte' }, (err, res) => {
|
|
77
|
-
console.log('pushed element');
|
|
78
|
-
cb(err);
|
|
79
|
-
}),
|
|
80
|
-
cb => pop (q, stage, cb),
|
|
81
|
-
cb => reject (q, stage, cb),
|
|
82
|
-
cb => pop (q, stage, cb),
|
|
83
|
-
cb => reject (q, stage, cb),
|
|
84
|
-
cb => pop (q, stage, cb),
|
|
85
|
-
cb => reject (q, stage, cb),
|
|
86
|
-
cb => pop (q, stage, cb),
|
|
87
|
-
cb => reject (q, stage, cb),
|
|
88
|
-
cb => pop (q, stage, cb),
|
|
89
|
-
cb => reject (q, stage, cb),
|
|
90
|
-
cb => pop (q, stage, cb),
|
|
91
|
-
cb => reject (q, stage, cb)
|
|
92
|
-
], err => {
|
|
93
|
-
// all done
|
|
94
|
-
if (err) console.error ('reject_line error: ', err);
|
|
95
|
-
else console.log ('reject_line done');
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
factory.deadletter_queue().pop('c2', (err, res) => {
|
|
99
|
-
console.log('from deadletter_queue, got element %o', res);
|
|
100
|
-
setTimeout (() => {
|
|
101
|
-
q.cancel ();
|
|
102
|
-
factory.close (() => console.log ('done'));
|
|
103
|
-
}, 1000);
|
|
104
|
-
});
|
|
105
|
-
});
|
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
*
|
|
3
|
-
* Runs a set of producers and consumers, where consumers do a reserve-commit-rollback cycle. In each cycle a
|
|
4
|
-
* consumer would randomly choose whether to commit or rollback (10% chance of rollback). No deadletter is used
|
|
5
|
-
* so elements are retried ad infinitum until processed ok
|
|
6
|
-
*
|
|
7
|
-
* Upon completion (all items generated and consumed ok) some stats will be shown
|
|
8
|
-
*
|
|
9
|
-
* It uses bucket-mongo-safe backend for high throughput
|
|
10
|
-
*
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
var MQ = require ('../../backends/bucket-mongo-safe');
|
|
14
|
-
|
|
15
|
-
var _ = require ('lodash');
|
|
16
|
-
var async = require ('async');
|
|
17
|
-
var Chance = require ('chance');
|
|
18
|
-
var chance = new Chance();
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
var factory_opts = {
|
|
22
|
-
url: 'mongodb://localhost/qeus',
|
|
23
|
-
name: 'Random-NS',
|
|
24
|
-
reject_delta_base: 2000,
|
|
25
|
-
reject_delta_factor: 2000
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
// test dimensions: elems to produce and consume, number of consumers, number of producers
|
|
29
|
-
const num_elems = 1000000;
|
|
30
|
-
const num_producers = 3;
|
|
31
|
-
const num_consumers = 7;
|
|
32
|
-
const commit_likelihood = 75;
|
|
33
|
-
|
|
34
|
-
// stats holder
|
|
35
|
-
var selfs = {
|
|
36
|
-
consumers: {},
|
|
37
|
-
producers: {}
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
var shareds = {};
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
44
|
-
function consume_one (shared_ctx, self_ctx, cb) {
|
|
45
|
-
if (shared_ctx.pop_count > shared_ctx.pop_max) {
|
|
46
|
-
console.log ('pop consumer %s ended', self_ctx.id);
|
|
47
|
-
shared_ctx.q.cancel ();
|
|
48
|
-
return cb ();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
shared_ctx.pop_count ++;
|
|
52
|
-
self_ctx.pop_count ++;
|
|
53
|
-
|
|
54
|
-
shared_ctx.q.pop (self_ctx.id, shared_ctx.pop_opts, (err, res) => {
|
|
55
|
-
if (err) return cb (err);
|
|
56
|
-
if ((shared_ctx.pop_count % 100000) == 0) console.log ('%s : consumed #%d elems', self_ctx.id, shared_ctx.pop_count);
|
|
57
|
-
consume_one (shared_ctx, self_ctx, cb);
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
function run_a_pop_consumer (shared_ctx, cb) {
|
|
63
|
-
var self_ctx = {
|
|
64
|
-
id: chance.word (),
|
|
65
|
-
pop_count: 0
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
selfs.consumers[self_ctx.id] = self_ctx;
|
|
69
|
-
|
|
70
|
-
consume_one (shared_ctx, self_ctx, cb);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
function run_consumers (q, cnt, cb) {
|
|
75
|
-
var shared_ctx = {
|
|
76
|
-
q: q,
|
|
77
|
-
pop_count: 0,
|
|
78
|
-
pop_max: cnt,
|
|
79
|
-
pop_opts: {}
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
shareds.pc = shared_ctx;
|
|
83
|
-
|
|
84
|
-
var tasks = [];
|
|
85
|
-
for (var i = 0; i < num_consumers; i++) tasks.push ((cb) => run_a_pop_consumer (shared_ctx, cb));
|
|
86
|
-
async.parallel (tasks, cb);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
90
|
-
|
|
91
|
-
var das_pop = 0;
|
|
92
|
-
var das_ko = 0;
|
|
93
|
-
var das_ok = 0;
|
|
94
|
-
|
|
95
|
-
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
96
|
-
function reserve_and_commit_one (shared_ctx, self_ctx, cb) {
|
|
97
|
-
self_ctx.pop_count ++;
|
|
98
|
-
|
|
99
|
-
shared_ctx.q.pop (self_ctx.consumer, shared_ctx.pop_opts, (err, res) => {
|
|
100
|
-
if (err) return cb (err);
|
|
101
|
-
self_ctx.resv_count ++;
|
|
102
|
-
|
|
103
|
-
das_pop++;
|
|
104
|
-
|
|
105
|
-
if (chance.bool({likelihood: commit_likelihood})) {
|
|
106
|
-
shared_ctx.q.ok (res._id, (err) => {
|
|
107
|
-
if (err) return cb (err);
|
|
108
|
-
self_ctx.ok_count ++;
|
|
109
|
-
shared_ctx.pop_count ++;
|
|
110
|
-
das_ok++;
|
|
111
|
-
|
|
112
|
-
if (shared_ctx.pop_count > shared_ctx.pop_max) {
|
|
113
|
-
console.log ('rcr consumer %s ended', self_ctx.id);
|
|
114
|
-
shared_ctx.q.cancel ();
|
|
115
|
-
return cb ();
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// if ((shared_ctx.pop_count % 100000) == 0) console.log ('%s : consumed #%d elems', self_ctx.id, shared_ctx.pop_count);
|
|
119
|
-
reserve_and_commit_one (shared_ctx, self_ctx, cb);
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
shared_ctx.q.ko (res._id, (err) => {
|
|
124
|
-
if (err) return cb (err);
|
|
125
|
-
self_ctx.ko_count ++;
|
|
126
|
-
das_ko++;
|
|
127
|
-
|
|
128
|
-
// if ((shared_ctx.pop_count % 100000) == 0) console.log ('%s : consumed #%d elems', self_ctx.id, shared_ctx.pop_count);
|
|
129
|
-
reserve_and_commit_one (shared_ctx, self_ctx, cb);
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function run_a_rcr_consumer (shared_ctx, cb) {
|
|
136
|
-
var self_ctx = {
|
|
137
|
-
id: chance.word (),
|
|
138
|
-
pop_count: 0,
|
|
139
|
-
resv_count: 0,
|
|
140
|
-
ko_count: 0,
|
|
141
|
-
ok_count: 0
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
selfs.consumers[self_ctx.id] = self_ctx;
|
|
145
|
-
|
|
146
|
-
reserve_and_commit_one (shared_ctx, self_ctx, cb);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function run_rcr_consumers (q, cnt, cb) {
|
|
150
|
-
var shared_ctx = {
|
|
151
|
-
q: q,
|
|
152
|
-
pop_count: 0,
|
|
153
|
-
pop_max: cnt,
|
|
154
|
-
pop_opts: {
|
|
155
|
-
reserve: true
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
shareds.rcrc = shared_ctx;
|
|
160
|
-
|
|
161
|
-
var tasks = [];
|
|
162
|
-
for (var i = 0; i < num_consumers; i++)
|
|
163
|
-
tasks.push ((cb) => run_a_rcr_consumer (shared_ctx, cb));
|
|
164
|
-
|
|
165
|
-
async.parallel (tasks, cb);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
173
|
-
function produce_one (shared_ctx, self_ctx, cb) {
|
|
174
|
-
if (shared_ctx.push_count > shared_ctx.push_max) {
|
|
175
|
-
console.log ('producer %s ended', self_ctx.id);
|
|
176
|
-
return cb ();
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
shared_ctx.push_count ++;
|
|
180
|
-
self_ctx.push_count ++;
|
|
181
|
-
|
|
182
|
-
shared_ctx.q.push ({a: chance.integer (), b: chance.word (), n: shared_ctx.push_count}, function (err, res) {
|
|
183
|
-
if (err) return console.error (err);
|
|
184
|
-
// if ((shared_ctx.push_count % 100000) == 0) console.log ('%s : produced #%d elems', self_ctx.id, shared_ctx.push_count);
|
|
185
|
-
produce_one (shared_ctx, self_ctx, cb);
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function run_a_producer (shared_ctx, cb) {
|
|
190
|
-
var self_ctx = {
|
|
191
|
-
id: chance.word (),
|
|
192
|
-
push_count: 0
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
selfs.producers[self_ctx.id] = self_ctx;
|
|
196
|
-
|
|
197
|
-
produce_one (shared_ctx, self_ctx, cb);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function run_producers (q, cnt, cb) {
|
|
201
|
-
var shared_ctx = {
|
|
202
|
-
q: q,
|
|
203
|
-
push_count: 0,
|
|
204
|
-
push_max: cnt
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
shareds.prod = shared_ctx;
|
|
208
|
-
|
|
209
|
-
var tasks = [];
|
|
210
|
-
for (var i = 0; i < num_producers; i++) tasks.push ((cb) => run_a_producer (shared_ctx, cb));
|
|
211
|
-
async.parallel (tasks, cb);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
// initialize factory
|
|
218
|
-
MQ (factory_opts, function (err, factory) {
|
|
219
|
-
if (err) return console.error (err);
|
|
220
|
-
|
|
221
|
-
// factory ready, create one queue
|
|
222
|
-
var q_opts = {};
|
|
223
|
-
var q = factory.queue ('test_queue_456', q_opts);
|
|
224
|
-
|
|
225
|
-
var timer = setInterval (() => {
|
|
226
|
-
console.log ('**** state: %o', _.map (shareds, (v, k) => {return {cnt: v.push_count || v.pop_count, max: v.push_max || v.pop_max }}));
|
|
227
|
-
|
|
228
|
-
console.log ('das pop %d, ko %d, ok %d', das_pop, das_ko, das_ok);
|
|
229
|
-
|
|
230
|
-
q.status ((err ,res) => {
|
|
231
|
-
console.log ('**** status: %o', res);
|
|
232
|
-
});
|
|
233
|
-
}, 2000);
|
|
234
|
-
|
|
235
|
-
async.parallel ([
|
|
236
|
-
(cb) => run_producers (q, num_elems, cb),
|
|
237
|
-
// (cb) => run_consumers (q, 250000, cb),
|
|
238
|
-
(cb) => run_rcr_consumers (q, num_elems, cb),
|
|
239
|
-
], (err) => {
|
|
240
|
-
if (err) {
|
|
241
|
-
console.error (err);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
var tot_push = 0;
|
|
245
|
-
var tot_pop = 0;
|
|
246
|
-
var tot_resv = 0;
|
|
247
|
-
var tot_ok = 0;
|
|
248
|
-
var tot_ko = 0;
|
|
249
|
-
|
|
250
|
-
console.log ('\nProducers: ');
|
|
251
|
-
_.each (selfs.producers, (v, k) => {console.log (' %s: pushed %d', v.id, v.push_count), tot_push += v.push_count});
|
|
252
|
-
|
|
253
|
-
console.log ('\nConsumers: ');
|
|
254
|
-
_.each (selfs.consumers, (v, k) => {
|
|
255
|
-
console.log (' %s: popped %d, resvd %d, committed %d, rollbacked %d', v.id, v.pop_count, v.resv_count, v.ok_count, v.ko_count);
|
|
256
|
-
tot_pop += v.pop_count;
|
|
257
|
-
tot_resv += v.resv_count;
|
|
258
|
-
tot_ok += v.ok_count;
|
|
259
|
-
tot_ko += v.ko_count;
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
console.log (' \nTotals: %d popped, %d pushed, resvd %d, committed %d, rollbacked %d', tot_pop, tot_push, tot_resv, tot_ok, tot_ko);
|
|
263
|
-
clearInterval (timer);
|
|
264
|
-
|
|
265
|
-
q.status ((err ,res) => {
|
|
266
|
-
console.log ('**** status: %o', res);
|
|
267
|
-
q.drain (() => factory.close ());
|
|
268
|
-
});
|
|
269
|
-
});
|
|
270
|
-
});
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
*
|
|
3
|
-
* very simple example of stream-mongo: one element pushed, consumed three times
|
|
4
|
-
*
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const async = require ('async');
|
|
8
|
-
const MQ = require ('../../backends/stream-mongo');
|
|
9
|
-
|
|
10
|
-
// initialize factory
|
|
11
|
-
MQ ({
|
|
12
|
-
url: 'mongodb://localhost/keuss_test_stream'
|
|
13
|
-
}, (err, factory) => {
|
|
14
|
-
if (err) return console.error(err);
|
|
15
|
-
|
|
16
|
-
// factory ready, create one queue
|
|
17
|
-
const q0 = factory.queue ('test_stream', {groups: 'G1, G2, G4'});
|
|
18
|
-
const q1 = factory.queue ('test_stream', {group: 'G1'});
|
|
19
|
-
const q2 = factory.queue ('test_stream', {group: 'G2'});
|
|
20
|
-
|
|
21
|
-
async.series ([
|
|
22
|
-
// push element
|
|
23
|
-
cb => q0.push (
|
|
24
|
-
{elem: 1, headline: 'something something', tags: {a: 1, b: 2}}, // this is the payload
|
|
25
|
-
{
|
|
26
|
-
hdrs: {h1: 'aaa', h2: 12, h3: false} // let's add some headers too
|
|
27
|
-
},
|
|
28
|
-
cb
|
|
29
|
-
),
|
|
30
|
-
cb => setTimeout (cb, 1000), // wait a bit
|
|
31
|
-
cb => q1.pop ('consumer-1', cb), // pop element in group G1
|
|
32
|
-
cb => q2.pop ('consumer-2', cb), // pop element in group G2
|
|
33
|
-
], (err, res) => {
|
|
34
|
-
if (err) {
|
|
35
|
-
console.error (err);
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
console.log ('element popped for group G1:', res[2]);
|
|
39
|
-
console.log ('element popped for group G2:', res[3]);
|
|
40
|
-
// this should print twice something like:
|
|
41
|
-
// {
|
|
42
|
-
// _id: <some id>,
|
|
43
|
-
// mature: <some date>,
|
|
44
|
-
// payload: { elem: 1, headline: 'something something', tags: { a: 1, b: 2 } },
|
|
45
|
-
// tries: 0
|
|
46
|
-
// hdrs: {h1: 'aaa', h2: 12, h3: false}
|
|
47
|
-
// }
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
factory.close ();
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
// redis-list consumer & producer on a redislabs Redis
|
|
2
|
-
|
|
3
|
-
var MQ = require('../../backends/redis-list');
|
|
4
|
-
|
|
5
|
-
var factory_opts = {
|
|
6
|
-
redis: {
|
|
7
|
-
Redis: {
|
|
8
|
-
port: 12345,
|
|
9
|
-
host: 'redis-12345.c3.eu-west-1-2.ec2.cloud.redislabs.com',
|
|
10
|
-
family: 4,
|
|
11
|
-
password: 'xxxxxxxx',
|
|
12
|
-
db: 0
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
// initialize factory
|
|
18
|
-
MQ(factory_opts, function (err, factory) {
|
|
19
|
-
if (err) {
|
|
20
|
-
return console.error(err);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// factory ready, create one queue
|
|
24
|
-
var q_opts = {};
|
|
25
|
-
var q = factory.queue('test_queue', q_opts);
|
|
26
|
-
|
|
27
|
-
// insert element
|
|
28
|
-
q.push({ a: 1, b: '666' }, function (err, res) {
|
|
29
|
-
if (err) {
|
|
30
|
-
return console.error(err);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// element inserted at this point. pop it again
|
|
34
|
-
var pop_opts = {};
|
|
35
|
-
q.pop('consumer-one', pop_opts, function (err, res) {
|
|
36
|
-
if (err) {
|
|
37
|
-
return console.error(err);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
console.log('got this: ', res.payload);
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
});
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
// mongodb: create a consumer and a producer, use redis signaller and redis stats
|
|
2
|
-
var MQ = require ('../backends/mongo');
|
|
3
|
-
var signal_redis_pubsub = require ('../signal/redis-pubsub');
|
|
4
|
-
var stats_redis = require ('../stats/redis');
|
|
5
|
-
|
|
6
|
-
var local_redis_opts = {
|
|
7
|
-
Redis: {
|
|
8
|
-
port: 6379,
|
|
9
|
-
host: 'localhost',
|
|
10
|
-
db: 6
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
var factory_opts = {
|
|
15
|
-
url: 'mongodb://localhost/qeus',
|
|
16
|
-
signaller: {
|
|
17
|
-
provider: signal_redis_pubsub,
|
|
18
|
-
opts: local_redis_opts
|
|
19
|
-
},
|
|
20
|
-
stats: {
|
|
21
|
-
provider: stats_redis,
|
|
22
|
-
opts: local_redis_opts
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
// initialize factory
|
|
27
|
-
MQ (factory_opts, function (err, factory) {
|
|
28
|
-
if (err) {
|
|
29
|
-
return console.error (err);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// factory ready, create one queue
|
|
33
|
-
var q_opts = {};
|
|
34
|
-
var q = factory.queue ('test_queue_123', q_opts);
|
|
35
|
-
|
|
36
|
-
// insert element
|
|
37
|
-
q.push ({a:1, b:'666'}, function (err, res) {
|
|
38
|
-
if (err) {
|
|
39
|
-
return console.error (err);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// element inserted at this point. pop it again
|
|
43
|
-
var pop_opts = {};
|
|
44
|
-
q.pop ('consumer-one', pop_opts, function (err, res) {
|
|
45
|
-
if (err) {
|
|
46
|
-
return console.error (err);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
console.log ('got this: ', res.payload);
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
});
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# Keuss example app: WebHook delivery
|
|
2
|
-
|
|
3
|
-
This is a small but fully functional WebHook Delivery System using keuss as job-queue middleware. It can be certainly improved in many ways, but it is perfectly usable in its current state
|
|
4
|
-
|
|
5
|
-
## install & run
|
|
6
|
-
You need a mongodb instance running locally.
|
|
7
|
-
|
|
8
|
-
Then, run the usual `npm install` and then `node .`
|
|
9
|
-
|
|
10
|
-
## How it works
|
|
11
|
-
This system works as a store-and-forward http relay:
|
|
12
|
-
* you make HTTP calls (any method) to `http://localhost:6677/wh`. The whole HTTP request will be queued for later. You'll receive a `HTTP 201 Created` response, immediately
|
|
13
|
-
* The queued requests are extracted by means of a reserve from the queue and *executed*.
|
|
14
|
-
* If they fail with a retriable error (http 5xx, non-http errors) they are rolled back with a delay of `tries^2 * 3 + tries * 3 + 3` seconds.
|
|
15
|
-
* If they fail with a non-retriable error (http 4xx) they are committed
|
|
16
|
-
* If they succeed (http 2xx) they are committed
|
|
17
|
-
* Also, deadletter is used. If a webhook is retried over 14 times, it is moved to `__deadletter__`
|
|
18
|
-
|
|
19
|
-
In order to work, you need to pass along the destination url as `x-dest-url` header. This header is not passed along. Also, you can specify an initial delay in secons in the header `x-delay`, which is not passed along either
|
|
20
|
-
|
|
21
|
-
A set of testing urls is also provided for a self-contained testing:
|
|
22
|
-
* `/test/200`: returns a HTTP 200
|
|
23
|
-
* `/test/400`: returns a HTTP 400
|
|
24
|
-
* `/test/404`: returns a HTTP 404
|
|
25
|
-
* `/test/500`: returns a HTTP 500
|
|
26
|
-
* `/test/drop`: no response, and close the socket
|
|
27
|
-
|
|
28
|
-
Then, you can issue a POST webhook which would be retried 14 times and then moved to deadletter like this:
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
curl -X POST --data-bin @wh-payload.json -v -H 'x-dest-url: http://localhost:6677/test/500' -H 'content-type: text/plain' -H 'x-delay: 1' http://localhost:6677/wh
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
You would need to first create a file `wh-payload.json` with the webhook payload or content. Also, it will be issued with an initial delay of 1 second.
|
|
35
|
-
The provided sample in the `wh-payload.json` file is a sample content for posting a message to a Microsoft Teams channel using webhooks connector. You can find the sample and more concrete explanation of how to build your own cards for Microsoft Teams here:
|
|
36
|
-
https://docs.microsoft.com/en-us/microsoftteams/platform/task-modules-and-cards/cards/cards-reference#thumbnail-card
|
package/examples/webhooks/app.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
const express = require ('express');
|
|
2
|
-
const bodyParser = require ('body-parser');
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
module.exports = (context) => {
|
|
6
|
-
var app = express();
|
|
7
|
-
|
|
8
|
-
// parse everything as text. A more robust and generic solution shoudl use raw() and manage Buffers, though
|
|
9
|
-
app.use (bodyParser.text ({type: () => true}));
|
|
10
|
-
|
|
11
|
-
// main server entry point: anything here is queued for async delivery
|
|
12
|
-
app.all ('/wh', (req, res) => {
|
|
13
|
-
const url = req.headers['x-dest-url'];
|
|
14
|
-
let delay = 0;
|
|
15
|
-
|
|
16
|
-
// we expect a header x-dest-url to specif the webhook's url
|
|
17
|
-
if (!url) return res.status (400).send ('no x-dest-url, ignoring request');
|
|
18
|
-
|
|
19
|
-
// one can specify the initial delay, if desired
|
|
20
|
-
const delay_str = req.headers['x-delay'];
|
|
21
|
-
if (delay_str) {
|
|
22
|
-
delete req.headers['x-delay'];
|
|
23
|
-
delay = parseInt (delay_str);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// build the payload...
|
|
27
|
-
delete req.headers['x-dest-url'];
|
|
28
|
-
const pl = {
|
|
29
|
-
url: url,
|
|
30
|
-
method: req.method,
|
|
31
|
-
headers: req.headers,
|
|
32
|
-
body: req.body
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
// ...and queue it
|
|
36
|
-
context.q.push (pl, {delay: delay}, (err, id) => {
|
|
37
|
-
// error while queuing?
|
|
38
|
-
if (err) {
|
|
39
|
-
console.error ('error whipe pushing payload:', err);
|
|
40
|
-
return res.status (500).send (err);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// no errors, return a 201 Created...
|
|
44
|
-
console.log ('inserted element with id %s', id);
|
|
45
|
-
return res.status (201).send ({res: 'ok', id: id});
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// test respnses for various http response codes
|
|
51
|
-
app.all ('/test/200', (req, res) => res.status (200).send ('a 200'));
|
|
52
|
-
app.all ('/test/400', (req, res) => res.status (400).send ('a 400'));
|
|
53
|
-
app.all ('/test/404', (req, res) => res.status (404).send ('a 404'));
|
|
54
|
-
app.all ('/test/500', (req, res) => res.status (500).send ('a 500'));
|
|
55
|
-
|
|
56
|
-
// do not respond
|
|
57
|
-
app.all ('/test/noresponse', (req, res) => {});
|
|
58
|
-
|
|
59
|
-
// close socket
|
|
60
|
-
app.all ('/test/drop', (req, res) => req.socket.destroy());
|
|
61
|
-
|
|
62
|
-
// express error manager
|
|
63
|
-
app.use (function (err, req, res, next) {
|
|
64
|
-
console.error ('error caught: %s', err.stack);
|
|
65
|
-
res.status (err.status || 500).send (err.stack);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
return app;
|
|
69
|
-
};
|
|
70
|
-
|