@usermetrics/queuebit 1.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/LICENSE +21 -0
- package/README.md +276 -0
- package/docs/API.md +577 -0
- package/docs/EXAMPLES.md +330 -0
- package/docs/QUICKSTART.md +122 -0
- package/examples/browser-example.html +573 -0
- package/package.json +52 -0
- package/src/client-browser.js +134 -0
- package/src/client-node.js +112 -0
- package/src/client.js +73 -0
- package/src/index.js +7 -0
- package/src/server-runner.js +30 -0
- package/src/server.js +292 -0
package/docs/EXAMPLES.md
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
# QueueBit Examples
|
|
2
|
+
|
|
3
|
+
Practical examples for common use cases.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Chat Application](#chat-application)
|
|
8
|
+
- [Task Queue System](#task-queue-system)
|
|
9
|
+
- [Real-time Analytics](#real-time-analytics)
|
|
10
|
+
- [Microservices Communication](#microservices-communication)
|
|
11
|
+
- [Event Sourcing](#event-sourcing)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Chat Application
|
|
16
|
+
|
|
17
|
+
Simple chat room using QueueBit.
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
const { QueueBitServer, QueueBitClient } = require('queuebit');
|
|
21
|
+
|
|
22
|
+
// Server
|
|
23
|
+
const server = new QueueBitServer({ port: 3000 });
|
|
24
|
+
|
|
25
|
+
// Client
|
|
26
|
+
const username = process.argv[2] || 'Anonymous';
|
|
27
|
+
const client = new QueueBitClient('http://localhost:3000');
|
|
28
|
+
|
|
29
|
+
// Receive messages
|
|
30
|
+
await client.subscribe((message) => {
|
|
31
|
+
const { user, text, timestamp } = message.data;
|
|
32
|
+
const time = new Date(timestamp).toLocaleTimeString();
|
|
33
|
+
console.log(`[${time}] ${user}: ${text}`);
|
|
34
|
+
}, { subject: 'chat' });
|
|
35
|
+
|
|
36
|
+
// Send messages
|
|
37
|
+
const readline = require('readline');
|
|
38
|
+
const rl = readline.createInterface({
|
|
39
|
+
input: process.stdin,
|
|
40
|
+
output: process.stdout
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
rl.on('line', async (text) => {
|
|
44
|
+
await client.publish(
|
|
45
|
+
{ user: username, text, timestamp: new Date() },
|
|
46
|
+
{ subject: 'chat' }
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
console.log(`Joined chat as ${username}`);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Task Queue System
|
|
56
|
+
|
|
57
|
+
Distribute tasks across multiple workers.
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
// producer.js
|
|
61
|
+
const { QueueBitClient } = require('queuebit');
|
|
62
|
+
const client = new QueueBitClient('http://localhost:3000');
|
|
63
|
+
|
|
64
|
+
async function produceTasks() {
|
|
65
|
+
for (let i = 1; i <= 100; i++) {
|
|
66
|
+
await client.publish(
|
|
67
|
+
{
|
|
68
|
+
taskId: i,
|
|
69
|
+
type: 'process-image',
|
|
70
|
+
imageUrl: `https://example.com/img${i}.jpg`,
|
|
71
|
+
priority: i % 10 === 0 ? 'high' : 'normal'
|
|
72
|
+
},
|
|
73
|
+
{ subject: 'tasks' }
|
|
74
|
+
);
|
|
75
|
+
console.log(`Task ${i} queued`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
produceTasks();
|
|
80
|
+
|
|
81
|
+
// worker.js
|
|
82
|
+
const { QueueBitClient } = require('queuebit');
|
|
83
|
+
const workerId = process.argv[2] || '1';
|
|
84
|
+
const client = new QueueBitClient('http://localhost:3000');
|
|
85
|
+
|
|
86
|
+
await client.subscribe(async (message) => {
|
|
87
|
+
const { taskId, type, imageUrl, priority } = message.data;
|
|
88
|
+
|
|
89
|
+
console.log(`Worker ${workerId} processing task ${taskId} (${priority})`);
|
|
90
|
+
|
|
91
|
+
// Simulate work
|
|
92
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
93
|
+
|
|
94
|
+
// Publish result
|
|
95
|
+
await client.publish(
|
|
96
|
+
{ taskId, workerId, status: 'completed', timestamp: new Date() },
|
|
97
|
+
{ subject: 'results' }
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
console.log(`Worker ${workerId} completed task ${taskId}`);
|
|
101
|
+
}, { subject: 'tasks', queue: 'workers' });
|
|
102
|
+
|
|
103
|
+
console.log(`Worker ${workerId} ready`);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Real-time Analytics
|
|
109
|
+
|
|
110
|
+
Collect and aggregate analytics events.
|
|
111
|
+
|
|
112
|
+
```javascript
|
|
113
|
+
// event-collector.js
|
|
114
|
+
const { QueueBitServer, QueueBitClient } = require('queuebit');
|
|
115
|
+
|
|
116
|
+
const server = new QueueBitServer({ port: 3000 });
|
|
117
|
+
const collector = new QueueBitClient('http://localhost:3000');
|
|
118
|
+
|
|
119
|
+
const stats = {
|
|
120
|
+
pageViews: 0,
|
|
121
|
+
clicks: 0,
|
|
122
|
+
purchases: 0
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
await collector.subscribe((message) => {
|
|
126
|
+
const { eventType, data } = message.data;
|
|
127
|
+
|
|
128
|
+
switch(eventType) {
|
|
129
|
+
case 'pageview':
|
|
130
|
+
stats.pageViews++;
|
|
131
|
+
break;
|
|
132
|
+
case 'click':
|
|
133
|
+
stats.clicks++;
|
|
134
|
+
break;
|
|
135
|
+
case 'purchase':
|
|
136
|
+
stats.purchases++;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
console.log('Stats:', stats);
|
|
141
|
+
}, { subject: 'analytics' });
|
|
142
|
+
|
|
143
|
+
// Display stats every 5 seconds
|
|
144
|
+
setInterval(() => {
|
|
145
|
+
console.log('\n=== Analytics Dashboard ===');
|
|
146
|
+
console.log(`Page Views: ${stats.pageViews}`);
|
|
147
|
+
console.log(`Clicks: ${stats.clicks}`);
|
|
148
|
+
console.log(`Purchases: ${stats.purchases}`);
|
|
149
|
+
console.log('===========================\n');
|
|
150
|
+
}, 5000);
|
|
151
|
+
|
|
152
|
+
// event-generator.js (simulate events)
|
|
153
|
+
const client = new QueueBitClient('http://localhost:3000');
|
|
154
|
+
|
|
155
|
+
setInterval(async () => {
|
|
156
|
+
const events = ['pageview', 'click', 'purchase'];
|
|
157
|
+
const eventType = events[Math.floor(Math.random() * events.length)];
|
|
158
|
+
|
|
159
|
+
await client.publish(
|
|
160
|
+
{
|
|
161
|
+
eventType,
|
|
162
|
+
data: { userId: Math.floor(Math.random() * 1000) },
|
|
163
|
+
timestamp: new Date()
|
|
164
|
+
},
|
|
165
|
+
{ subject: 'analytics' }
|
|
166
|
+
);
|
|
167
|
+
}, 100);
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Microservices Communication
|
|
173
|
+
|
|
174
|
+
Services communicate through QueueBit.
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
// user-service.js
|
|
178
|
+
const { QueueBitClient } = require('queuebit');
|
|
179
|
+
const client = new QueueBitClient('http://localhost:3000');
|
|
180
|
+
|
|
181
|
+
// Listen for user creation requests
|
|
182
|
+
await client.subscribe(async (message) => {
|
|
183
|
+
const { requestId, username, email } = message.data;
|
|
184
|
+
|
|
185
|
+
// Create user in database
|
|
186
|
+
const userId = await createUser(username, email);
|
|
187
|
+
|
|
188
|
+
// Publish user created event
|
|
189
|
+
await client.publish(
|
|
190
|
+
{ userId, username, email },
|
|
191
|
+
{ subject: 'user.created' }
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
// Send response
|
|
195
|
+
await client.publish(
|
|
196
|
+
{ requestId, success: true, userId },
|
|
197
|
+
{ subject: 'responses' }
|
|
198
|
+
);
|
|
199
|
+
}, { subject: 'user.create' });
|
|
200
|
+
|
|
201
|
+
// order-service.js
|
|
202
|
+
const client = new QueueBitClient('http://localhost:3000');
|
|
203
|
+
|
|
204
|
+
// Listen for user created events
|
|
205
|
+
await client.subscribe(async (message) => {
|
|
206
|
+
const { userId, username } = message.data;
|
|
207
|
+
|
|
208
|
+
console.log(`New user ${username} (${userId}) - initializing order history`);
|
|
209
|
+
await initializeOrderHistory(userId);
|
|
210
|
+
}, { subject: 'user.created' });
|
|
211
|
+
|
|
212
|
+
// api-gateway.js
|
|
213
|
+
const client = new QueueBitClient('http://localhost:3000');
|
|
214
|
+
|
|
215
|
+
async function createUser(username, email) {
|
|
216
|
+
const requestId = generateId();
|
|
217
|
+
|
|
218
|
+
// Listen for response
|
|
219
|
+
const responsePromise = new Promise((resolve) => {
|
|
220
|
+
client.subscribe((message) => {
|
|
221
|
+
if (message.data.requestId === requestId) {
|
|
222
|
+
resolve(message.data);
|
|
223
|
+
}
|
|
224
|
+
}, { subject: 'responses' });
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// Send request
|
|
228
|
+
await client.publish(
|
|
229
|
+
{ requestId, username, email },
|
|
230
|
+
{ subject: 'user.create' }
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
return responsePromise;
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Event Sourcing
|
|
240
|
+
|
|
241
|
+
Store all events and rebuild state.
|
|
242
|
+
|
|
243
|
+
```javascript
|
|
244
|
+
// event-store.js
|
|
245
|
+
const { QueueBitClient } = require('queuebit');
|
|
246
|
+
const client = new QueueBitClient('http://localhost:3000');
|
|
247
|
+
|
|
248
|
+
const events = [];
|
|
249
|
+
|
|
250
|
+
// Store all events
|
|
251
|
+
await client.subscribe((message) => {
|
|
252
|
+
events.push(message.data);
|
|
253
|
+
console.log(`Event stored: ${message.data.type}`);
|
|
254
|
+
}, { subject: 'events' });
|
|
255
|
+
|
|
256
|
+
// Rebuild state from events
|
|
257
|
+
function rebuildState() {
|
|
258
|
+
const state = { balance: 0, transactions: [] };
|
|
259
|
+
|
|
260
|
+
for (const event of events) {
|
|
261
|
+
switch(event.type) {
|
|
262
|
+
case 'deposit':
|
|
263
|
+
state.balance += event.amount;
|
|
264
|
+
state.transactions.push(event);
|
|
265
|
+
break;
|
|
266
|
+
case 'withdraw':
|
|
267
|
+
state.balance -= event.amount;
|
|
268
|
+
state.transactions.push(event);
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return state;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// bank-account.js
|
|
277
|
+
const client = new QueueBitClient('http://localhost:3000');
|
|
278
|
+
|
|
279
|
+
async function deposit(amount) {
|
|
280
|
+
await client.publish(
|
|
281
|
+
{
|
|
282
|
+
type: 'deposit',
|
|
283
|
+
amount,
|
|
284
|
+
timestamp: new Date(),
|
|
285
|
+
accountId: 'ACC123'
|
|
286
|
+
},
|
|
287
|
+
{ subject: 'events' }
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async function withdraw(amount) {
|
|
292
|
+
await client.publish(
|
|
293
|
+
{
|
|
294
|
+
type: 'withdraw',
|
|
295
|
+
amount,
|
|
296
|
+
timestamp: new Date(),
|
|
297
|
+
accountId: 'ACC123'
|
|
298
|
+
},
|
|
299
|
+
{ subject: 'events' }
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Usage
|
|
304
|
+
await deposit(100);
|
|
305
|
+
await withdraw(50);
|
|
306
|
+
await deposit(75);
|
|
307
|
+
|
|
308
|
+
// Rebuild state at any time
|
|
309
|
+
const state = rebuildState();
|
|
310
|
+
console.log('Current balance:', state.balance); // 125
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## More Examples
|
|
316
|
+
|
|
317
|
+
See the [examples folder](../examples/) for:
|
|
318
|
+
- Browser-based example with UI
|
|
319
|
+
- Performance testing
|
|
320
|
+
- Advanced patterns
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## Tips
|
|
325
|
+
|
|
326
|
+
1. **Use subjects** to organize message types
|
|
327
|
+
2. **Queue groups** for scalable processing
|
|
328
|
+
3. **Store event IDs** to prevent duplicate processing
|
|
329
|
+
4. **Set expiry** for temporary messages
|
|
330
|
+
5. **Monitor performance** with the test harness
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# QueueBit Quick Start Guide
|
|
2
|
+
|
|
3
|
+
Get started with QueueBit in 5 minutes!
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install queuebit
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Start the Server
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
// server.js
|
|
15
|
+
const { QueueBitServer } = require('queuebit');
|
|
16
|
+
|
|
17
|
+
const server = new QueueBitServer({ port: 3000 });
|
|
18
|
+
console.log('QueueBit server running on port 3000');
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Run it:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
node server.js
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Publisher Example
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
// publisher.js
|
|
31
|
+
const { QueueBitClient } = require('queuebit');
|
|
32
|
+
|
|
33
|
+
const client = new QueueBitClient('http://localhost:3000');
|
|
34
|
+
|
|
35
|
+
// Wait for connection
|
|
36
|
+
setTimeout(async () => {
|
|
37
|
+
// Publish a message
|
|
38
|
+
await client.publish({
|
|
39
|
+
message: 'Hello, QueueBit!',
|
|
40
|
+
timestamp: new Date()
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
console.log('Message published!');
|
|
44
|
+
}, 1000);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Subscriber Example
|
|
48
|
+
|
|
49
|
+
```javascript
|
|
50
|
+
// subscriber.js
|
|
51
|
+
const { QueueBitClient } = require('queuebit');
|
|
52
|
+
|
|
53
|
+
const client = new QueueBitClient('http://localhost:3000');
|
|
54
|
+
|
|
55
|
+
// Subscribe to messages
|
|
56
|
+
client.subscribe((message) => {
|
|
57
|
+
console.log('Received:', message.data);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
console.log('Waiting for messages...');
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Run the Examples
|
|
64
|
+
|
|
65
|
+
Open three terminals:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Terminal 1: Start server
|
|
69
|
+
node server.js
|
|
70
|
+
|
|
71
|
+
# Terminal 2: Start subscriber
|
|
72
|
+
node subscriber.js
|
|
73
|
+
|
|
74
|
+
# Terminal 3: Publish messages
|
|
75
|
+
node publisher.js
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Next Steps
|
|
79
|
+
|
|
80
|
+
- Read the [API Documentation](./API.md)
|
|
81
|
+
- Check out [Examples](./EXAMPLES.md)
|
|
82
|
+
- See the [browser example](../examples/browser-example.html)
|
|
83
|
+
|
|
84
|
+
## Common Patterns
|
|
85
|
+
|
|
86
|
+
### Work Queue
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
// Multiple workers process tasks in parallel
|
|
90
|
+
await worker.subscribe((message) => {
|
|
91
|
+
processTask(message.data);
|
|
92
|
+
}, { subject: 'tasks', queue: 'workers' });
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Pub/Sub
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
// All subscribers receive every message
|
|
99
|
+
await subscriber.subscribe((message) => {
|
|
100
|
+
handleEvent(message.data);
|
|
101
|
+
}, { subject: 'events' });
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Request/Response
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
// Send request and wait for response
|
|
108
|
+
const requestId = generateId();
|
|
109
|
+
|
|
110
|
+
await client.subscribe((msg) => {
|
|
111
|
+
if (msg.data.requestId === requestId) {
|
|
112
|
+
console.log('Response:', msg.data);
|
|
113
|
+
}
|
|
114
|
+
}, { subject: 'responses' });
|
|
115
|
+
|
|
116
|
+
await client.publish(
|
|
117
|
+
{ requestId, data: 'request' },
|
|
118
|
+
{ subject: 'requests' }
|
|
119
|
+
);
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Happy queuing! 🚀
|