keuss 1.6.7 → 1.6.8

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 (56) hide show
  1. package/.nyc_output/ad035de4-a3d3-451b-b2ad-402e8ed517b8.json +1 -0
  2. package/.nyc_output/{06313f3e-1553-402b-bdc2-3a7a639cd559.json → c8683d6c-e7e6-496b-ab0d-1ff730837d08.json} +0 -0
  3. package/.nyc_output/processinfo/ad035de4-a3d3-451b-b2ad-402e8ed517b8.json +1 -0
  4. package/.nyc_output/processinfo/c8683d6c-e7e6-496b-ab0d-1ff730837d08.json +1 -0
  5. package/.nyc_output/processinfo/index.json +1 -1
  6. package/Pipeline/Queue.js +23 -0
  7. package/TODO +0 -6
  8. package/backends/bucket-mongo-safe.js +38 -2
  9. package/backends/mongo.js +2 -1
  10. package/backends/pl-mongo.js +2 -1
  11. package/backends/ps-mongo.js +30 -1
  12. package/backends/redis-oq.js +12 -1
  13. package/coverage/index.html +43 -43
  14. package/coverage/keuss/Pipeline/BaseLink.js.html +18 -18
  15. package/coverage/keuss/Pipeline/Builder.js.html +1 -1
  16. package/coverage/keuss/Pipeline/ChoiceLink.js.html +1 -1
  17. package/coverage/keuss/Pipeline/DirectLink.js.html +1 -1
  18. package/coverage/keuss/Pipeline/Pipeline.js.html +15 -15
  19. package/coverage/keuss/Pipeline/Queue.js.html +124 -55
  20. package/coverage/keuss/Pipeline/Sink.js.html +1 -1
  21. package/coverage/keuss/Pipeline/index.html +18 -18
  22. package/coverage/keuss/QFactory-MongoDB-defaults.js.html +6 -6
  23. package/coverage/keuss/QFactory.js.html +28 -28
  24. package/coverage/keuss/Queue.js.html +232 -181
  25. package/coverage/keuss/Signal.js.html +28 -28
  26. package/coverage/keuss/Stats.js.html +4 -4
  27. package/coverage/keuss/backends/bucket-mongo-safe.js.html +476 -314
  28. package/coverage/keuss/backends/bucket-mongo.js.html +134 -86
  29. package/coverage/keuss/backends/index.html +69 -69
  30. package/coverage/keuss/backends/mongo.js.html +137 -74
  31. package/coverage/keuss/backends/pl-mongo.js.html +54 -54
  32. package/coverage/keuss/backends/ps-mongo.js.html +164 -80
  33. package/coverage/keuss/backends/redis-list.js.html +39 -36
  34. package/coverage/keuss/backends/redis-oq.js.html +27 -27
  35. package/coverage/keuss/index.html +18 -18
  36. package/coverage/keuss/signal/index.html +1 -1
  37. package/coverage/keuss/signal/local.js.html +17 -17
  38. package/coverage/keuss/signal/mongo-capped.js.html +1 -1
  39. package/coverage/keuss/signal/redis-pubsub.js.html +12 -12
  40. package/coverage/keuss/stats/index.html +10 -10
  41. package/coverage/keuss/stats/mem.js.html +36 -30
  42. package/coverage/keuss/stats/mongo.js.html +8 -8
  43. package/coverage/keuss/stats/redis.js.html +17 -17
  44. package/coverage/keuss/utils/RedisConn.js.html +1 -1
  45. package/coverage/keuss/utils/RedisOrderedQueue.js.html +36 -33
  46. package/coverage/keuss/utils/index.html +5 -5
  47. package/docusaurus/docs/api/queue.md +14 -0
  48. package/docusaurus/docs/changelog.md +2 -0
  49. package/docusaurus/docs/concepts.md +10 -9
  50. package/docusaurus/package.json +3 -3
  51. package/package.json +1 -1
  52. package/test/backends_remove.js +299 -0
  53. package/utils/RedisOrderedQueue.js +46 -3
  54. package/.nyc_output/a06aa990-295d-4428-872d-ba9fa06afd1f.json +0 -1
  55. package/.nyc_output/processinfo/06313f3e-1553-402b-bdc2-3a7a639cd559.json +0 -1
  56. package/.nyc_output/processinfo/a06aa990-295d-4428-872d-ba9fa06afd1f.json +0 -1
