keuss 1.6.15 → 1.7.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/Queue.js +26 -0
- package/backends/ps-mongo.js +20 -5
- package/backends/stream-mongo.js +476 -0
- package/examples/snippets/07-stream-simple.js +53 -0
- package/package.json +1 -1
- package/stats/mem.js +5 -8
- package/stats/redis.js +16 -2
- package/test/backends_deadletter.js +5 -4
- package/test/backends_payload.js +2 -1
- package/test/backends_reserve-commit-rollback.js +16 -15
- package/test/pause.js +5 -5
- package/test/signal.js +35 -0
- package/test/stats.js +44 -3
- package/test/stream-mongo.js +166 -0
- package/backends/bucket-mongo.js +0 -366
- package/test/backends_bucket-at-most-once.js +0 -151
package/backends/bucket-mongo.js
DELETED
|
@@ -1,366 +0,0 @@
|
|
|
1
|
-
var async = require ('async');
|
|
2
|
-
var _ = require ('lodash');
|
|
3
|
-
var AsyncLock = require ('async-lock');
|
|
4
|
-
|
|
5
|
-
var debug = require('debug')('keuss:backend:BucketMongo');
|
|
6
|
-
|
|
7
|
-
var MongoClient = require ('mongodb').MongoClient;
|
|
8
|
-
var mongo = require ('mongodb');
|
|
9
|
-
|
|
10
|
-
var Queue = require ('../Queue');
|
|
11
|
-
var QFactory_MongoDB_defaults = require ('../QFactory-MongoDB-defaults');
|
|
12
|
-
|
|
13
|
-
class BucketMongoQueue extends Queue {
|
|
14
|
-
|
|
15
|
-
//////////////////////////////////////////////
|
|
16
|
-
constructor (name, factory, opts, orig_opts) {
|
|
17
|
-
//////////////////////////////////////////////
|
|
18
|
-
super (name, factory, opts, orig_opts);
|
|
19
|
-
|
|
20
|
-
this._factory = factory;
|
|
21
|
-
this._col = factory._db.collection (name);
|
|
22
|
-
|
|
23
|
-
this._insert_bucket = {
|
|
24
|
-
_id: new mongo.ObjectID (),
|
|
25
|
-
b: []
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
this._read_bucket = {
|
|
29
|
-
b: []
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
this._bucket_max_size = opts.bucket_max_size || 1024;
|
|
33
|
-
this._bucket_max_wait = opts.bucket_max_wait || 500;
|
|
34
|
-
|
|
35
|
-
this._lock = new AsyncLock ();
|
|
36
|
-
|
|
37
|
-
debug ('created BucketMongoSafe %s', name);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
/////////////////////////////////////////
|
|
42
|
-
static Type () {
|
|
43
|
-
/////////////////////////////////////////
|
|
44
|
-
return 'mongo:bucket';
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/////////////////////////////////////////
|
|
48
|
-
type () {
|
|
49
|
-
/////////////////////////////////////////
|
|
50
|
-
return 'mongo:bucket';
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/////////////////////////////////////////
|
|
54
|
-
// add element to queue
|
|
55
|
-
insert (entry, callback) {
|
|
56
|
-
if (this._insert_bucket.b.length == 0) this._insert_bucket.mature = entry.mature;
|
|
57
|
-
|
|
58
|
-
this._insert_bucket.b.push ({
|
|
59
|
-
__p: entry.payload,
|
|
60
|
-
__h: (entry.hdrs || {})
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
var id = this._insert_bucket._id.toString () + '--' + this._insert_bucket.b.length;
|
|
64
|
-
debug ('added to bucket, %s', id);
|
|
65
|
-
|
|
66
|
-
if (this._insert_bucket.b.length >= this._bucket_max_size) {
|
|
67
|
-
if (this._flush_timer) clearTimeout (this._flush_timer);
|
|
68
|
-
this._flush_timer = null;
|
|
69
|
-
|
|
70
|
-
debug ('cancelled periodic_flush');
|
|
71
|
-
|
|
72
|
-
this._flush_bucket (callback);
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
if (this._insert_bucket.b.length == 1) {
|
|
76
|
-
debug ('first insert of bucket, set periodic_flush');
|
|
77
|
-
this._set_periodic_flush ();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
setImmediate (() => callback (null, id));
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
/////////////////////////////////////////
|
|
86
|
-
// get element from queue
|
|
87
|
-
get (callback) {
|
|
88
|
-
if (this._in_drain) {
|
|
89
|
-
if (this._read_bucket.b.length == 0) {
|
|
90
|
-
debug ('in_drain_read: read_buffer empty, calling _drain_read_cb');
|
|
91
|
-
this._drain_read_cb ();
|
|
92
|
-
this._drain_read_cb = undefined;
|
|
93
|
-
return setImmediate (() => callback (null, null));
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
debug ('in_drain_read: %d pending in read_buffer', this._read_bucket.b.length);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
debug ('_ensure_bucket: acquire lock');
|
|
101
|
-
|
|
102
|
-
this._lock.acquire ('ensure-bucket', done => {
|
|
103
|
-
debug ('_ensure_bucket: lock acquired');
|
|
104
|
-
|
|
105
|
-
if (this._read_bucket.b.length) {
|
|
106
|
-
debug ('_ensure_bucket: end (already present)');
|
|
107
|
-
return done ();
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
this._get_bucket ((err, res) => {
|
|
111
|
-
if (err) {
|
|
112
|
-
debug ('_ensure_bucket: end (error) %o', err);
|
|
113
|
-
return done (err);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (!res) {
|
|
117
|
-
debug ('_ensure_bucket: end (no bucket)');
|
|
118
|
-
this._read_bucket = {b: []};
|
|
119
|
-
return done ();
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
debug ('_ensure_bucket: end (bucket read)');
|
|
123
|
-
this._read_bucket = res;
|
|
124
|
-
done (null, res);
|
|
125
|
-
});
|
|
126
|
-
}, (err, ret) => {
|
|
127
|
-
debug ('BucketSet:_ensure_bucket: lock released');
|
|
128
|
-
if (err) return callback (err);
|
|
129
|
-
|
|
130
|
-
if (this._read_bucket.b.length) {
|
|
131
|
-
var pl = this._read_bucket.b.shift ();
|
|
132
|
-
var elem = {};
|
|
133
|
-
|
|
134
|
-
if (pl.__p) {
|
|
135
|
-
// add-headers: array contains both payload and headers, breaks backwards compat
|
|
136
|
-
elem.payload = pl.__p;
|
|
137
|
-
elem.hdrs = pl.__h;
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
// backwards compat, pre-headers: array contains whole payloads
|
|
141
|
-
elem.payload = pl;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (elem.payload._bsontype == 'Binary') elem.payload = elem.payload.buffer;
|
|
145
|
-
elem.tries = 0;
|
|
146
|
-
elem.mature = this._read_bucket.mature;
|
|
147
|
-
setImmediate (() => callback (null, elem));
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
setImmediate (callback);
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
/////////////////////////////////////////
|
|
157
|
-
_drain_read (cb) {
|
|
158
|
-
if (this._read_bucket.b.length == 0) {
|
|
159
|
-
debug ('no read_buffer, drain_read done');
|
|
160
|
-
cb ();
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
debug ('drain_read: %d pending in bucket, %d consumers. Setting cb for later', this._read_bucket.b.length, this.nConsumers ());
|
|
164
|
-
this._drain_read_cb = cb;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
/////////////////////////////////////////
|
|
170
|
-
_drain_insert (cb) {
|
|
171
|
-
debug ('drain_insert called');
|
|
172
|
-
|
|
173
|
-
if (this._insert_bucket.b.length) {
|
|
174
|
-
if (this._flush_timer) clearTimeout (this._flush_timer);
|
|
175
|
-
this._flush_timer = null;
|
|
176
|
-
|
|
177
|
-
debug ('drain_insert flushing _insert_bucket');
|
|
178
|
-
|
|
179
|
-
this._flush_bucket (cb);
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
debug ('drain_insert: nothing pending insertion, completed');
|
|
183
|
-
cb ();
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/////////////////////////////////////////
|
|
188
|
-
// empty local buffers
|
|
189
|
-
drain (callback) {
|
|
190
|
-
async.series ([
|
|
191
|
-
cb => {this._in_drain = true; cb ();},
|
|
192
|
-
cb => async.parallel ([
|
|
193
|
-
cb => this._drain_read (cb),
|
|
194
|
-
cb => this._drain_insert (cb),
|
|
195
|
-
], cb),
|
|
196
|
-
cb => {debug ('drain stages completed'), cb ()},
|
|
197
|
-
cb => {this._in_drain = false; this._drained = true; cb ()},
|
|
198
|
-
cb => {this.cancel (); cb ()},
|
|
199
|
-
cb => {debug ('drain completed'), cb ()}
|
|
200
|
-
], callback);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
//////////////////////////////////
|
|
205
|
-
// queue size including non-mature elements
|
|
206
|
-
totalSize (callback) {
|
|
207
|
-
//////////////////////////////////
|
|
208
|
-
const cursor = this._col.aggregate ([
|
|
209
|
-
{$group:{_id:'t', v: {$sum: '$n'}}}
|
|
210
|
-
]);
|
|
211
|
-
|
|
212
|
-
cursor.toArray ((err, res) => {
|
|
213
|
-
if (err) return callback (err);
|
|
214
|
-
if (res.length == 0) return callback (null, 0);
|
|
215
|
-
callback (null, res[0].v);
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
//////////////////////////////////
|
|
221
|
-
// queue size NOT including non-mature elements
|
|
222
|
-
size (callback) {
|
|
223
|
-
//////////////////////////////////
|
|
224
|
-
this.totalSize (callback);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
/////////////////////////////////////////
|
|
229
|
-
_set_periodic_flush () {
|
|
230
|
-
/////////////////////////////////////////
|
|
231
|
-
if (this._flush_timer) return;
|
|
232
|
-
|
|
233
|
-
this._flush_timer = setTimeout (() => {
|
|
234
|
-
this._flush_timer = null;
|
|
235
|
-
|
|
236
|
-
debug ('flush_timer went off');
|
|
237
|
-
|
|
238
|
-
if (this._insert_bucket.b.length) {
|
|
239
|
-
this._flush_bucket ((err, res) => {
|
|
240
|
-
if (err) {
|
|
241
|
-
// keep retrying
|
|
242
|
-
this._set_periodic_flush ();
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
else {
|
|
247
|
-
// nothing to insert, stop
|
|
248
|
-
}
|
|
249
|
-
}, this._bucket_max_wait);
|
|
250
|
-
|
|
251
|
-
debug ('_set_periodic_flush set, wait %d msecs', this._bucket_max_wait);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
/////////////////////////////////////////
|
|
256
|
-
_flush_bucket (callback) {
|
|
257
|
-
/////////////////////////////////////////
|
|
258
|
-
var bucket = this._insert_bucket;
|
|
259
|
-
bucket.n = bucket.b.length;
|
|
260
|
-
|
|
261
|
-
this._insert_bucket = {
|
|
262
|
-
_id: new mongo.ObjectID (),
|
|
263
|
-
b: []
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
debug ('flushing bucket %s with %d elems', bucket._id.toString(), bucket.b.length);
|
|
267
|
-
|
|
268
|
-
this._col.insertOne (bucket, {}, (err, result) => {
|
|
269
|
-
if (err) return callback (err);
|
|
270
|
-
this._signal_insertion_own (bucket.mature);
|
|
271
|
-
|
|
272
|
-
callback (null, bucket);
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
/////////////////////////////////////////
|
|
278
|
-
// get element from queue
|
|
279
|
-
_get_bucket (callback) {
|
|
280
|
-
/////////////////////////////////////////
|
|
281
|
-
debug ('need to read a bucket');
|
|
282
|
-
|
|
283
|
-
this._col.findOneAndDelete ({}, {sort: {_id : 1}}, (err, result) => {
|
|
284
|
-
if (err) return callback (err);
|
|
285
|
-
|
|
286
|
-
var val = result && result.value;
|
|
287
|
-
|
|
288
|
-
if (val) {
|
|
289
|
-
debug ('read a bucket %s with %d elems', val._id.toString(), val.n);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
callback (null, val);
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
////////////////////////////////////////
|
|
298
|
-
// redefine signalling of insertion:
|
|
299
|
-
//
|
|
300
|
-
// inhibit inherited one
|
|
301
|
-
_signal_insertion (t) {
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// and define own one
|
|
305
|
-
_signal_insertion_own (t) {
|
|
306
|
-
this._signaller.signalInsertion (t);
|
|
307
|
-
}
|
|
308
|
-
};
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
class Factory extends QFactory_MongoDB_defaults {
|
|
312
|
-
constructor (opts, mongo_conn) {
|
|
313
|
-
super (opts);
|
|
314
|
-
this._mongo_conn = mongo_conn;
|
|
315
|
-
this._db = mongo_conn.db();
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
queue (name, opts) {
|
|
319
|
-
var full_opts = {}
|
|
320
|
-
_.merge(full_opts, this._opts, opts);
|
|
321
|
-
return new BucketMongoQueue (name, this, full_opts, opts);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
close (cb) {
|
|
325
|
-
super.close (() => {
|
|
326
|
-
if (this._mongo_conn) {
|
|
327
|
-
this._mongo_conn.close ();
|
|
328
|
-
this._mongo_conn = null;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
if (cb) return cb ();
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
type () {
|
|
336
|
-
return BucketMongoQueue.Type ();
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
capabilities () {
|
|
340
|
-
return {
|
|
341
|
-
sched: false,
|
|
342
|
-
reserve: false,
|
|
343
|
-
pipeline: false,
|
|
344
|
-
tape: false,
|
|
345
|
-
remove: true
|
|
346
|
-
};
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
function creator (opts, cb) {
|
|
351
|
-
var _opts = opts || {};
|
|
352
|
-
var m_url = _opts.url || 'mongodb://localhost:27017/keuss';
|
|
353
|
-
|
|
354
|
-
MongoClient.connect (m_url, { useNewUrlParser: true }, (err, cl) => {
|
|
355
|
-
if (err) return cb (err);
|
|
356
|
-
var F = new Factory (_opts, cl);
|
|
357
|
-
F.async_init (err => cb (null, F));
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
module.exports = creator;
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
var async = require ('async');
|
|
3
|
-
var should = require ('should');
|
|
4
|
-
|
|
5
|
-
var LocalSignal = require ('../signal/local');
|
|
6
|
-
var MemStats = require ('../stats/mem');
|
|
7
|
-
|
|
8
|
-
const MongoClient = require ('mongodb').MongoClient;
|
|
9
|
-
|
|
10
|
-
var factory = null;
|
|
11
|
-
|
|
12
|
-
[
|
|
13
|
-
{label: 'MongoDB Bucket', mq: require ('../backends/bucket-mongo')}
|
|
14
|
-
].forEach (function (MQ_item) {
|
|
15
|
-
|
|
16
|
-
describe ('bucket-at-most-once with ' + MQ_item.label + ' queue backend', function () {
|
|
17
|
-
var MQ = MQ_item.mq;
|
|
18
|
-
|
|
19
|
-
before (function (done) {
|
|
20
|
-
var opts = {
|
|
21
|
-
url: 'mongodb://localhost/keuss_test_bucket_at_most_once',
|
|
22
|
-
signaller: { provider: LocalSignal},
|
|
23
|
-
stats: {provider: MemStats}
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
MQ (opts, function (err, fct) {
|
|
27
|
-
if (err) return done (err);
|
|
28
|
-
factory = fct;
|
|
29
|
-
done();
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
after (done => async.series ([
|
|
35
|
-
cb => setTimeout (cb, 1000),
|
|
36
|
-
cb => factory.close (cb),
|
|
37
|
-
cb => MongoClient.connect ('mongodb://localhost/keuss_test_bucket_at_most_once', (err, cl) => {
|
|
38
|
-
if (err) return done (err);
|
|
39
|
-
cl.db().dropDatabase (() => cl.close (cb))
|
|
40
|
-
})
|
|
41
|
-
], done));
|
|
42
|
-
|
|
43
|
-
it ('queue is created empty and ok', function (done){
|
|
44
|
-
var q = factory.queue('test_queue');
|
|
45
|
-
should.equal (q.nextMatureDate (), null);
|
|
46
|
-
q.name ().should.equal ('test_queue');
|
|
47
|
-
|
|
48
|
-
async.series([
|
|
49
|
-
function (cb) {q.stats(cb)},
|
|
50
|
-
function (cb) {q.size (cb)},
|
|
51
|
-
function (cb) {q.totalSize (cb)},
|
|
52
|
-
function (cb) {q.next_t (cb)},
|
|
53
|
-
], function(err, results) {
|
|
54
|
-
results.should.eql ([{get: 0, put: 0}, 0, 0, null])
|
|
55
|
-
done();
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
it ('sequential push & pops, go as expected', function (done){
|
|
61
|
-
var q = factory.queue('test_queue');
|
|
62
|
-
|
|
63
|
-
async.series([
|
|
64
|
-
function (cb) {q.push ({elem:1, pl:'twetrwte'}, cb)},
|
|
65
|
-
function (cb) {q.push ({elem:2, pl:'twetrwte'}, cb)},
|
|
66
|
-
function (cb) {setTimeout (cb, 1111)},
|
|
67
|
-
function (cb) {q.size (function (err, size) {
|
|
68
|
-
size.should.equal (2);
|
|
69
|
-
cb();
|
|
70
|
-
})},
|
|
71
|
-
function (cb) {q.stats (function (err, res) {
|
|
72
|
-
res.should.eql ({get: 0, put: 2});
|
|
73
|
-
cb();
|
|
74
|
-
})},
|
|
75
|
-
function (cb) {q.next_t (function (err, res) {
|
|
76
|
-
should.equal (res, null);
|
|
77
|
-
cb();
|
|
78
|
-
})},
|
|
79
|
-
function (cb) {q.pop ('c1', function (err, ret) {
|
|
80
|
-
ret.payload.should.eql ({elem:1, pl:'twetrwte'});
|
|
81
|
-
cb (err);
|
|
82
|
-
})},
|
|
83
|
-
function (cb) {q.size (function (err, size) {
|
|
84
|
-
size.should.equal (0);
|
|
85
|
-
cb();
|
|
86
|
-
})},
|
|
87
|
-
function (cb) {q.stats (function (err, res) {
|
|
88
|
-
res.should.eql ({get: 1, put: 2});
|
|
89
|
-
cb();
|
|
90
|
-
})},
|
|
91
|
-
function (cb) {q.pop ('c2', function (err, ret) {
|
|
92
|
-
ret.payload.should.eql ({elem:2, pl:'twetrwte'});
|
|
93
|
-
cb (err);
|
|
94
|
-
})},
|
|
95
|
-
function (cb) {q.size (function (err, size) {
|
|
96
|
-
size.should.equal (0);
|
|
97
|
-
cb();
|
|
98
|
-
})},
|
|
99
|
-
function (cb) {q.stats (function (err, res) {
|
|
100
|
-
res.should.eql ({get: 2, put: 2});
|
|
101
|
-
cb();
|
|
102
|
-
})},
|
|
103
|
-
], function(err, results) {
|
|
104
|
-
q.drain();
|
|
105
|
-
done();
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
it ('pop cancellation works as expected', function (done){
|
|
111
|
-
var q = factory.queue('test_queue');
|
|
112
|
-
|
|
113
|
-
async.series([
|
|
114
|
-
function (cb) {
|
|
115
|
-
var tid1 = q.pop ('c1', {timeout: 2000}, function (err, ret) {err.should.equal('cancel')});
|
|
116
|
-
q.consumers().length.should.equal (1);
|
|
117
|
-
var tid2 = q.pop ('c2', {timeout: 2000}, function (err, ret) {err.should.equal('cancel')});
|
|
118
|
-
q.nConsumers().should.equal (2);
|
|
119
|
-
q.cancel (tid1);
|
|
120
|
-
q.nConsumers().should.equal (1);
|
|
121
|
-
q.cancel (tid2);
|
|
122
|
-
q.nConsumers().should.equal (0);
|
|
123
|
-
cb();
|
|
124
|
-
},
|
|
125
|
-
function (cb) {q.push ({elem:2, pl:'twetrwte'}, cb)},
|
|
126
|
-
function (cb) {q.push ({elem:1, pl:'twetrwte'}, cb)},
|
|
127
|
-
function (cb) {setTimeout (cb, 1111)},
|
|
128
|
-
function (cb) {q.pop ('c3', {timeout: 15000}, function (err, ret) {
|
|
129
|
-
ret.payload.should.eql ({elem:2, pl:'twetrwte'});
|
|
130
|
-
cb (err, ret);
|
|
131
|
-
})},
|
|
132
|
-
function (cb) {q.pop ('c4', {timeout: 15000}, function (err, ret) {
|
|
133
|
-
ret.payload.should.eql ({elem:1, pl:'twetrwte'});
|
|
134
|
-
cb (err, ret);
|
|
135
|
-
})},
|
|
136
|
-
function (cb) {q.size (function (err, size) {
|
|
137
|
-
size.should.equal (0);
|
|
138
|
-
cb();
|
|
139
|
-
})},
|
|
140
|
-
function (cb) {q.stats (function (err, res) {
|
|
141
|
-
res.should.eql ({get: 2, put: 2});
|
|
142
|
-
cb();
|
|
143
|
-
})},
|
|
144
|
-
], function(err, results) {
|
|
145
|
-
q.drain();
|
|
146
|
-
done();
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
});
|
|
151
|
-
});
|