@usermetrics/queuebit 1.0.6 → 1.0.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.
- package/README.md +21 -1
- package/docs/screen.jpg +0 -0
- package/examples/{server2server.js → client/server2server.js} +1 -1
- package/examples/client/start.cmd +2 -0
- package/examples/{inprocessserver.js → inprocess/inprocessserver.js} +6 -3
- package/examples/inprocess/start.cmd +1 -0
- package/examples/{loadbalancer.js → loadbalancer/loadbalancer.js} +6 -6
- package/examples/loadbalancer/server.js +10 -0
- package/examples/loadbalancer/start.cmd +5 -0
- package/examples/logger/logger.js +19 -0
- package/examples/logger/start.cmd +3 -0
- package/examples/qpanel.html +1 -1
- package/examples/standalone/server.js +11 -0
- package/examples/standalone/start.cmd +1 -0
- package/package.json +1 -1
- package/src/server.js +43 -0
- package/examples/start_load_balancer.cmd +0 -1
- package/examples/start_node_client.cmd +0 -1
- package/examples/start_node_inprocess.cmd +0 -1
package/README.md
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
# QueueBit
|
|
2
2
|
|
|
3
3
|
A high performance socket-based message queue server with guaranteed delivery, compatible with NATS queue patterns.
|
|
4
|
+
|
|
4
5
|
Built-in Load Balancer with round-robin delivery. (see examples).
|
|
5
6
|
|
|
7
|
+
If you need a pubsub between client and server, or server to server, this is a good choice.
|
|
8
|
+
|
|
6
9
|
It can run in-process in an existing Node.js app, separately as a standalone server, or run clients
|
|
7
10
|
in the backend and/or frontend.
|
|
8
11
|
A frontend in examples (qpanel.html) can help test the server.
|
|
@@ -33,13 +36,27 @@ npm install @usermetrics/queuebit
|
|
|
33
36
|
|
|
34
37
|
## Quick Start
|
|
35
38
|
|
|
36
|
-
### Start the Server
|
|
39
|
+
### Start the Server in-process with a node app
|
|
40
|
+
#### QueueBit runs with the main app. This can reduce costs for simple apps running the cloud.
|
|
37
41
|
|
|
38
42
|
```javascript
|
|
39
43
|
const { QueueBitServer } = require('./src/server');
|
|
40
44
|
const server = new QueueBitServer({ port: 3333 });
|
|
41
45
|
```
|
|
42
46
|
|
|
47
|
+
### Start the Server with monitoring
|
|
48
|
+
```javascript
|
|
49
|
+
const { QueueBitServer } = require('../../src/server');
|
|
50
|
+
const PORT = 3333;
|
|
51
|
+
new QueueBitServer({ port: PORT,
|
|
52
|
+
monitorInterval: 1000,
|
|
53
|
+
monitorCallback: (data) => {
|
|
54
|
+
console.log(data);
|
|
55
|
+
} });
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Start the Server as a standalone process
|
|
59
|
+
#### The server runs standalone
|
|
43
60
|
On Windows:
|
|
44
61
|
```cmd
|
|
45
62
|
start_server.cmd
|
|
@@ -93,6 +110,9 @@ setTimeout(async () => {
|
|
|
93
110
|
|
|
94
111
|
See [`examples/inprocessserver.js`](./examples/inprocessserver.js) for a full example.
|
|
95
112
|
|
|
113
|
+
## Testing Control Panel
|
|
114
|
+

|
|
115
|
+
|
|
96
116
|
## API Overview
|
|
97
117
|
|
|
98
118
|
### Server Options
|
package/docs/screen.jpg
ADDED
|
Binary file
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* run the server with /start_server.cmd and then run this example with /examples/start_node_client.cmd
|
|
6
6
|
*/
|
|
7
7
|
const http = require('http');
|
|
8
|
-
const { QueueBitClient } = require('
|
|
8
|
+
const { QueueBitClient } = require('../../src/client-node');
|
|
9
9
|
|
|
10
10
|
const webserverPORT = 3000;
|
|
11
11
|
const queuebitPORT = 3333;
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* In-process QueueBit demo.
|
|
3
3
|
* Starts the QueueBit server and an HTTP server in the same process.
|
|
4
|
-
* Use the qpanel.html dashboard
|
|
4
|
+
* Use the qpanel.html dashboard (run with live server in vscode) to publish messages to the queue
|
|
5
|
+
* and see them received by the HTTP server.
|
|
5
6
|
* Run this example with /examples/start_node_inprocess.cmd
|
|
6
7
|
* No need to run a separate QueueBit server.
|
|
8
|
+
* Pros: Simple setup, good for testing and demos. Lower costs since only one process is running.
|
|
9
|
+
* Cons: If the process crashes, both the queue server and HTTP server go down.
|
|
7
10
|
*/
|
|
8
11
|
const http = require('http');
|
|
9
|
-
const { QueueBitServer } = require('
|
|
10
|
-
const { QueueBitClient } = require('
|
|
12
|
+
const { QueueBitServer } = require('../../src/server');
|
|
13
|
+
const { QueueBitClient } = require('../../src/client-node');
|
|
11
14
|
|
|
12
15
|
const webserverPORT = 3000;
|
|
13
16
|
const queuebitPORT = 3333;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
node inprocessserver.js
|
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
* Messages are distributed round-robin across workers in the same load balancer.
|
|
4
4
|
* Only ONE worker receives each message (unlike regular subscribe where ALL receive).
|
|
5
5
|
*
|
|
6
|
+
* Flow: Server Receives Message | Server sends to next worker in line for that load balancer id
|
|
7
|
+
* Each client is given a loadbalancer id (e.g. 'workers').
|
|
8
|
+
* The server keeps track of which client is next in line for each loadbalancer id.
|
|
6
9
|
* Run this example with: node examples/queuegroup.js
|
|
7
10
|
*/
|
|
8
|
-
const { QueueBitServer } = require('../src/server');
|
|
9
|
-
const { QueueBitClient } = require('../src/client-node');
|
|
10
11
|
|
|
11
|
-
const
|
|
12
|
+
const { QueueBitClient } = require('../../src/client-node');
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
new QueueBitServer({ port: PORT });
|
|
14
|
+
const PORT = 3333;
|
|
15
15
|
|
|
16
16
|
async function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
|
|
17
17
|
|
|
@@ -45,7 +45,7 @@ async function main() {
|
|
|
45
45
|
|
|
46
46
|
for (let i = 1; i <= 6; i++) {
|
|
47
47
|
await publisher.publish({ job: `task-${i}`, payload: `data-${i}` }, { subject: 'jobs' });
|
|
48
|
-
await sleep(
|
|
48
|
+
await sleep(1000);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
await sleep(500);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// simple server wrapper
|
|
2
|
+
// you can start the server with node src/server-runner.js or create your own wrapper like this:
|
|
3
|
+
const { QueueBitServer } = require('../../src/server');
|
|
4
|
+
const PORT = 3333;
|
|
5
|
+
new QueueBitServer({ port: PORT,
|
|
6
|
+
monitorInterval: 1000,
|
|
7
|
+
monitorCallback: (data) => {
|
|
8
|
+
console.log(data);
|
|
9
|
+
} });
|
|
10
|
+
console.log(`QueueBit server running on port ${PORT}`);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server to server queue.
|
|
3
|
+
* This adds queue functionality to a simple http server (the queue server is running elsewhere)
|
|
4
|
+
* Use the qpanel.html dashboard to publish messages to the queue and see them received by the HTTP server.
|
|
5
|
+
* run the server with /start_server.cmd and then run this example with /examples/start_node_client.cmd
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { QueueBitClient } = require('../../src/client-node');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
const queuebitPORT = 3333;
|
|
12
|
+
|
|
13
|
+
// Initialize a queuebit message queue. It will connect to the server running on port 3333
|
|
14
|
+
const messageQueue = new QueueBitClient(`http://localhost:${queuebitPORT}`);
|
|
15
|
+
|
|
16
|
+
messageQueue.subscribe((msg) => {
|
|
17
|
+
console.log('Received message from queue:', msg);
|
|
18
|
+
}, { subject: 'default' });
|
|
19
|
+
|
package/examples/qpanel.html
CHANGED
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
<input type="text" id="subject" placeholder="Subject" class="small">
|
|
116
116
|
<br>
|
|
117
117
|
<button onclick="publishMessage()">Publish</button>
|
|
118
|
-
<button onclick="publishEphemeral()">Ephemeral</button>
|
|
118
|
+
<button onclick="publishEphemeral()">Ephemeral (deliver and delete)</button>
|
|
119
119
|
</div>
|
|
120
120
|
</div>
|
|
121
121
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// simple server wrapper
|
|
2
|
+
// you can start the server with node src/server-runner.js or create your own wrapper like this:
|
|
3
|
+
// specify monitorInterval to enable server monitoring (logs memory usage and event loop lag every interval ms)
|
|
4
|
+
const { QueueBitServer } = require('../../src/server');
|
|
5
|
+
const PORT = 3333;
|
|
6
|
+
new QueueBitServer({ port: PORT,
|
|
7
|
+
monitorInterval: 1000,
|
|
8
|
+
monitorCallback: (data) => {
|
|
9
|
+
console.log(data);
|
|
10
|
+
} });
|
|
11
|
+
console.log(`QueueBit server running on port ${PORT}`);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
node server.js
|
package/package.json
CHANGED
package/src/server.js
CHANGED
|
@@ -7,6 +7,8 @@ class QueueBitServer {
|
|
|
7
7
|
const port = options.port || 3000;
|
|
8
8
|
this.maxQueueSize = options.maxQueueSize || 10000;
|
|
9
9
|
this.version = packageJson.version;
|
|
10
|
+
this.monitorInterval = options.monitorInterval || null;
|
|
11
|
+
this.monitorCallback = options.monitorCallback || null;
|
|
10
12
|
|
|
11
13
|
this.messages = new Map();
|
|
12
14
|
this.subscribers = new Map();
|
|
@@ -33,6 +35,9 @@ class QueueBitServer {
|
|
|
33
35
|
this.setupHandlers();
|
|
34
36
|
this.startExpiryCheck();
|
|
35
37
|
this.startDeliveryProcessor();
|
|
38
|
+
if (this.monitorInterval) {
|
|
39
|
+
this.startMonitor(this.monitorInterval);
|
|
40
|
+
}
|
|
36
41
|
|
|
37
42
|
console.log(`QueueBit server v${this.version} listening on port ${port}`);
|
|
38
43
|
}
|
|
@@ -296,6 +301,44 @@ class QueueBitServer {
|
|
|
296
301
|
}, 1000); // Check every second
|
|
297
302
|
}
|
|
298
303
|
|
|
304
|
+
startMonitor(interval = 5000) {
|
|
305
|
+
setInterval(() => {
|
|
306
|
+
const stats = {
|
|
307
|
+
timestamp: new Date().toISOString(),
|
|
308
|
+
deliveryQueuePending: this.deliveryQueue.length,
|
|
309
|
+
subjects: {},
|
|
310
|
+
totalMessages: 0,
|
|
311
|
+
totalSubscribers: 0,
|
|
312
|
+
totalLBWorkers: 0,
|
|
313
|
+
loadBalancers: {}
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
for (const [subject, queue] of this.messages.entries()) {
|
|
317
|
+
stats.subjects[subject] = stats.subjects[subject] || {};
|
|
318
|
+
stats.subjects[subject].messages = queue.length;
|
|
319
|
+
stats.totalMessages += queue.length;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
for (const [subject, subs] of this.subscribers.entries()) {
|
|
323
|
+
stats.subjects[subject] = stats.subjects[subject] || {};
|
|
324
|
+
stats.subjects[subject].subscribers = subs.size;
|
|
325
|
+
stats.totalSubscribers += subs.size;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
for (const [subject, lbs] of this.loadBalancers.entries()) {
|
|
329
|
+
for (const [lbName, lb] of lbs.entries()) {
|
|
330
|
+
const key = `${subject} | ${lbName}`;
|
|
331
|
+
stats.loadBalancers[key] = lb.sockets.length;
|
|
332
|
+
stats.totalLBWorkers += lb.sockets.length;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (this.monitorCallback) {
|
|
337
|
+
this.monitorCallback(stats);
|
|
338
|
+
}
|
|
339
|
+
}, interval);
|
|
340
|
+
}
|
|
341
|
+
|
|
299
342
|
close() {
|
|
300
343
|
this.io.close();
|
|
301
344
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
node ./loadbalancer.js
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
node ./server2server.js
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
call node inprocessserver.js
|