keuss 1.6.12 → 1.6.15
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/.github/workflows/codeql-analysis.yml +72 -0
- package/Queue.js +3 -1
- package/Signal.js +6 -0
- package/TODO +0 -2
- package/backends/bucket-mongo-safe.js +2 -1
- package/backends/bucket-mongo.js +3 -1
- package/backends/mongo.js +1 -0
- package/backends/pl-mongo.js +1 -0
- package/backends/redis-list.js +3 -1
- package/backends/redis-oq.js +1 -0
- package/examples/snippets/06-random-consumer-producer.js +5 -5
- package/package.json +4 -3
- package/signal/local.js +76 -3
- package/signal/mongo-capped.js +68 -3
- package/signal/redis-pubsub.js +82 -3
- package/test/signal.js +161 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# For most projects, this workflow file will not need changing; you simply need
|
|
2
|
+
# to commit it to your repository.
|
|
3
|
+
#
|
|
4
|
+
# You may wish to alter this file to override the set of languages analyzed,
|
|
5
|
+
# or to provide custom queries or build logic.
|
|
6
|
+
#
|
|
7
|
+
# ******** NOTE ********
|
|
8
|
+
# We have attempted to detect the languages in your repository. Please check
|
|
9
|
+
# the `language` matrix defined below to confirm you have the correct set of
|
|
10
|
+
# supported CodeQL languages.
|
|
11
|
+
#
|
|
12
|
+
name: "CodeQL"
|
|
13
|
+
|
|
14
|
+
on:
|
|
15
|
+
push:
|
|
16
|
+
branches: [ master ]
|
|
17
|
+
pull_request:
|
|
18
|
+
# The branches below must be a subset of the branches above
|
|
19
|
+
branches: [ master ]
|
|
20
|
+
schedule:
|
|
21
|
+
- cron: '26 13 * * 1'
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
analyze:
|
|
25
|
+
name: Analyze
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
permissions:
|
|
28
|
+
actions: read
|
|
29
|
+
contents: read
|
|
30
|
+
security-events: write
|
|
31
|
+
|
|
32
|
+
strategy:
|
|
33
|
+
fail-fast: false
|
|
34
|
+
matrix:
|
|
35
|
+
language: [ 'javascript' ]
|
|
36
|
+
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
|
37
|
+
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
|
38
|
+
|
|
39
|
+
steps:
|
|
40
|
+
- name: Checkout repository
|
|
41
|
+
uses: actions/checkout@v3
|
|
42
|
+
|
|
43
|
+
# Initializes the CodeQL tools for scanning.
|
|
44
|
+
- name: Initialize CodeQL
|
|
45
|
+
uses: github/codeql-action/init@v2
|
|
46
|
+
with:
|
|
47
|
+
languages: ${{ matrix.language }}
|
|
48
|
+
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
49
|
+
# By default, queries listed here will override any specified in a config file.
|
|
50
|
+
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
51
|
+
|
|
52
|
+
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
|
53
|
+
# queries: security-extended,security-and-quality
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
|
57
|
+
# If this step fails, then you should remove it and run the build manually (see below)
|
|
58
|
+
- name: Autobuild
|
|
59
|
+
uses: github/codeql-action/autobuild@v2
|
|
60
|
+
|
|
61
|
+
# ℹ️ Command-line programs to run using the OS shell.
|
|
62
|
+
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
|
63
|
+
|
|
64
|
+
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
|
65
|
+
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
|
66
|
+
|
|
67
|
+
# - run: |
|
|
68
|
+
# echo "Run, Build Application using script"
|
|
69
|
+
# ./location_of_script_within_repo/buildscript.sh
|
|
70
|
+
|
|
71
|
+
- name: Perform CodeQL Analysis
|
|
72
|
+
uses: github/codeql-action/analyze@v2
|
package/Queue.js
CHANGED
|
@@ -537,13 +537,15 @@ class Queue {
|
|
|
537
537
|
//////////////////////////////////
|
|
538
538
|
async.parallel ({
|
|
539
539
|
type: cb => cb (null, this.type()),
|
|
540
|
+
capabilities: cb => cb (null, this.capabilities ()),
|
|
541
|
+
factory: cb => cb (null, this._factory.to_descriptor_obj ()),
|
|
540
542
|
stats: cb => this.stats (cb),
|
|
541
543
|
paused: cb => this.paused (cb),
|
|
542
544
|
next_mature_t: cb => this.next_t (cb),
|
|
543
545
|
size: cb => this.size (cb),
|
|
544
546
|
totalSize: cb => this.totalSize (cb),
|
|
545
547
|
schedSize: cb => this.schedSize (cb),
|
|
546
|
-
resvSize: cb => this.resvSize (cb)
|
|
548
|
+
resvSize: cb => this.resvSize (cb)
|
|
547
549
|
}, cb);
|
|
548
550
|
}
|
|
549
551
|
|
package/Signal.js
CHANGED
|
@@ -73,6 +73,12 @@ class Signal {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
|
|
76
|
+
// to be extended: generic pubsub service
|
|
77
|
+
subscribe_extra (topic, on_cb) {return false}
|
|
78
|
+
unsubscribe_extra (subscr) {}
|
|
79
|
+
emit_extra (topic, ev, cb) {if (cb) cb ();}
|
|
80
|
+
|
|
81
|
+
|
|
76
82
|
static _hrtimeAsMSecs (hrtime) {
|
|
77
83
|
return (hrtime[0] * 1000) + (hrtime[1] / 1e6);
|
|
78
84
|
}
|
package/TODO
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
bugs
|
|
2
2
|
-------------------------------------------------------------
|
|
3
|
-
* deadlettering on all backend but mongo-pipeline does not preserve hdrs
|
|
4
3
|
|
|
5
4
|
prio 1
|
|
6
5
|
-------------------------------------------------------------
|
|
@@ -10,7 +9,6 @@ prio 1
|
|
|
10
9
|
+ add some commonplace transforms (etl-like)
|
|
11
10
|
+ create a server for that, allow processor code defined externally
|
|
12
11
|
|
|
13
|
-
|
|
14
12
|
prio 0
|
|
15
13
|
-----------------------------------------------------------------
|
|
16
14
|
* bridges?
|
package/backends/bucket-mongo.js
CHANGED
package/backends/mongo.js
CHANGED
package/backends/pl-mongo.js
CHANGED
package/backends/redis-list.js
CHANGED
package/backends/redis-oq.js
CHANGED
|
@@ -26,10 +26,10 @@ var factory_opts = {
|
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
// test dimensions: elems to produce and consume, number of consumers, number of producers
|
|
29
|
-
const num_elems =
|
|
29
|
+
const num_elems = 1000000;
|
|
30
30
|
const num_producers = 3;
|
|
31
31
|
const num_consumers = 7;
|
|
32
|
-
const commit_likelihood =
|
|
32
|
+
const commit_likelihood = 75;
|
|
33
33
|
|
|
34
34
|
// stats holder
|
|
35
35
|
var selfs = {
|
|
@@ -223,12 +223,12 @@ MQ (factory_opts, function (err, factory) {
|
|
|
223
223
|
var q = factory.queue ('test_queue_456', q_opts);
|
|
224
224
|
|
|
225
225
|
var timer = setInterval (() => {
|
|
226
|
-
console.log ('**** state: %
|
|
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
227
|
|
|
228
228
|
console.log ('das pop %d, ko %d, ok %d', das_pop, das_ko, das_ok);
|
|
229
229
|
|
|
230
230
|
q.status ((err ,res) => {
|
|
231
|
-
console.log ('**** status: %
|
|
231
|
+
console.log ('**** status: %o', res);
|
|
232
232
|
});
|
|
233
233
|
}, 2000);
|
|
234
234
|
|
|
@@ -263,7 +263,7 @@ MQ (factory_opts, function (err, factory) {
|
|
|
263
263
|
clearInterval (timer);
|
|
264
264
|
|
|
265
265
|
q.status ((err ,res) => {
|
|
266
|
-
console.log ('**** status: %
|
|
266
|
+
console.log ('**** status: %o', res);
|
|
267
267
|
q.drain (() => factory.close ());
|
|
268
268
|
});
|
|
269
269
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "keuss",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.15",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"queue",
|
|
6
6
|
"persistent",
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
"lodash": "~4.17.21",
|
|
35
35
|
"mitt": "~3.0.0",
|
|
36
36
|
"mongodb": "~4.5.0",
|
|
37
|
-
"uuid": "~8.3.2"
|
|
37
|
+
"uuid": "~8.3.2",
|
|
38
|
+
"why-is-node-running": "^2.2.2"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"chance": "~1.1.8",
|
|
@@ -43,6 +44,6 @@
|
|
|
43
44
|
},
|
|
44
45
|
"scripts": {
|
|
45
46
|
"test": "mocha --reporter spec --check-leaks --no-timeouts --exit test/",
|
|
46
|
-
"test-with-coverage": "nyc --reporter=
|
|
47
|
+
"test-with-coverage": "nyc --reporter=html -- mocha --reporter spec --check-leaks --no-timeouts --exit test/"
|
|
47
48
|
}
|
|
48
49
|
}
|
package/signal/local.js
CHANGED
|
@@ -4,6 +4,7 @@ var Signal = require ('../Signal');
|
|
|
4
4
|
var debug = require('debug')('keuss:Signal:local');
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
//////////////////////////////////////////////////////////////////////
|
|
7
8
|
class LocalSignal extends Signal {
|
|
8
9
|
constructor (queue, factory, opts) {
|
|
9
10
|
super (queue, opts);
|
|
@@ -39,38 +40,110 @@ class LocalSignal extends Signal {
|
|
|
39
40
|
debug ('created LocalSignal for channel %s', this._channel);
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
type () {return LocalSignalFactory.Type ()}
|
|
43
43
|
|
|
44
|
+
//////////////////////////////////////////////////////////////////////
|
|
45
|
+
type () {
|
|
46
|
+
return LocalSignalFactory.Type ();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
//////////////////////////////////////////////////////////////////////
|
|
44
51
|
emitInsertion (mature, cb) {
|
|
45
52
|
debug ('got insertion event [%o], relay on local mitt', mature);
|
|
46
53
|
this._factory._emitter.emit (this._channel, mature.getTime () + '');
|
|
47
54
|
}
|
|
48
55
|
|
|
56
|
+
//////////////////////////////////////////////////////////////////////
|
|
49
57
|
emitPaused (paused, cb) {
|
|
50
58
|
debug ('got paused event [%d], relay on local mitt', paused);
|
|
51
59
|
this._factory._emitter.emit (this._channel, `p ${paused}`);
|
|
52
60
|
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
//////////////////////////////////////////////////////////////////////
|
|
64
|
+
subscribe_extra (topic, on_cb) {
|
|
65
|
+
return this._factory.subscribe_extra (this._master.ns (), topic, on_cb);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
//////////////////////////////////////////////////////////////////////
|
|
70
|
+
unsubscribe_extra (subscr) {
|
|
71
|
+
this._factory.unsubscribe_extra (subscr);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
//////////////////////////////////////////////////////////////////////
|
|
76
|
+
emit_extra (topic, ev, cb) {
|
|
77
|
+
this._factory.emit_extra (this._master.ns (), topic, ev, cb);
|
|
78
|
+
}
|
|
53
79
|
}
|
|
54
80
|
|
|
55
81
|
|
|
82
|
+
//////////////////////////////////////////////////////////////////////
|
|
56
83
|
class LocalSignalFactory {
|
|
57
84
|
constructor (opts) {
|
|
58
85
|
this._emitter = mitt();
|
|
86
|
+
debug ('created local factory');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
//////////////////////////////////////////////////////////////////////
|
|
91
|
+
static Type () {
|
|
92
|
+
return 'signal:local';
|
|
59
93
|
}
|
|
60
94
|
|
|
61
|
-
static Type () {return 'signal:local'}
|
|
62
|
-
type () {return LocalSignalFactory.Type ()}
|
|
63
95
|
|
|
96
|
+
//////////////////////////////////////////////////////////////////////
|
|
97
|
+
type () {
|
|
98
|
+
return LocalSignalFactory.Type ();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
//////////////////////////////////////////////////////////////////////
|
|
64
103
|
signal (queue, opts) {
|
|
65
104
|
return new LocalSignal (queue, this, opts);
|
|
66
105
|
}
|
|
67
106
|
|
|
107
|
+
|
|
108
|
+
//////////////////////////////////////////////////////////////////////
|
|
109
|
+
subscribe_extra (ns, topic, on_cb) {
|
|
110
|
+
const t = `keuss:signal:${ns}:extra:${topic}`;
|
|
111
|
+
debug ('subscribing to ns [%s], topic [%s]', ns, t);
|
|
112
|
+
|
|
113
|
+
const s = {
|
|
114
|
+
n: ns,
|
|
115
|
+
t: t,
|
|
116
|
+
f: (msg => on_cb (msg))
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
this._emitter.on (s.t, s.f);
|
|
120
|
+
return s;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
//////////////////////////////////////////////////////////////////////
|
|
125
|
+
unsubscribe_extra (s) {
|
|
126
|
+
this._emitter.off (s.t, s.f);
|
|
127
|
+
debug ('unsubscribed on %s', s.t);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
//////////////////////////////////////////////////////////////////////
|
|
132
|
+
emit_extra (ns, topic, ev, cb) {
|
|
133
|
+
const t = `keuss:signal:${ns}:extra:${topic}`;
|
|
134
|
+
debug ('emit extra on topic [%s], value [%j]', t, ev);
|
|
135
|
+
this._emitter.emit (t, ev);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
//////////////////////////////////////////////////////////////////////
|
|
68
140
|
close (cb) {
|
|
69
141
|
cb ();
|
|
70
142
|
}
|
|
71
143
|
}
|
|
72
144
|
|
|
73
145
|
|
|
146
|
+
//////////////////////////////////////////////////////////////////////
|
|
74
147
|
function creator (opts, cb) {
|
|
75
148
|
return cb (null, new LocalSignalFactory (opts));
|
|
76
149
|
}
|
package/signal/mongo-capped.js
CHANGED
|
@@ -5,7 +5,7 @@ var Signal = require ('../Signal');
|
|
|
5
5
|
|
|
6
6
|
var debug = require('debug')('keuss:Signal:MongoCapped');
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
//////////////////////////////////////////////////////////////////////
|
|
9
9
|
class MCSignal extends Signal {
|
|
10
10
|
constructor (queue, factory, opts) {
|
|
11
11
|
super (queue, opts);
|
|
@@ -45,24 +45,52 @@ class MCSignal extends Signal {
|
|
|
45
45
|
debug ('created mongo-capped signaller for topic %s with opts %o', this._topic_name, opts);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
|
|
49
|
+
//////////////////////////////////////////////////////////////////////
|
|
48
50
|
type () {return MCSignalFactory.Type ()}
|
|
49
51
|
|
|
52
|
+
|
|
53
|
+
//////////////////////////////////////////////////////////////////////
|
|
50
54
|
emitInsertion (mature, cb) {
|
|
51
55
|
debug ('emit insertion on topic [%s] value [%d])', this._topic_name, mature);
|
|
52
56
|
this._factory._channel.publish (this._topic_name, mature.getTime());
|
|
53
57
|
}
|
|
54
58
|
|
|
59
|
+
|
|
60
|
+
//////////////////////////////////////////////////////////////////////
|
|
55
61
|
emitPaused (paused, cb) {
|
|
56
62
|
debug ('emit paused on topic [%s], value [%b]', this._topic_name, paused);
|
|
57
63
|
this._factory._channel.publish (this._topic_name, `p ${paused}`);
|
|
58
64
|
}
|
|
59
65
|
|
|
66
|
+
|
|
67
|
+
//////////////////////////////////////////////////////////////////////
|
|
60
68
|
_insertionEvent (mature) {
|
|
61
69
|
debug ('got insertion event on ch [%s], mature is %s, calling master.emitInsertion()', this._channel, mature);
|
|
62
70
|
this._master.signalInsertion (new Date (mature));
|
|
63
71
|
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
//////////////////////////////////////////////////////////////////////
|
|
75
|
+
subscribe_extra (topic, on_cb) {
|
|
76
|
+
return this._factory.subscribe_extra (this._master.ns (), topic, on_cb);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
//////////////////////////////////////////////////////////////////////
|
|
81
|
+
unsubscribe_extra (subscr) {
|
|
82
|
+
this._factory.unsubscribe_extra (subscr);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
//////////////////////////////////////////////////////////////////////
|
|
87
|
+
emit_extra (topic, ev, cb) {
|
|
88
|
+
this._factory.emit_extra (this._master.ns (), topic, ev, cb);
|
|
89
|
+
}
|
|
64
90
|
}
|
|
65
91
|
|
|
92
|
+
|
|
93
|
+
//////////////////////////////////////////////////////////////////////
|
|
66
94
|
class MCSignalFactory {
|
|
67
95
|
constructor (opts) {
|
|
68
96
|
var defaults = {
|
|
@@ -79,19 +107,56 @@ class MCSignalFactory {
|
|
|
79
107
|
debug ('created mongo-capped factory with opts %o', opts);
|
|
80
108
|
}
|
|
81
109
|
|
|
82
|
-
static Type () {return 'signal:mongo-capped'}
|
|
83
|
-
type () {return MCSignalFactory.Type ()}
|
|
84
110
|
|
|
111
|
+
//////////////////////////////////////////////////////////////////////
|
|
112
|
+
static Type () {
|
|
113
|
+
return 'signal:mongo-capped';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
//////////////////////////////////////////////////////////////////////
|
|
118
|
+
type () {
|
|
119
|
+
return MCSignalFactory.Type ();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
//////////////////////////////////////////////////////////////////////
|
|
85
124
|
signal (channel, opts) {
|
|
86
125
|
return new MCSignal (channel, this, opts);
|
|
87
126
|
}
|
|
88
127
|
|
|
128
|
+
|
|
129
|
+
//////////////////////////////////////////////////////////////////////
|
|
130
|
+
subscribe_extra (ns, topic, on_cb) {
|
|
131
|
+
const t = `keuss:signal:${ns}:extra:${topic}`;
|
|
132
|
+
debug ('subscribing to ns [%s], topic [%s]', ns, t);
|
|
133
|
+
return this._channel.subscribe (t, on_cb);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
//////////////////////////////////////////////////////////////////////
|
|
138
|
+
unsubscribe_extra (subscr) {
|
|
139
|
+
subscr.unsubscribe ();
|
|
140
|
+
debug ('unsubscribed on %j', subscr);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
//////////////////////////////////////////////////////////////////////
|
|
145
|
+
emit_extra (ns, topic, ev, cb) {
|
|
146
|
+
const t = `keuss:signal:${ns}:extra:${topic}`;
|
|
147
|
+
debug ('emit extra on ns [%s], topic [%s], value [%j]', ns, t, ev);
|
|
148
|
+
this._channel.publish (t, ev);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
//////////////////////////////////////////////////////////////////////
|
|
89
153
|
close (cb) {
|
|
90
154
|
this._mubsub.close (cb);
|
|
91
155
|
}
|
|
92
156
|
}
|
|
93
157
|
|
|
94
158
|
|
|
159
|
+
//////////////////////////////////////////////////////////////////////
|
|
95
160
|
function creator (opts, cb) {
|
|
96
161
|
return cb (null, new MCSignalFactory (opts));
|
|
97
162
|
}
|
package/signal/redis-pubsub.js
CHANGED
|
@@ -8,6 +8,7 @@ var Signal = require ('../Signal');
|
|
|
8
8
|
var debug = require('debug')('keuss:Signal:RedisPubsub');
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
//////////////////////////////////////////////////////////////////////
|
|
11
12
|
class RPSSignal extends Signal {
|
|
12
13
|
constructor (queue, factory, opts) {
|
|
13
14
|
super (queue, opts);
|
|
@@ -53,24 +54,54 @@ class RPSSignal extends Signal {
|
|
|
53
54
|
debug ('created redis-pubsub signaller for topic %s with opts %o', this._topic_name, opts);
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
type () {return RPSSignalFactory.Type ()}
|
|
57
57
|
|
|
58
|
+
//////////////////////////////////////////////////////////////////////
|
|
59
|
+
type () {
|
|
60
|
+
return RPSSignalFactory.Type ();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
//////////////////////////////////////////////////////////////////////
|
|
58
65
|
emitInsertion (mature, cb) {
|
|
59
66
|
debug ('emit insertion on channel [%s] value [%d])', this._channel, mature);
|
|
60
67
|
this._rediscl_pub.publish (this._channel, mature.getTime());
|
|
61
68
|
}
|
|
62
69
|
|
|
70
|
+
|
|
71
|
+
//////////////////////////////////////////////////////////////////////
|
|
63
72
|
emitPaused (paused, cb) {
|
|
64
73
|
debug ('emit paused on channel [%s], value [%b]', this._channel, paused);
|
|
65
74
|
this._rediscl_pub.publish (this._channel, `p ${paused}`);
|
|
66
75
|
}
|
|
67
76
|
|
|
77
|
+
|
|
78
|
+
//////////////////////////////////////////////////////////////////////
|
|
68
79
|
_insertionEvent (mature) {
|
|
69
80
|
debug ('got insertion event on ch [%s], mature is %s, calling master.emitInsertion()', this._channel, mature);
|
|
70
81
|
this._master.signalInsertion (new Date (mature));
|
|
71
82
|
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
//////////////////////////////////////////////////////////////////////
|
|
86
|
+
subscribe_extra (topic, on_cb) {
|
|
87
|
+
return this._factory.subscribe_extra (this._master.ns (), topic, on_cb);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
//////////////////////////////////////////////////////////////////////
|
|
92
|
+
unsubscribe_extra (subscr) {
|
|
93
|
+
this._factory.unsubscribe_extra (subscr);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
//////////////////////////////////////////////////////////////////////
|
|
98
|
+
emit_extra (topic, ev, cb) {
|
|
99
|
+
this._factory.emit_extra (this._master.ns (), topic, ev, cb);
|
|
100
|
+
}
|
|
72
101
|
}
|
|
73
102
|
|
|
103
|
+
|
|
104
|
+
//////////////////////////////////////////////////////////////////////
|
|
74
105
|
class RPSSignalFactory {
|
|
75
106
|
constructor (opts) {
|
|
76
107
|
this._opts = opts || {};
|
|
@@ -86,14 +117,61 @@ class RPSSignalFactory {
|
|
|
86
117
|
debug ('created redis-pubsub factory with opts %o', opts);
|
|
87
118
|
}
|
|
88
119
|
|
|
89
|
-
static Type () {return 'signal:redis-pubsub'}
|
|
90
|
-
type () {return Type ()}
|
|
91
120
|
|
|
121
|
+
//////////////////////////////////////////////////////////////////////
|
|
122
|
+
static Type () {
|
|
123
|
+
return 'signal:redis-pubsub';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
//////////////////////////////////////////////////////////////////////
|
|
128
|
+
type () {
|
|
129
|
+
return RPSSignalFactory.Type ();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
//////////////////////////////////////////////////////////////////////
|
|
92
134
|
signal (channel, opts) {
|
|
93
135
|
debug ('creating redis-pubsub signaller with opts %o', opts);
|
|
94
136
|
return new RPSSignal (channel, this, opts);
|
|
95
137
|
}
|
|
96
138
|
|
|
139
|
+
|
|
140
|
+
//////////////////////////////////////////////////////////////////////
|
|
141
|
+
subscribe_extra (ns, topic, on_cb) {
|
|
142
|
+
const t = `keuss:signal:${ns}:extra:${topic}`;
|
|
143
|
+
debug ('subscribing to ns [%s], topic [%s]', ns, t);
|
|
144
|
+
|
|
145
|
+
const s = {
|
|
146
|
+
n: ns,
|
|
147
|
+
t: t,
|
|
148
|
+
f: (msg => on_cb (JSON.parse (msg)))
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
this._emitter.on (s.t, s.f);
|
|
152
|
+
this._rediscl_sub.subscribe (s.t);
|
|
153
|
+
return s;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
//////////////////////////////////////////////////////////////////////
|
|
158
|
+
unsubscribe_extra (subscr) {
|
|
159
|
+
this._rediscl_sub.unsubscribe (subscr.t);
|
|
160
|
+
this._emitter.off (subscr.t, subscr.f);
|
|
161
|
+
debug ('unsubscribed on %j', subscr);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
//////////////////////////////////////////////////////////////////////
|
|
166
|
+
emit_extra (ns, topic, ev, cb) {
|
|
167
|
+
const t = `keuss:signal:${ns}:extra:${topic}`;
|
|
168
|
+
const v = JSON.stringify(ev);
|
|
169
|
+
debug ('emit extra on ns [%s], topic [%s], value [%j]', ns, t, ev);
|
|
170
|
+
this._rediscl_pub.publish (t, v);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
//////////////////////////////////////////////////////////////////////
|
|
97
175
|
close (cb) {
|
|
98
176
|
async.parallel ([
|
|
99
177
|
cb => this._rediscl_pub.quit (cb),
|
|
@@ -103,6 +181,7 @@ class RPSSignalFactory {
|
|
|
103
181
|
}
|
|
104
182
|
|
|
105
183
|
|
|
184
|
+
//////////////////////////////////////////////////////////////////////
|
|
106
185
|
function creator (opts, cb) {
|
|
107
186
|
return cb (null, new RPSSignalFactory (opts));
|
|
108
187
|
}
|
package/test/signal.js
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
const should = require ('should');
|
|
2
|
+
const async = require ('async');
|
|
3
|
+
const _ = require ('lodash');
|
|
4
|
+
|
|
5
|
+
const Local = require ('../signal/local');
|
|
6
|
+
const Redis = require ('../signal/redis-pubsub');
|
|
7
|
+
const Mongo = require ('../signal/mongo-capped');
|
|
8
|
+
|
|
9
|
+
// const whyIsNodeRunning = require('why-is-node-running');
|
|
10
|
+
|
|
11
|
+
const MongoClient = require ('mongodb').MongoClient;
|
|
12
|
+
|
|
13
|
+
// setTimeout (() => whyIsNodeRunning(), 9000)
|
|
14
|
+
|
|
15
|
+
_.forEach ({
|
|
16
|
+
Local,
|
|
17
|
+
Redis,
|
|
18
|
+
Mongo
|
|
19
|
+
}, (CL, CLName) => {
|
|
20
|
+
describe (`${CLName} signaller`, () => {
|
|
21
|
+
|
|
22
|
+
before (done => {
|
|
23
|
+
done();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
after (done => async.series ([
|
|
27
|
+
cb => setTimeout (cb, 1000),
|
|
28
|
+
cb => MongoClient.connect ('mongodb://localhost/keuss_signal', (err, cl) => {
|
|
29
|
+
if (err) return done (err);
|
|
30
|
+
cl.db().dropDatabase (() => cl.close (cb))
|
|
31
|
+
})
|
|
32
|
+
], done));
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
it ('creates ok', done => {
|
|
36
|
+
CL ({}, (err, factory) => {
|
|
37
|
+
if (err) return done(err);
|
|
38
|
+
const q = {ns() {return 'the-ns'}, name () {return 'the-queue'}};
|
|
39
|
+
const signal = factory.signal (q, {});
|
|
40
|
+
setTimeout (() => factory.close(done), 500);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
describe (`extra/generic pubsub`, () => {
|
|
46
|
+
it ('subscribes and receives info ok on 3 subscribers', done => {
|
|
47
|
+
CL ({}, (err, factory) => {
|
|
48
|
+
if (err) return done(err);
|
|
49
|
+
const q = {ns() {return 'the-ns'}, name () {return 'the-queue'}};
|
|
50
|
+
const signal1 = factory.signal (q, {});
|
|
51
|
+
const signal2 = factory.signal (q, {});
|
|
52
|
+
const signal3 = factory.signal (q, {});
|
|
53
|
+
|
|
54
|
+
const evs = [];
|
|
55
|
+
|
|
56
|
+
function manage (ev) {
|
|
57
|
+
evs.push (ev);
|
|
58
|
+
if (evs.length == 3) {
|
|
59
|
+
evs.should.eql ([
|
|
60
|
+
{ a: 1, b: 'ertwetr' },
|
|
61
|
+
{ a: 1, b: 'ertwetr' },
|
|
62
|
+
{ a: 1, b: 'ertwetr' }
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
factory.close(done);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
signal1.subscribe_extra ('the-topic', manage);
|
|
70
|
+
signal2.subscribe_extra ('the-topic', manage);
|
|
71
|
+
signal3.subscribe_extra ('the-topic', manage);
|
|
72
|
+
|
|
73
|
+
setTimeout (() => signal2.emit_extra ('the-topic', {a:1, b:'ertwetr'}), 100);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
it ('functions across several queues on the same signaller', done => {
|
|
79
|
+
CL ({}, (err, factory) => {
|
|
80
|
+
if (err) return done(err);
|
|
81
|
+
const signal1 = factory.signal ({ns() {return 'the-ns'}, name () {return 'the-queue-1'}}, {});
|
|
82
|
+
const signal2 = factory.signal ({ns() {return 'the-ns'}, name () {return 'the-queue-2'}}, {});
|
|
83
|
+
const signal3 = factory.signal ({ns() {return 'the-ns'}, name () {return 'the-queue-3'}}, {});
|
|
84
|
+
|
|
85
|
+
const evs = [];
|
|
86
|
+
|
|
87
|
+
function manage (ev) {
|
|
88
|
+
evs.push (ev);
|
|
89
|
+
if (evs.length == 3) {
|
|
90
|
+
evs.should.eql ([
|
|
91
|
+
{ a: 1, b: 'ertwetr' },
|
|
92
|
+
{ a: 1, b: 'ertwetr' },
|
|
93
|
+
{ a: 1, b: 'ertwetr' }
|
|
94
|
+
]);
|
|
95
|
+
|
|
96
|
+
factory.close(done);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
signal1.subscribe_extra ('the-topic', manage);
|
|
101
|
+
signal2.subscribe_extra ('the-topic', manage);
|
|
102
|
+
signal3.subscribe_extra ('the-topic', manage);
|
|
103
|
+
|
|
104
|
+
setTimeout (() => signal2.emit_extra ('the-topic', {a:1, b:'ertwetr'}), 100);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it ('isolates namespaces', done => {
|
|
109
|
+
CL ({}, (err, factory) => {
|
|
110
|
+
if (err) return done(err);
|
|
111
|
+
const signal1 = factory.signal ({ns() {return 'the-ns-1'}, name () {return 'the-queue'}}, {});
|
|
112
|
+
const signal2 = factory.signal ({ns() {return 'the-ns-2'}, name () {return 'the-queue'}}, {});
|
|
113
|
+
|
|
114
|
+
const evs = [];
|
|
115
|
+
|
|
116
|
+
async.series ([
|
|
117
|
+
cb => {signal1.subscribe_extra ('the-topic', ev => evs.push ({src: 1, ev})); cb ();},
|
|
118
|
+
cb => {signal2.subscribe_extra ('the-topic', ev => evs.push ({src: 2, ev})); cb ();},
|
|
119
|
+
cb => setTimeout (() => {signal1.emit_extra ('the-topic', {a:1, b:'qwertyuiop'}); cb ()}, 100),
|
|
120
|
+
cb => setTimeout (() => {signal2.emit_extra ('the-topic', {a:2, b:'asdfghjkl'}); cb ()}, 100),
|
|
121
|
+
cb => setTimeout (cb, 100),
|
|
122
|
+
], err => {
|
|
123
|
+
if (err) return done(err);
|
|
124
|
+
evs.should.eql ([
|
|
125
|
+
{ src: 1, ev: { a: 1, b: 'qwertyuiop' } },
|
|
126
|
+
{ src: 2, ev: { a: 2, b: 'asdfghjkl' } }
|
|
127
|
+
]);
|
|
128
|
+
factory.close(done);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it ('unsubscribes ok and ceases to receive info', done => {
|
|
134
|
+
CL ({}, (err, factory) => {
|
|
135
|
+
if (err) return done(err);
|
|
136
|
+
const signal1 = factory.signal ({ns() {return 'the-ns'}, name () {return 'the-queue'}}, {});
|
|
137
|
+
|
|
138
|
+
const evs = [];
|
|
139
|
+
|
|
140
|
+
function manage (ev) { evs.push (ev); }
|
|
141
|
+
|
|
142
|
+
let subscr = null;
|
|
143
|
+
async.series ([
|
|
144
|
+
cb => {subscr = signal1.subscribe_extra ('the-topic', manage); cb ();},
|
|
145
|
+
cb => setTimeout (() => {signal1.emit_extra ('the-topic', {a:1, b:'ertwetr'}); cb ()}, 100),
|
|
146
|
+
cb => setTimeout (cb, 100),
|
|
147
|
+
cb => {signal1.unsubscribe_extra (subscr); cb (); },
|
|
148
|
+
cb => setTimeout (() => {signal1.emit_extra ('the-topic', {a:2, b:'asdfghjk'}); cb ()}, 100),
|
|
149
|
+
], err => {
|
|
150
|
+
if (err) return done(err);
|
|
151
|
+
evs.should.eql ([ { a: 1, b: 'ertwetr' } ]);
|
|
152
|
+
factory.close(done);
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
});
|
|
161
|
+
});
|