@@ -0,0 +1,299 @@
1
+ var async = require ('async');
2
+ var should = require ('should');
3
+ var _ = require ('lodash');
4
+
5
+ var LocalSignal = require ('../signal/local');
6
+ var MemStats = require ('../stats/mem');
7
+
8
+ const MongoClient = require ('mongodb').MongoClient;
9
+ const Redis = require("ioredis");
10
+
11
+ function stats (q, cb) {
12
+ async.series ({
13
+ stats: cb => q.stats(cb),
14
+ tsize: cb => q.totalSize(cb),
15
+ rsize: cb => q.resvSize(cb),
16
+ }, (err, res) => {
17
+ // console.log ('stats:', res);
18
+ cb (err, res);
19
+ });
20
+ }
21
+
22
+ function pop (q, stage, cb) {
23
+ q.pop('c1', { reserve: true }, (err, res) => {
24
+ stage.obj = res;
25
+ // console.log('reserved element %o', res);
26
+ cb(err);
27
+ });
28
+ }
29
+
30
+ function reject (q, stage, cb) {
31
+ var next_t = new Date().getTime() + 2000;
32
+
33
+ q.ko (stage.obj, next_t, (err, res) => {
34
+ if (err) {
35
+ // console.error ('error in rollback of %s: %j', stage.obj._id, err);
36
+ return cb (err);
37
+ }
38
+
39
+ // console.log('rolled back element %s: %o', stage.obj._id, res);
40
+ cb();
41
+ });
42
+ }
43
+
44
+ function accept (q, stage, cb) {
45
+ q.ok (stage.obj, (err, res) => {
46
+ if (err) {
47
+ // console.error ('error in rollback of %s: %j', stage.obj._id, err);
48
+ return cb (err);
49
+ }
50
+
51
+ // console.log('commited element %s: %j', stage.obj._id, res);
52
+ cb();
53
+ });
54
+ }
55
+
56
+ function get_mq_factory (MQ, opts, cb) {
57
+ const common_opts = {
58
+ url: 'mongodb://localhost/keuss_test_backends_remove',
59
+ signaller: { provider: LocalSignal},
60
+ stats: {provider: MemStats},
61
+ deadletter: {
62
+ }
63
+ };
64
+
65
+ // initialize factory
66
+ MQ (_.merge ({}, common_opts, opts), cb);
67
+ }
68
+
69
+ function release_mq_factory (q, factory, cb) {
70
+ // console.log ('releasing mq factory');
71
+
72
+ setTimeout (() => {
73
+ q.cancel ();
74
+ factory.close (cb);
75
+ }, 1000);
76
+ }
77
+
78
+
79
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
80
+ [
81
+ {label: 'Simple MongoDB', mq: require ('../backends/mongo')},
82
+ {label: 'Pipelined MongoDB', mq: require ('../backends/pl-mongo')},
83
+ {label: 'Tape MongoDB', mq: require ('../backends/ps-mongo')},
84
+ {label: 'Redis OrderedQueue', mq: require ('../backends/redis-oq')},
85
+ {label: 'MongoDB SafeBucket', mq: require ('../backends/bucket-mongo-safe')}
86
+ ].forEach(function (MQ_item) {
87
+ var is_redis = (MQ_item.label == 'Redis OrderedQueue');
88
+
89
+ describe('remove operations on ' + MQ_item.label + ' queue backend', () => {
90
+ const MQ = MQ_item.mq;
91
+
92
+ beforeEach (done => {
93
+ done();
94
+ });
95
+
96
+ afterEach (done => async.series ([
97
+ cb => setTimeout (cb, 1000),
98
+ cb => MongoClient.connect ('mongodb://localhost/keuss_test_backends_remove', (err, cl) => {
99
+ if (err) return done (err);
100
+ cl.db().dropDatabase (() => cl.close (cb))
101
+ }),
102
+ cb => {
103
+ const redis = new Redis();
104
+ redis.keys ('*', (err, keys) => {
105
+ const tasks = [];
106
+ _.each (keys, k => tasks.push (cb => redis.del (k, cb)));
107
+ async.series (tasks, (err, res) => {
108
+ redis.disconnect();
109
+ cb (err, res);
110
+ });
111
+ });
112
+ }
113
+ ], done));
114
+
115
+
116
+ it('fails on invalid id', done => {
117
+ // skip if redis
118
+ if (is_redis) return done();
119
+
120
+ async.waterfall ([
121
+ cb => get_mq_factory (MQ, {}, cb),
122
+ (factory, cb) => {
123
+ const q = factory.queue('test_queue_remove', {});
124
+ q.remove ('invalid-id', err => cb (null, err, q, factory))
125
+ },
126
+ (err, q, factory, cb) => {
127
+ err.should.match (/id \[invalid-id\] can not be used as remove id/);
128
+ release_mq_factory (q, factory, cb);
129
+ }
130
+ ], done);
131
+ });
132
+
133
+
134
+ it('fails on nonexistent id', done => {
135
+ async.waterfall ([
136
+ cb => get_mq_factory (MQ, {}, cb),
137
+ (factory, cb) => {
138
+ const q = factory.queue('test_queue_remove', {});
139
+ q.remove ('00112233445566778899aabb', (err, res) => cb (null, err, res, q, factory))
140
+ },
141
+ (err, res, q, factory, cb) => {
142
+ should (err).be.null();
143
+ res.should.be.false();
144
+ release_mq_factory (q, factory, cb);
145
+ }
146
+ ], done);
147
+ });
148
+
149
+
150
+ it('deletes regular element ok', done => {
151
+ const ctx = {};
152
+ async.waterfall ([
153
+ cb => get_mq_factory (MQ, {}, cb),
154
+ (factory, cb) => {
155
+ const q = factory.queue('test_queue_remove', {});
156
+ cb (null, q, factory);
157
+ },
158
+ (q, factory, cb) => async.series ([
159
+ cb => q.push ({a: 1, b: 'oo'}, cb),
160
+ cb => setTimeout (cb, 1000),
161
+ cb => stats (q, cb)
162
+ ], (err, res) => {
163
+ ctx.id = res[0];
164
+ ctx.id.should.not.be.null();
165
+ res[2].should.eql ({
166
+ stats: { get: 0, put: 1, reserve: 0, commit: 0, rollback: 0 },
167
+ tsize: 1,
168
+ rsize: is_redis ? null : 0
169
+ })
170
+ cb (err, q, factory);
171
+ }),
172
+ (q, factory, cb) => {
173
+ q.remove (ctx.id, (err, res) => {
174
+ should (err).be.null();
175
+ res.should.be.true();
176
+ cb (err, q, factory);
177
+ });
178
+ },
179
+ (q, factory, cb) => async.series ([
180
+ cb => stats (q, cb),
181
+ cb => setTimeout (cb, 1000),
182
+ ], (err, res) => {
183
+ res[0].should.eql ({
184
+ stats: { get: 0, put: 1, reserve: 0, commit: 0, rollback: 0 },
185
+ tsize: 0,
186
+ rsize: is_redis ? null : 0
187
+ });
188
+ cb (err, q, factory);
189
+ }),
190
+ (q, factory, cb) => {
191
+ release_mq_factory (q, factory, cb);
192
+ }
193
+ ], done);
194
+ });
195
+
196
+
197
+ it('does not delete reserved element', done => {
198
+ const ctx = {};
199
+ async.waterfall ([
200
+ cb => get_mq_factory (MQ, {}, cb),
201
+ (factory, cb) => {
202
+ const q = factory.queue('test_queue_remove', {});
203
+ cb (null, q, factory);
204
+ },
205
+ (q, factory, cb) => async.series ([
206
+ cb => q.push ({a: 1, b: 'oo'}, cb),
207
+ cb => setTimeout (cb, 1000),
208
+ ], (err, res) => {
209
+ ctx.id = res[0];
210
+ ctx.id.should.not.be.null();
211
+ cb (err, q, factory);
212
+ }),
213
+ (q, factory, cb) => {
214
+ q.pop('c1', { reserve: true }, (err, res) => {
215
+ // res._id.should.eql (ctx.id);
216
+ cb (err, q, factory);
217
+ });
218
+ },
219
+ (q, factory, cb) => {
220
+ q.remove (ctx.id, (err, res) => {
221
+ should (err).be.null();
222
+ res.should.be.false();
223
+ cb (err, q, factory);
224
+ });
225
+ },
226
+ (q, factory, cb) => async.series ([
227
+ cb => stats (q, cb),
228
+ cb => setTimeout (cb, 1000),
229
+ ], (err, res) => {
230
+ res[0].should.eql ({
231
+ stats: { get: 0, put: 1, reserve: 1, commit: 0, rollback: 0 },
232
+ tsize: 1,
233
+ rsize: is_redis ? null : 1
234
+ });
235
+ cb (err, q, factory);
236
+ }),
237
+ (q, factory, cb) => {
238
+ release_mq_factory (q, factory, cb);
239
+ }
240
+ ], done);
241
+ });
242
+
243
+
244
+ it('does delete reserved+rolledback element', done => {
245
+ const ctx = {};
246
+ async.waterfall ([
247
+ cb => get_mq_factory (MQ, {}, cb),
248
+ (factory, cb) => {
249
+ const q = factory.queue('test_queue_remove', {});
250
+ cb (null, q, factory);
251
+ },
252
+ (q, factory, cb) => async.series ([
253
+ cb => q.push ({a: 1, b: 'oo'}, cb),
254
+ cb => setTimeout (cb, 1000),
255
+ ], (err, res) => {
256
+ ctx.id = res[0];
257
+ ctx.id.should.not.be.null();
258
+ cb (err, q, factory);
259
+ }),
260
+ (q, factory, cb) => {
261
+ q.pop('c1', { reserve: true }, (err, res) => {
262
+ res._id.should.eql (ctx.id);
263
+ cb (err, q, factory);
264
+ });
265
+ },
266
+ (q, factory, cb) => async.series ([
267
+ cb => q.ko(ctx.id, new Date().getTime() + 2000, cb),
268
+ cb => setTimeout (cb, 1000),
269
+ ], (err, res) => {
270
+ res[0].should.be.true();
271
+ cb (err, q, factory);
272
+ }),
273
+ (q, factory, cb) => {
274
+ q.remove (ctx.id, (err, res) => {
275
+ should (err).be.null();
276
+ res.should.be.true();
277
+ cb (err, q, factory);
278
+ });
279
+ },
280
+ (q, factory, cb) => async.series ([
281
+ cb => stats (q, cb),
282
+ cb => setTimeout (cb, 1000),
283
+ ], (err, res) => {
284
+ res[0].should.eql ({
285
+ stats: { get: 0, put: 1, reserve: 1, commit: 0, rollback: 1 },
286
+ tsize: 0,
287
+ rsize: is_redis ? null : 0
288
+ });
289
+ cb (err, q, factory);
290
+ }),
291
+ (q, factory, cb) => {
292
+ release_mq_factory (q, factory, cb);
293
+ }
294
+ ], done);
295
+ });
296
+
297
+
298
+ });
299
+ });
@@ -11,7 +11,8 @@ const _s_lua_code_push = `
11
11
  redis.call ('HSET', 'keuss:q:ordered_queue:hash:' .. KEYS[1], ARGV[1], ARGV[3])
12
12
 
13
13
  -- insert id+mature in index
14
- return redis.call ('ZADD', 'keuss:q:ordered_queue:index:' .. KEYS[1], ARGV[2], ARGV[1])
14
+ redis.call ('ZADD', 'keuss:q:ordered_queue:index:' .. KEYS[1], ARGV[2], ARGV[1])
15
+ return ARGV[1]
15
16
  `;
