queen-mq 0.6.3 → 0.7.4

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.
Files changed (48) hide show
  1. package/README.md +500 -327
  2. package/{client-js/client-v2 → client-v2}/Queen.js +5 -2
  3. package/{client-js/client-v2 → client-v2}/README.md +53 -2
  4. package/{client-js/client-v2 → client-v2}/builders/QueueBuilder.js +24 -1
  5. package/{client-js/client-v2 → client-v2}/consumer/ConsumerManager.js +25 -4
  6. package/{client-js/client-v2 → client-v2}/http/HttpClient.js +24 -12
  7. package/client-v2/http/LoadBalancer.js +271 -0
  8. package/{client-js/client-v2 → client-v2}/utils/defaults.js +4 -2
  9. package/package.json +6 -8
  10. package/{client-js/test-v2 → test-v2}/maintenance.js +1 -1
  11. package/LICENSE.md +0 -202
  12. package/client-js/benchmark/consumer.js +0 -209
  13. package/client-js/benchmark/consumer_multi.js +0 -216
  14. package/client-js/benchmark/producer.js +0 -80
  15. package/client-js/benchmark/producer_multi.js +0 -115
  16. package/client-js/client-v2/http/LoadBalancer.js +0 -50
  17. /package/{client-js/client-v2 → client-v2}/LOGGING.md +0 -0
  18. /package/{client-js/client-v2 → client-v2}/buffer/BufferManager.js +0 -0
  19. /package/{client-js/client-v2 → client-v2}/buffer/MessageBuffer.js +0 -0
  20. /package/{client-js/client-v2 → client-v2}/builders/TransactionBuilder.js +0 -0
  21. /package/{client-js/client-v2 → client-v2}/index.js +0 -0
  22. /package/{client-js/client-v2 → client-v2}/stream/StreamBuilder.js +0 -0
  23. /package/{client-js/client-v2 → client-v2}/stream/StreamConsumer.js +0 -0
  24. /package/{client-js/client-v2 → client-v2}/stream/Window.js +0 -0
  25. /package/{client-js/client-v2 → client-v2}/utils/logger.js +0 -0
  26. /package/{client-js/client-v2 → client-v2}/utils/validation.js +0 -0
  27. /package/{client-js/test-v2 → test-v2}/AI_TEST_SUMMARY.md +0 -0
  28. /package/{client-js/test-v2 → test-v2}/GETTING_STARTED.md +0 -0
  29. /package/{client-js/test-v2 → test-v2}/MAINTENANCE_TEST.md +0 -0
  30. /package/{client-js/test-v2 → test-v2}/README_SUBSCRIPTION_TESTS.md +0 -0
  31. /package/{client-js/test-v2 → test-v2}/ai_buffering.js +0 -0
  32. /package/{client-js/test-v2 → test-v2}/ai_error_handling.js +0 -0
  33. /package/{client-js/test-v2 → test-v2}/ai_lease_renewal.js +0 -0
  34. /package/{client-js/test-v2 → test-v2}/ai_mixed_scenarios.js +0 -0
  35. /package/{client-js/test-v2 → test-v2}/ai_priority.js +0 -0
  36. /package/{client-js/test-v2 → test-v2}/ai_resources.js +0 -0
  37. /package/{client-js/test-v2 → test-v2}/ai_ttl_retention.js +0 -0
  38. /package/{client-js/test-v2 → test-v2}/complete.js +0 -0
  39. /package/{client-js/test-v2 → test-v2}/consume.js +0 -0
  40. /package/{client-js/test-v2 → test-v2}/dlq.js +0 -0
  41. /package/{client-js/test-v2 → test-v2}/load.js +0 -0
  42. /package/{client-js/test-v2 → test-v2}/pop.js +0 -0
  43. /package/{client-js/test-v2 → test-v2}/push.js +0 -0
  44. /package/{client-js/test-v2 → test-v2}/queue.js +0 -0
  45. /package/{client-js/test-v2 → test-v2}/retention.js +0 -0
  46. /package/{client-js/test-v2 → test-v2}/run.js +0 -0
  47. /package/{client-js/test-v2 → test-v2}/subscription.js +0 -0
  48. /package/{client-js/test-v2 → test-v2}/transaction.js +0 -0
