queen-mq 0.2.0 → 0.2.22
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 +186 -763
- package/{src → client-js}/benchmark/consumer.js +6 -4
- package/{src → client-js}/benchmark/producer.js +9 -4
- package/{src → client-js}/client/client.js +277 -7
- package/{src → client-js}/client/index.js +1 -4
- package/{src → client-js}/client/utils/http.js +3 -2
- package/{src → client-js}/client/utils/retry.js +7 -1
- package/{src → client-js}/test/README.md +30 -9
- package/{src → client-js}/test/core-tests.js +7 -2
- package/{src → client-js}/test/edge-case-tests.js +2 -1
- package/client-js/test/human.js +162 -0
- package/client-js/test/partition-transaction-tests.js +482 -0
- package/client-js/test/qos0-tests.js +334 -0
- package/{src → client-js}/test/test-new.js +55 -0
- package/package.json +8 -17
- package/init-db.js +0 -20
- package/src/cluster-server.js +0 -242
- package/src/config.js +0 -229
- package/src/database/connection.js +0 -129
- package/src/database/poolManager.js +0 -199
- package/src/database/schema-v2.sql +0 -278
- package/src/managers/eventManager.js +0 -59
- package/src/managers/queueManagerOptimized.js +0 -1634
- package/src/managers/resourceCache.js +0 -96
- package/src/managers/systemEventManager.js +0 -132
- package/src/routes/ack.js +0 -26
- package/src/routes/configure.js +0 -46
- package/src/routes/messages.js +0 -368
- package/src/routes/pop.js +0 -69
- package/src/routes/push.js +0 -28
- package/src/routes/resources.js +0 -330
- package/src/routes/status.js +0 -1037
- package/src/server.js +0 -1633
- package/src/test/MIGRATION_ISSUES.md +0 -174
- package/src/test/test.js +0 -4524
- package/src/utils/streaming.js +0 -231
- package/src/webapp-dist/assets/Analytics-DJrE4Rz2.css +0 -1
- package/src/webapp-dist/assets/Analytics-HEMXKmfJ.js +0 -1
- package/src/webapp-dist/assets/ConfirmDialog-YEoCdE7x.js +0 -1
- package/src/webapp-dist/assets/ConsumerGroups-CC5VJywp.css +0 -1
- package/src/webapp-dist/assets/ConsumerGroups-D8Z20HhZ.js +0 -1
- package/src/webapp-dist/assets/Dashboard-BRFOz6it.css +0 -1
- package/src/webapp-dist/assets/Dashboard-Bpx9I32h.js +0 -1
- package/src/webapp-dist/assets/LoadingSpinner-BPttXcbs.js +0 -1
- package/src/webapp-dist/assets/Messages-BOfVHKma.css +0 -1
- package/src/webapp-dist/assets/Messages-EKURCbLl.js +0 -1
- package/src/webapp-dist/assets/QueueDetail-BXXA7xoZ.css +0 -1
- package/src/webapp-dist/assets/QueueDetail-Bmxg0KiA.js +0 -1
- package/src/webapp-dist/assets/Queues-CvrJkrZT.css +0 -1
- package/src/webapp-dist/assets/Queues-yUx9_3-9.js +0 -1
- package/src/webapp-dist/assets/StatusBadge-C1bBtXHh.css +0 -1
- package/src/webapp-dist/assets/StatusBadge-C6N84XmO.js +0 -1
- package/src/webapp-dist/assets/analytics-BapTekLM.js +0 -1
- package/src/webapp-dist/assets/colors-5z6Q_kUr.js +0 -18
- package/src/webapp-dist/assets/index-B7w2bKT6.css +0 -1
- package/src/webapp-dist/assets/index-CUSnwYTH.js +0 -31
- package/src/webapp-dist/assets/messages-CRV6E-xU.js +0 -1
- package/src/webapp-dist/assets/queen-logo-blue.svg +0 -210
- package/src/webapp-dist/assets/queen-logo-cyan.svg +0 -210
- package/src/webapp-dist/assets/queen-logo-indigo.svg +0 -210
- package/src/webapp-dist/assets/queen-logo-orange.svg +0 -210
- package/src/webapp-dist/assets/queen-logo-pink.svg +0 -210
- package/src/webapp-dist/assets/queen-logo-purple.svg +0 -210
- package/src/webapp-dist/assets/queen-logo-rose.svg +0 -239
- package/src/webapp-dist/assets/queen-logo.svg +0 -263
- package/src/webapp-dist/assets/queues-BdUbxfBC.js +0 -1
- package/src/webapp-dist/assets/resources-Bs9U-ceF.js +0 -1
- package/src/webapp-dist/index.html +0 -15
- package/src/websocket/wsServer.js +0 -228
- /package/{src → client-js}/benchmark/consumer_multi.js +0 -0
- /package/{src → client-js}/benchmark/producer_multi.js +0 -0
- /package/{src → client-js}/client/utils/loadBalancer.js +0 -0
- /package/{src → client-js}/services/encryptionService.js +0 -0
- /package/{src → client-js}/services/evictionService.js +0 -0
- /package/{src → client-js}/services/retentionService.js +0 -0
- /package/{src → client-js}/services/startupSync.js +0 -0
- /package/{src → client-js}/test/advanced-client-tests.js +0 -0
- /package/{src → client-js}/test/advanced-pattern-tests.js +0 -0
- /package/{src → client-js}/test/bus-mode-tests.js +0 -0
- /package/{src → client-js}/test/enterprise-tests.js +0 -0
- /package/{src → client-js}/test/partition-locking-tests.js +0 -0
- /package/{src → client-js}/test/utils.js +0 -0
- /package/{src → client-js}/test/window-buffer-test.js +0 -0
- /package/{src → client-js}/utils/logger.js +0 -0
- /package/{src → client-js}/utils/uuid.js +0 -0
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
import { generateUUID } from '../utils/uuid.js';
|
|
2
|
-
import config from '../config.js';
|
|
3
|
-
|
|
4
|
-
export const createWebSocketServer = (app, eventManager) => {
|
|
5
|
-
const connections = new Map();
|
|
6
|
-
|
|
7
|
-
// Broadcast event to all connected clients
|
|
8
|
-
const broadcast = (event, data) => {
|
|
9
|
-
const message = JSON.stringify({ event, data, timestamp: new Date().toISOString() });
|
|
10
|
-
|
|
11
|
-
for (const [id, ws] of connections) {
|
|
12
|
-
try {
|
|
13
|
-
ws.send(message);
|
|
14
|
-
} catch (error) {
|
|
15
|
-
console.error(`Failed to send to client ${id}:`, error);
|
|
16
|
-
connections.delete(id);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
// Setup WebSocket route
|
|
22
|
-
app.ws('/ws/dashboard', {
|
|
23
|
-
compression: config.WEBSOCKET.COMPRESSION,
|
|
24
|
-
maxPayloadLength: config.WEBSOCKET.MAX_PAYLOAD_LENGTH,
|
|
25
|
-
idleTimeout: config.WEBSOCKET.IDLE_TIMEOUT,
|
|
26
|
-
|
|
27
|
-
open: (ws) => {
|
|
28
|
-
const connectionId = generateUUID();
|
|
29
|
-
connections.set(connectionId, ws);
|
|
30
|
-
ws.connectionId = connectionId;
|
|
31
|
-
|
|
32
|
-
console.log(`WebSocket client connected: ${connectionId}`);
|
|
33
|
-
|
|
34
|
-
// Send welcome message
|
|
35
|
-
ws.send(JSON.stringify({
|
|
36
|
-
event: 'connected',
|
|
37
|
-
data: {
|
|
38
|
-
connectionId,
|
|
39
|
-
version: 'v2'
|
|
40
|
-
},
|
|
41
|
-
timestamp: new Date().toISOString()
|
|
42
|
-
}));
|
|
43
|
-
|
|
44
|
-
broadcast('client.connected', { clientId: connectionId });
|
|
45
|
-
},
|
|
46
|
-
|
|
47
|
-
message: (ws, message, isBinary) => {
|
|
48
|
-
// Handle ping/pong
|
|
49
|
-
const msg = Buffer.from(message).toString();
|
|
50
|
-
if (msg === 'ping') {
|
|
51
|
-
ws.send('pong');
|
|
52
|
-
} else {
|
|
53
|
-
// Handle subscription requests
|
|
54
|
-
try {
|
|
55
|
-
const data = JSON.parse(msg);
|
|
56
|
-
if (data.type === 'subscribe') {
|
|
57
|
-
// Store subscription preferences (could be used for filtering)
|
|
58
|
-
ws.subscriptions = data.queues || [];
|
|
59
|
-
ws.send(JSON.stringify({
|
|
60
|
-
event: 'subscribed',
|
|
61
|
-
data: { queues: ws.subscriptions },
|
|
62
|
-
timestamp: new Date().toISOString()
|
|
63
|
-
}));
|
|
64
|
-
}
|
|
65
|
-
} catch (error) {
|
|
66
|
-
// Invalid JSON, ignore
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
},
|
|
70
|
-
|
|
71
|
-
close: (ws, code, message) => {
|
|
72
|
-
const connectionId = ws.connectionId;
|
|
73
|
-
connections.delete(connectionId);
|
|
74
|
-
console.log(`WebSocket client disconnected: ${connectionId}`);
|
|
75
|
-
broadcast('client.disconnected', { clientId: connectionId });
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
// Subscribe to queue events - Updated for V2 structure
|
|
80
|
-
eventManager.on('message.pushed', (data) => {
|
|
81
|
-
broadcast('message.pushed', {
|
|
82
|
-
queue: data.queue,
|
|
83
|
-
partition: data.partition,
|
|
84
|
-
transactionId: data.transactionId
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
eventManager.on('message.processing', (data) => {
|
|
89
|
-
broadcast('message.processing', {
|
|
90
|
-
queue: data.queue,
|
|
91
|
-
partition: data.partition,
|
|
92
|
-
transactionId: data.transactionId,
|
|
93
|
-
workerId: data.workerId
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
eventManager.on('message.completed', (data) => {
|
|
98
|
-
broadcast('message.completed', {
|
|
99
|
-
transactionId: data.transactionId
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
eventManager.on('message.failed', (data) => {
|
|
104
|
-
broadcast('message.failed', {
|
|
105
|
-
transactionId: data.transactionId,
|
|
106
|
-
error: data.error
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
eventManager.on('queue.created', (data) => {
|
|
111
|
-
broadcast('queue.created', {
|
|
112
|
-
queue: data.queue,
|
|
113
|
-
partition: data.partition ?? 'Default'
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
// Periodic queue depth updates - Updated for V2
|
|
118
|
-
const updateQueueDepths = async (queueManager) => {
|
|
119
|
-
try {
|
|
120
|
-
const stats = await queueManager.getQueueStats();
|
|
121
|
-
|
|
122
|
-
// Group by queue for aggregated depths
|
|
123
|
-
const queueDepths = {};
|
|
124
|
-
|
|
125
|
-
for (const stat of stats) {
|
|
126
|
-
if (!queueDepths[stat.queue]) {
|
|
127
|
-
queueDepths[stat.queue] = {
|
|
128
|
-
queue: stat.queue,
|
|
129
|
-
namespace: stat.namespace,
|
|
130
|
-
task: stat.task,
|
|
131
|
-
totalDepth: 0,
|
|
132
|
-
totalProcessing: 0,
|
|
133
|
-
partitions: {}
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Skip consumer group specific stats for queue depth calculation
|
|
138
|
-
// Only count NULL consumer_group (queue mode) stats
|
|
139
|
-
if (stat.consumer_group) continue;
|
|
140
|
-
|
|
141
|
-
// Initialize partition if not exists
|
|
142
|
-
if (!queueDepths[stat.queue].partitions[stat.partition]) {
|
|
143
|
-
queueDepths[stat.queue].partitions[stat.partition] = {
|
|
144
|
-
depth: 0,
|
|
145
|
-
processing: 0,
|
|
146
|
-
completed: 0,
|
|
147
|
-
failed: 0
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Add partition stats (using direct field names from new schema)
|
|
152
|
-
const partitionStats = queueDepths[stat.queue].partitions[stat.partition];
|
|
153
|
-
partitionStats.depth += parseInt(stat.pending || 0);
|
|
154
|
-
partitionStats.processing += parseInt(stat.processing || 0);
|
|
155
|
-
partitionStats.completed += parseInt(stat.completed || 0);
|
|
156
|
-
partitionStats.failed += parseInt(stat.failed || 0);
|
|
157
|
-
|
|
158
|
-
// Update totals
|
|
159
|
-
queueDepths[stat.queue].totalDepth += parseInt(stat.pending || 0);
|
|
160
|
-
queueDepths[stat.queue].totalProcessing += parseInt(stat.processing || 0);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// Broadcast aggregated queue depths
|
|
164
|
-
for (const queueData of Object.values(queueDepths)) {
|
|
165
|
-
broadcast('queue.depth', queueData);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Also broadcast individual partition depths for detailed monitoring
|
|
169
|
-
for (const stat of stats) {
|
|
170
|
-
// Skip consumer group specific stats
|
|
171
|
-
if (stat.consumer_group) continue;
|
|
172
|
-
|
|
173
|
-
broadcast('partition.depth', {
|
|
174
|
-
queue: stat.queue,
|
|
175
|
-
partition: stat.partition,
|
|
176
|
-
depth: parseInt(stat.pending || 0),
|
|
177
|
-
processing: parseInt(stat.processing || 0),
|
|
178
|
-
completed: parseInt(stat.completed || 0),
|
|
179
|
-
failed: parseInt(stat.failed || 0),
|
|
180
|
-
total: parseInt(stat.total_messages || 0)
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
} catch (error) {
|
|
185
|
-
console.error('Error updating queue depths:', error);
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
// Send system stats periodically
|
|
190
|
-
const sendSystemStats = async (pool) => {
|
|
191
|
-
try {
|
|
192
|
-
const result = await pool.query(`
|
|
193
|
-
SELECT
|
|
194
|
-
(SELECT COALESCE(SUM(pending_estimate), 0)::integer FROM queen.partition_consumers
|
|
195
|
-
WHERE consumer_group = '__QUEUE_MODE__') as pending,
|
|
196
|
-
(SELECT COUNT(*) FROM queen.partition_consumers
|
|
197
|
-
WHERE consumer_group = '__QUEUE_MODE__'
|
|
198
|
-
AND lease_expires_at IS NOT NULL
|
|
199
|
-
AND lease_expires_at > NOW()) as processing,
|
|
200
|
-
(SELECT COUNT(*) FROM queen.messages WHERE created_at > NOW() - INTERVAL '1 minute') as recent_created,
|
|
201
|
-
(SELECT COALESCE(SUM(CASE WHEN last_consumed_at > NOW() - INTERVAL '1 minute'
|
|
202
|
-
THEN total_batches_consumed ELSE 0 END), 0)::integer
|
|
203
|
-
FROM queen.partition_consumers
|
|
204
|
-
WHERE consumer_group = '__QUEUE_MODE__') as recent_completed
|
|
205
|
-
`);
|
|
206
|
-
|
|
207
|
-
const stats = result.rows[0];
|
|
208
|
-
|
|
209
|
-
broadcast('system.stats', {
|
|
210
|
-
pending: parseInt(stats.pending || 0),
|
|
211
|
-
processing: parseInt(stats.processing || 0),
|
|
212
|
-
recentCreated: parseInt(stats.recent_created || 0),
|
|
213
|
-
recentCompleted: parseInt(stats.recent_completed || 0),
|
|
214
|
-
connections: connections.size
|
|
215
|
-
});
|
|
216
|
-
} catch (error) {
|
|
217
|
-
console.error('Error sending system stats:', error);
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
return {
|
|
222
|
-
broadcast,
|
|
223
|
-
updateQueueDepths,
|
|
224
|
-
sendSystemStats,
|
|
225
|
-
getConnectionCount: () => connections.size,
|
|
226
|
-
getConnections: () => Array.from(connections.keys())
|
|
227
|
-
};
|
|
228
|
-
};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|