16
17
 
17
18
  const _s_lua_code_pop = `
@@ -86,7 +87,7 @@ const _s_lua_code_commit = `
86
87
  local id = ARGV[1]
87
88
  local val = redis.call ('HGET', 'keuss:q:ordered_queue:hash:' .. KEYS[1], id)
88
89
 
89
- if (val == nil) then
90
+ if (not(val)) then
90
91
  return nil
91
92
  end
92
93
 
@@ -113,7 +114,7 @@ const _s_lua_code_rollback = `
113
114
  local id = ARGV[1]
114
115
  local val = redis.call ('HGET', 'keuss:q:ordered_queue:hash:' .. KEYS[1], id)
115
116
 
116
- if (val==false) then
117
+ if (not(val)) then
117
118
  return nil
118
119
  end
119
120
 
@@ -135,6 +136,31 @@ const _s_lua_code_rollback = `
135
136
  return id
136
137
  `;
137
138
 
139
+ const _s_lua_code_remove = `
140
+ -- qname in KEYS[1]
141
+ -- id in ARGV[1]
142
+
143
+ local id = ARGV[1]
144
+ local val = redis.call ('HGET', 'keuss:q:ordered_queue:hash:' .. KEYS[1], id)
145
+
146
+ if (not (val)) then
147
+ return nil
148
+ end
149
+
150
+ -- check if it was reserved
151
+ local obj_val = cjson.decode (val)
152
+
153
+ if (obj_val.reserved) then
154
+ -- it is reserved
155
+ return nil
156
+ end
157
+
158
+ -- delete from index, hash
159
+ redis.call ('ZREM', 'keuss:q:ordered_queue:index:' .. KEYS[1], id)
160
+ redis.call ('HDEL', 'keuss:q:ordered_queue:hash:' .. KEYS[1], id)
161
+
162
+ return id
163
+ `;
138
164
 
139
165
 
140
166
  class RedisOrderedQueue {
@@ -164,6 +190,7 @@ class RedisOrderedQueue {
164
190
  this._rediscl.roq_push (this._name, pl._id, pl.mature, JSON.stringify (pl), done);
165
191
  }
166
192
 
193
+
167
194
  //////////////////////////////////
168
195
  pop (done) {
169
196
  //////////////////////////////////
@@ -184,6 +211,7 @@ class RedisOrderedQueue {
184
211
  });
185
212
  }
186
213
 
214
+
187
215
  //////////////////////////////////
188
216
  reserve (incr, done) {
189
217
  //////////////////////////////////
@@ -204,18 +232,21 @@ class RedisOrderedQueue {
204
232
  });
205
233
  }
206
234
 
235
+
207
236
  //////////////////////////////////
208
237
  commit (id, done) {
209
238
  //////////////////////////////////
210
239
  this._rediscl.roq_commit (this._name, id, done);
211
240
  }
212
241
 
242
+
213
243
  //////////////////////////////////
214
244
  rollback (id, next_t, done) {
215
245
  //////////////////////////////////
216
246
  this._rediscl.roq_rollback (this._name, id, next_t || (new Date().getTime ()), done);
217
247
  }
218
248
 
249
+
219
250
  //////////////////////////////////
220
251
  // queue size including non-mature elements
221
252
  totalSize (callback) {
@@ -223,6 +254,7 @@ class RedisOrderedQueue {
223
254
  this._rediscl.zcard ('keuss:q:ordered_queue:index:' + this._name, callback);
224
255
  }
225
256
 
257
+
226
258
  //////////////////////////////////
227
259
  // queue size NOT including non-mature elements
228
260
  size (callback) {
@@ -230,6 +262,7 @@ class RedisOrderedQueue {
230
262
  this._rediscl.zcount ('keuss:q:ordered_queue:index:' + this._name, '-inf', new Date().getTime(), callback);
231
263
  }
232
264
 
265
+
233
266
  //////////////////////////////////
234
267
  // queue size of non-mature elements only
235
268
  schedSize (callback) {
@@ -237,12 +270,20 @@ class RedisOrderedQueue {
237
270
  this._rediscl.zcount ('keuss:q:ordered_queue:index:' + this._name, new Date().getTime(), '+inf', callback);
238
271
  }
239
272
 
273
+
240
274
  //////////////////////////////////
241
275
  // get first
242
276
  peek (callback) {
243
277
  //////////////////////////////////
244
278
  this._rediscl.zrange ('keuss:q:ordered_queue:index:' + this._name, 0, 0, 'WITHSCORES', callback);
245
279
  }
280
+
281
+
282
+ //////////////////////////////////
283
+ remove (id, done) {
284
+ //////////////////////////////////
285
+ this._rediscl.roq_remove (this._name, id, done);
286
+ }
246
287
  }
247
288
 
248
289
 
@@ -255,8 +296,10 @@ class Factory {
255
296
  this._rediscl.defineCommand('roq_reserve', {numberOfKeys: 1, lua: _s_lua_code_reserve});
256
297
  this._rediscl.defineCommand('roq_commit', {numberOfKeys: 1, lua: _s_lua_code_commit});
257
298
  this._rediscl.defineCommand('roq_rollback', {numberOfKeys: 1, lua: _s_lua_code_rollback});
299
+ this._rediscl.defineCommand('roq_remove', {numberOfKeys: 1, lua: _s_lua_code_remove});
258
300
  }
259
301
 
302
+
260
303
  roq (name) {
261
304
  return new RedisOrderedQueue (name, this);
262
305
  }