@@ -1,80 +0,0 @@
1
- import { Queen } from '../client/client.js';
2
- import fs from 'fs';
3
-
4
- const TOTAL_MESSAGES = 1000000;
5
- const PARTITIONS = 10;
6
- const MAX_BATCH_SIZE = 100; // Reduced from 10000
7
- const PUSH_PARALLEL = 10; // Reduced from 10 to avoid lock contention
8
- const QUEUE_NAME = 'benchmark-queue-001';
9
-
10
- const q = new Queen({
11
- baseUrls: ['http://localhost:6632'],
12
- timeout: 120000
13
- });
14
-
15
-
16
- try {
17
- await q.queueDelete(QUEUE_NAME);
18
- await q.queue(QUEUE_NAME, {
19
- leaseTime: 10,
20
- retryLimit: 3
21
- }, { namespace: 'benchmark' });
22
- } catch (e) {
23
- console.error(e);
24
- }
25
-
26
-
27
-
28
- let batches = []
29
- const messagesPerPartition = Math.floor(TOTAL_MESSAGES / PARTITIONS);
30
-
31
- // Create batches for each partition
32
- const partitionBatches = [];
33
- for (let i = 0; i < PARTITIONS; i++) {
34
- partitionBatches[i] = [];
35
- let messages = [];
36
- for (let j = 0; j < messagesPerPartition; j++) {
37
- messages.push({
38
- id: j,
39
- //message: `Message ${globalMessageId}`,
40
- //timestamp: new Date().toISOString()
41
- });
42
- if (messages.length >= MAX_BATCH_SIZE) {
43
- console.log(`Pushing ${messages.length} messages for partition ${i}`);
44
- partitionBatches[i].push({
45
- partition: i,
46
- messages: messages
47
- });
48
- messages = [];
49
- }
50
- }
51
- // Only add the remaining batch if it has messages
52
- if (messages.length > 0) {
53
- console.log(`Pushing ${messages.length} messages for partition ${i}`);
54
- partitionBatches[i].push({
55
- partition: i,
56
- messages: messages
57
- });
58
- }
59
- }
60
-
61
- // Interleave batches from different partitions to avoid lock contention
62
- // This ensures parallel pushes go to different partitions
63
- const maxBatchesPerPartition = Math.max(...partitionBatches.map(pb => pb.length));
64
- for (let batchIndex = 0; batchIndex < maxBatchesPerPartition; batchIndex++) {
65
- for (let partition = 0; partition < PARTITIONS; partition++) {
66
- if (partitionBatches[partition][batchIndex]) {
67
- batches.push(partitionBatches[partition][batchIndex]);
68
- }
69
- }
70
- }
71
-
72
- const start = Date.now();
73
- console.log(`Total batches: ${batches.length}, pushing ${PUSH_PARALLEL} at a time`);
74
- for (let i = 0; i < batches.length; i += PUSH_PARALLEL) {
75
- const batchGroup = batches.slice(i, i + PUSH_PARALLEL);
76
- console.log(`Pushing batch group ${Math.floor(i/PUSH_PARALLEL) + 1}/${Math.ceil(batches.length/PUSH_PARALLEL)}: ${batchGroup.map(b => `partition ${b.partition} (${b.messages.length} msgs)`).join(', ')}`);
77
- await Promise.all(batchGroup.map(batch => q.push(`${QUEUE_NAME}/${batch.partition}`, batch.messages)));
78
- }
79
- const end = Date.now();
80
- console.log(`Pushed ${TOTAL_MESSAGES} messages in ${(end - start) / 1000}s, ${(TOTAL_MESSAGES / ((end - start) / 1000)).toFixed(2)} msg/s`);
@@ -1,115 +0,0 @@
1
- import { Queen } from '../client/client.js';
2
- import fs from 'fs';
3
-
4
- const TOTAL_MESSAGES = 100000;
5
- const NUM_QUEUES = 50; // X: Number of queues
6
- const PARTITIONS_PER_QUEUE = 10; // Y: Partitions per queue
7
- const MAX_BATCH_SIZE = 10;
8
- const PUSH_PARALLEL = 10;
9
-
10
- const q = new Queen({
11
- baseUrls: ['http://localhost:6632'],
12
- timeout: 120000
13
- });
14
-
15
- // Create X queues, each with Y partitions, all in 'benchmark' namespace
16
- console.log(`Creating ${NUM_QUEUES} queues with ${PARTITIONS_PER_QUEUE} partitions each...`);
17
- for (let queueIdx = 0; queueIdx < NUM_QUEUES; queueIdx++) {
18
- const queueName = `benchmark-queue-${String(queueIdx + 1).padStart(2, '0')}`;
19
- try {
20
- //await q.queueDelete(queueName);
21
- } catch (e) {
22
- // Queue might not exist
23
- }
24
- await q.queue(queueName, {
25
- leaseTime: 10,
26
- retryLimit: 3
27
- }, { namespace: 'benchmark' });
28
- console.log(` Created queue: ${queueName}`);
29
- }
30
-
31
-
32
- // Calculate total partitions across all queues
33
- const TOTAL_PARTITIONS = NUM_QUEUES * PARTITIONS_PER_QUEUE;
34
- const messagesPerPartition = Math.floor(TOTAL_MESSAGES / TOTAL_PARTITIONS);
35
-
36
- console.log(`\nDistributing ${TOTAL_MESSAGES} messages across ${NUM_QUEUES} queues × ${PARTITIONS_PER_QUEUE} partitions = ${TOTAL_PARTITIONS} total partitions`);
37
- console.log(`Messages per partition: ${messagesPerPartition}\n`);
38
-
39
- // Create batches for each queue/partition combination
40
- const queuePartitionBatches = [];
41
- for (let queueIdx = 0; queueIdx < NUM_QUEUES; queueIdx++) {
42
- for (let partitionIdx = 0; partitionIdx < PARTITIONS_PER_QUEUE; partitionIdx++) {
43
- const key = `q${queueIdx}_p${partitionIdx}`;
44
- queuePartitionBatches.push({ queueIdx, partitionIdx, batches: [] });
45
-
46
- let messages = [];
47
- for (let msgIdx = 0; msgIdx < messagesPerPartition; msgIdx++) {
48
- messages.push({
49
- id: msgIdx,
50
- queue: queueIdx,
51
- partition: partitionIdx
52
- });
53
-
54
- if (messages.length >= MAX_BATCH_SIZE) {
55
- queuePartitionBatches[queuePartitionBatches.length - 1].batches.push([...messages]);
56
- messages = [];
57
- }
58
- }
59
-
60
- // Add remaining messages
61
- if (messages.length > 0) {
62
- queuePartitionBatches[queuePartitionBatches.length - 1].batches.push([...messages]);
63
- }
64
- }
65
- }
66
-
67
- // Flatten and interleave batches to distribute load evenly
68
- let batches = [];
69
- const maxBatchesPerQueuePartition = Math.max(...queuePartitionBatches.map(qp => qp.batches.length));
70
- for (let batchIdx = 0; batchIdx < maxBatchesPerQueuePartition; batchIdx++) {
71
- for (const qp of queuePartitionBatches) {
72
- if (qp.batches[batchIdx]) {
73
- batches.push({
74
- queueIdx: qp.queueIdx,
75
- partitionIdx: qp.partitionIdx,
76
- messages: qp.batches[batchIdx]
77
- });
78
- }
79
- }
80
- }
81
-
82
- const start = Date.now();
83
- console.log(`Total batches: ${batches.length}, pushing ${PUSH_PARALLEL} at a time\n`);
84
-
85
- for (let i = 0; i < batches.length; i += PUSH_PARALLEL) {
86
- const batchGroup = batches.slice(i, i + PUSH_PARALLEL);
87
- const batchGroupNum = Math.floor(i/PUSH_PARALLEL) + 1;
88
- const totalBatchGroups = Math.ceil(batches.length/PUSH_PARALLEL);
89
-
90
- console.log(`[${batchGroupNum}/${totalBatchGroups}] Pushing: ${batchGroup.map(b => {
91
- const queueName = `benchmark-queue-${String(b.queueIdx + 1).padStart(2, '0')}`;
92
- return `${queueName}/p${b.partitionIdx} (${b.messages.length} msgs)`;
93
- }).join(', ')}`);
94
-
95
- await Promise.all(batchGroup.map(batch => {
96
- const queueName = `benchmark-queue-${String(batch.queueIdx + 1).padStart(2, '0')}`;
97
- return q.push(`${queueName}/${batch.partitionIdx}`, batch.messages);
98
- }));
99
- }
100
-
101
- const end = Date.now();
102
- const duration = (end - start) / 1000;
103
- const throughput = (TOTAL_MESSAGES / duration).toFixed(2);
104
-
105
- console.log('\n' + '='.repeat(80));
106
- console.log('📤 PRODUCER RESULTS');
107
- console.log('='.repeat(80));
108
- console.log(`Total Messages Pushed: ${TOTAL_MESSAGES.toLocaleString()}`);
109
- console.log(`Queues: ${NUM_QUEUES}`);
110
- console.log(`Partitions per Queue: ${PARTITIONS_PER_QUEUE}`);
111
- console.log(`Total Partitions: ${TOTAL_PARTITIONS}`);
112
- console.log(`Duration: ${duration.toFixed(2)}s`);
113
- console.log(`Throughput: ${throughput} msg/s`);
114
- console.log('='.repeat(80));
115
-
@@ -1,50 +0,0 @@
1
- /**
2
- * Load balancer for distributing requests across multiple servers
3
- */
4
-
5
- export class LoadBalancer {
6
- #urls
7
- #strategy
8
- #currentIndex = 0
9
- #sessionMap = new Map()
10
- #sessionId
11
-
12
- constructor(urls, strategy = 'round-robin') {
13
- this.#urls = urls.map(url => url.replace(/\/$/, '')) // Remove trailing slashes
14
- this.#strategy = strategy
15
- this.#sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
16
- }
17
-
18
- getNextUrl(sessionKey = null) {
19
- const key = sessionKey || this.#sessionId
20
-
21
- if (this.#strategy === 'session') {
22
- // Session affinity: stick to the same server per session
23
- if (!this.#sessionMap.has(key)) {
24
- const assignedIndex = this.#currentIndex
25
- this.#sessionMap.set(key, assignedIndex)
26
- this.#currentIndex = (this.#currentIndex + 1) % this.#urls.length
27
- }
28
- return this.#urls[this.#sessionMap.get(key)]
29
- }
30
-
31
- // Round robin: cycle through URLs
32
- const url = this.#urls[this.#currentIndex]
33
- this.#currentIndex = (this.#currentIndex + 1) % this.#urls.length
34
- return url
35
- }
36
-
37
- getAllUrls() {
38
- return [...this.#urls]
39
- }
40
-
41
- getStrategy() {
42
- return this.#strategy
43
- }
44
-
45
- reset() {
46
- this.#currentIndex = 0
47
- this.#sessionMap.clear()
48
- }
49
- }
50
-
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