@pingpolls/redisq 0.1.0 ā 0.2.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/README.md +18 -7
- package/app.test.ts +59 -14
- package/app.ts +36 -44
- package/benchmark/medium.txt +1 -0
- package/benchmark/small.txt +1 -0
- package/benchmark/stress-worker.ts +21 -8
- package/benchmark/stress.ts +43 -38
- package/benchmark/tiny.txt +1 -0
- package/biome.json +0 -1
- package/compose.yml +5 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# RedisQ
|
|
2
2
|
|
|
3
3
|
A lightweight, type-safe Redis-based message queue for Bun with support for delayed messages, retries, and batch processing.
|
|
4
4
|
|
|
@@ -754,17 +754,28 @@ describe('Queue Tests', () => {
|
|
|
754
754
|
Run the stress test to benchmark on your hardware:
|
|
755
755
|
|
|
756
756
|
```bash
|
|
757
|
-
bun
|
|
757
|
+
bun stress
|
|
758
758
|
```
|
|
759
759
|
|
|
760
|
-
|
|
761
|
-
- **
|
|
762
|
-
- **
|
|
763
|
-
- **
|
|
764
|
-
|
|
760
|
+
Individual Queue Performance:
|
|
761
|
+
- **Tiny messages (100B)**: 47181 msg/s (p50: 49.97ms)
|
|
762
|
+
- **Small messages (1KB)**: 33709 msg/s (p50: 69.05ms)
|
|
763
|
+
- **Medium messages (10KB)**: 4056 msg/s (p50: 261.32ms)
|
|
764
|
+
|
|
765
|
+
Overall:
|
|
766
|
+
- **Throughput**: ~28,315 messages/second
|
|
767
|
+
- **Latency (p50)**: 126.78 ms
|
|
768
|
+
- **Latency (p95)**: 299.27 ms
|
|
769
|
+
- **Latency (p99)**: 383.86 ms
|
|
770
|
+
|
|
771
|
+
Tested on Dockerized `redis:alpine` through WSL2 with 1 CPU and 1GB instance.
|
|
765
772
|
|
|
766
773
|
*Results may vary based on hardware, Redis configuration, and network conditions.*
|
|
767
774
|
|
|
775
|
+
## Contributing
|
|
776
|
+
|
|
777
|
+
Check our github repository [here](https://github.com/pingpolls/redisq).
|
|
778
|
+
|
|
768
779
|
## License
|
|
769
780
|
|
|
770
781
|
Apache License 2.0
|
package/app.test.ts
CHANGED
|
@@ -22,7 +22,7 @@ describe("RedisQueue Tests", () => {
|
|
|
22
22
|
|
|
23
23
|
await queue.createQueue({ qname: "test-basic" });
|
|
24
24
|
|
|
25
|
-
const message =
|
|
25
|
+
const message = JSON.stringify({ id: 1, name: "John Doe" });
|
|
26
26
|
let receivedCount = 0;
|
|
27
27
|
|
|
28
28
|
const id = await queue.sendMessage({
|
|
@@ -61,9 +61,9 @@ describe("RedisQueue Tests", () => {
|
|
|
61
61
|
|
|
62
62
|
const sentAt = Date.now();
|
|
63
63
|
const id = await queue.sendMessage({
|
|
64
|
+
delay: delayMs,
|
|
64
65
|
message,
|
|
65
66
|
qname: "test-delayed",
|
|
66
|
-
delay: delayMs,
|
|
67
67
|
});
|
|
68
68
|
|
|
69
69
|
await new Promise<void>((resolve) => {
|
|
@@ -100,9 +100,9 @@ describe("RedisQueue Tests", () => {
|
|
|
100
100
|
const queue = new RedisQueue(redisConfig);
|
|
101
101
|
|
|
102
102
|
await queue.createQueue({
|
|
103
|
-
qname: "test-retry",
|
|
104
|
-
maxRetries: 3,
|
|
105
103
|
maxBackoffSeconds: 1,
|
|
104
|
+
maxRetries: 3,
|
|
105
|
+
qname: "test-retry",
|
|
106
106
|
});
|
|
107
107
|
|
|
108
108
|
const message = "Retry me!";
|
|
@@ -144,9 +144,9 @@ describe("RedisQueue Tests", () => {
|
|
|
144
144
|
const queue = new RedisQueue(redisConfig);
|
|
145
145
|
|
|
146
146
|
await queue.createQueue({
|
|
147
|
-
qname: "test-delayed-retry",
|
|
148
|
-
maxRetries: 2,
|
|
149
147
|
maxBackoffSeconds: 1,
|
|
148
|
+
maxRetries: 2,
|
|
149
|
+
qname: "test-delayed-retry",
|
|
150
150
|
});
|
|
151
151
|
|
|
152
152
|
const message = "Delayed retry message";
|
|
@@ -155,9 +155,9 @@ describe("RedisQueue Tests", () => {
|
|
|
155
155
|
|
|
156
156
|
const sentAt = Date.now();
|
|
157
157
|
await queue.sendMessage({
|
|
158
|
+
delay: delayMs,
|
|
158
159
|
message,
|
|
159
160
|
qname: "test-delayed-retry",
|
|
160
|
-
delay: delayMs,
|
|
161
161
|
});
|
|
162
162
|
|
|
163
163
|
await new Promise<void>((resolve) => {
|
|
@@ -205,9 +205,9 @@ describe("RedisQueue Tests", () => {
|
|
|
205
205
|
* This simulates a spreadsheet-queue:batch with shorter period for testing
|
|
206
206
|
*/
|
|
207
207
|
await queue.createQueue({
|
|
208
|
-
qname: "spreadsheet-queue:batch",
|
|
209
208
|
every: 3,
|
|
210
209
|
maxRetries: 0,
|
|
210
|
+
qname: "spreadsheet-queue:batch",
|
|
211
211
|
});
|
|
212
212
|
|
|
213
213
|
/**
|
|
@@ -235,9 +235,9 @@ describe("RedisQueue Tests", () => {
|
|
|
235
235
|
for (let i = 1; i <= 6; i++) {
|
|
236
236
|
const message = `Spreadsheet row ${i} for batch-001`;
|
|
237
237
|
await queue.sendBatchMessage({
|
|
238
|
-
qname: "spreadsheet-queue:batch",
|
|
239
238
|
batchId: "batch-001",
|
|
240
239
|
message,
|
|
240
|
+
qname: "spreadsheet-queue:batch",
|
|
241
241
|
});
|
|
242
242
|
batch001Messages.push(message);
|
|
243
243
|
}
|
|
@@ -248,9 +248,9 @@ describe("RedisQueue Tests", () => {
|
|
|
248
248
|
for (let i = 1; i <= 4; i++) {
|
|
249
249
|
const message = `Spreadsheet row ${i} for batch-002`;
|
|
250
250
|
await queue.sendBatchMessage({
|
|
251
|
-
qname: "spreadsheet-queue:batch",
|
|
252
251
|
batchId: "batch-002",
|
|
253
252
|
message,
|
|
253
|
+
qname: "spreadsheet-queue:batch",
|
|
254
254
|
});
|
|
255
255
|
batch002Messages.push(message);
|
|
256
256
|
}
|
|
@@ -334,10 +334,10 @@ describe("RedisQueue Tests", () => {
|
|
|
334
334
|
* Create batch queue with 2-second interval and retry enabled
|
|
335
335
|
*/
|
|
336
336
|
await queue.createQueue({
|
|
337
|
-
qname: "retry-test:batch",
|
|
338
337
|
every: 2,
|
|
339
|
-
maxRetries: 3,
|
|
340
338
|
maxBackoffSeconds: 1,
|
|
339
|
+
maxRetries: 3,
|
|
340
|
+
qname: "retry-test:batch",
|
|
341
341
|
});
|
|
342
342
|
|
|
343
343
|
const processedBatches: Array<{
|
|
@@ -351,9 +351,9 @@ describe("RedisQueue Tests", () => {
|
|
|
351
351
|
*/
|
|
352
352
|
for (let i = 1; i <= 3; i++) {
|
|
353
353
|
await queue.sendBatchMessage({
|
|
354
|
-
qname: "retry-test:batch",
|
|
355
354
|
batchId: `batch-00${i}`,
|
|
356
355
|
message: `Message ${i}`,
|
|
356
|
+
qname: "retry-test:batch",
|
|
357
357
|
});
|
|
358
358
|
}
|
|
359
359
|
|
|
@@ -365,8 +365,8 @@ describe("RedisQueue Tests", () => {
|
|
|
365
365
|
"retry-test:batch",
|
|
366
366
|
async (received) => {
|
|
367
367
|
processedBatches.push({
|
|
368
|
-
batchId: received.batchId,
|
|
369
368
|
attempt: received.attempt,
|
|
369
|
+
batchId: received.batchId,
|
|
370
370
|
success: false,
|
|
371
371
|
});
|
|
372
372
|
|
|
@@ -505,6 +505,51 @@ describe("RedisQueue Tests", () => {
|
|
|
505
505
|
|
|
506
506
|
await queue.close();
|
|
507
507
|
});
|
|
508
|
+
|
|
509
|
+
test("7. Can handle high volume and concurrency", async () => {
|
|
510
|
+
const totalMessages = 10_000;
|
|
511
|
+
|
|
512
|
+
const queue = new RedisQueue(redisConfig);
|
|
513
|
+
|
|
514
|
+
await queue.createQueue({ qname: "test-concurrency" });
|
|
515
|
+
|
|
516
|
+
const processedIds: string[] = [];
|
|
517
|
+
|
|
518
|
+
Array.from({ length: totalMessages }, async (_, i) => {
|
|
519
|
+
await queue.sendMessage({
|
|
520
|
+
message: JSON.stringify({
|
|
521
|
+
id: `${i}`,
|
|
522
|
+
name: `John Doe ${i}`,
|
|
523
|
+
}),
|
|
524
|
+
qname: "test-concurrency",
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
let receivedCount = 0;
|
|
529
|
+
|
|
530
|
+
await new Promise<void>((resolve) => {
|
|
531
|
+
queue.startWorker(
|
|
532
|
+
"test-concurrency",
|
|
533
|
+
async (received) => {
|
|
534
|
+
receivedCount++;
|
|
535
|
+
processedIds.push(JSON.parse(received.message).id);
|
|
536
|
+
if (receivedCount === totalMessages) {
|
|
537
|
+
resolve();
|
|
538
|
+
}
|
|
539
|
+
return { success: true };
|
|
540
|
+
},
|
|
541
|
+
workerConfig,
|
|
542
|
+
);
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
for (let i = 0; i < totalMessages; i++) {
|
|
546
|
+
expect(processedIds[i]).toBe(`${i}`);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
expect(receivedCount).toBe(totalMessages);
|
|
550
|
+
|
|
551
|
+
await queue.close();
|
|
552
|
+
});
|
|
508
553
|
});
|
|
509
554
|
|
|
510
555
|
afterAll(async () => {
|
package/app.ts
CHANGED
|
@@ -200,14 +200,25 @@ export class RedisQueue {
|
|
|
200
200
|
|
|
201
201
|
async deleteQueue(qname: string): Promise<boolean> {
|
|
202
202
|
const pattern = `${this.ns}:${qname}*`;
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
203
|
+
let cursor = "0";
|
|
204
|
+
let keysFound = false;
|
|
205
|
+
|
|
206
|
+
do {
|
|
207
|
+
const [nextCursor, keys] = await this.redis.scan(
|
|
208
|
+
cursor,
|
|
209
|
+
"MATCH",
|
|
210
|
+
pattern,
|
|
211
|
+
"COUNT",
|
|
212
|
+
500,
|
|
213
|
+
);
|
|
214
|
+
cursor = nextCursor as string;
|
|
215
|
+
if (keys.length > 0) {
|
|
216
|
+
keysFound = true;
|
|
217
|
+
await this.redis.del(...keys);
|
|
218
|
+
}
|
|
219
|
+
} while (cursor !== "0");
|
|
208
220
|
|
|
209
|
-
|
|
210
|
-
return true;
|
|
221
|
+
return keysFound;
|
|
211
222
|
}
|
|
212
223
|
|
|
213
224
|
async sendMessage(options: SendMessageOptions): Promise<string> {
|
|
@@ -295,10 +306,11 @@ export class RedisQueue {
|
|
|
295
306
|
const batchKey = this.getKey(qname, `batch:${batchId}`);
|
|
296
307
|
const batchMetaKey = this.getKey(qname, "batch-meta");
|
|
297
308
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
309
|
+
const [_, __, batchExists] = await Promise.all([
|
|
310
|
+
this.redis.hset(messagesKey, { [id]: encoded }),
|
|
311
|
+
this.redis.sadd(batchKey, id),
|
|
312
|
+
this.redis.hexists(batchMetaKey, batchId),
|
|
313
|
+
]);
|
|
302
314
|
|
|
303
315
|
if (!batchExists) {
|
|
304
316
|
const batchMeta: StoredBatchMeta = {
|
|
@@ -345,27 +357,6 @@ export class RedisQueue {
|
|
|
345
357
|
return JSON.parse(encoded);
|
|
346
358
|
}
|
|
347
359
|
|
|
348
|
-
private async fetchMessage(
|
|
349
|
-
qname: string,
|
|
350
|
-
id: string,
|
|
351
|
-
): Promise<Message | null> {
|
|
352
|
-
const messagesKey = this.getKey(qname, "messages");
|
|
353
|
-
const encoded = await this.redis.hget(messagesKey, id);
|
|
354
|
-
|
|
355
|
-
if (!encoded) {
|
|
356
|
-
return null;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
const stored = this.decodeMessage(encoded);
|
|
360
|
-
return {
|
|
361
|
-
attempt: stored.attempt,
|
|
362
|
-
id: stored.id,
|
|
363
|
-
message: stored.message,
|
|
364
|
-
sent: stored.sent,
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
// OPTIMIZED: Batch fetch multiple messages at once
|
|
369
360
|
private async fetchMessages(
|
|
370
361
|
qname: string,
|
|
371
362
|
ids: string[],
|
|
@@ -674,7 +665,6 @@ export class RedisQueue {
|
|
|
674
665
|
}
|
|
675
666
|
}
|
|
676
667
|
|
|
677
|
-
// OPTIMIZED: Process messages in parallel within worker
|
|
678
668
|
private async runWorker(
|
|
679
669
|
qname: string,
|
|
680
670
|
handler: (message: Message) => Promise<{ success: boolean }>,
|
|
@@ -683,22 +673,21 @@ export class RedisQueue {
|
|
|
683
673
|
silent: boolean,
|
|
684
674
|
): Promise<void> {
|
|
685
675
|
const queueKey = this.getKey(qname, "queue");
|
|
676
|
+
const BATCH_SIZE = 50;
|
|
686
677
|
|
|
687
678
|
while (!signal.aborted) {
|
|
688
679
|
try {
|
|
689
680
|
await this.processDelayedMessages(qname);
|
|
690
681
|
|
|
691
|
-
const
|
|
692
|
-
queueKey,
|
|
693
|
-
"0.1",
|
|
694
|
-
]);
|
|
682
|
+
const ids = await this.redis.rpop(queueKey, BATCH_SIZE);
|
|
695
683
|
|
|
696
|
-
if (
|
|
697
|
-
const
|
|
698
|
-
|
|
684
|
+
if (ids && ids.length > 0) {
|
|
685
|
+
const messages = await this.fetchMessages(
|
|
686
|
+
qname,
|
|
687
|
+
ids as string[],
|
|
688
|
+
);
|
|
699
689
|
|
|
700
|
-
|
|
701
|
-
// Process message without blocking the loop
|
|
690
|
+
const processingPromises = messages.map((message) =>
|
|
702
691
|
handler(message)
|
|
703
692
|
.then(async ({ success }) => {
|
|
704
693
|
if (success) {
|
|
@@ -715,8 +704,11 @@ export class RedisQueue {
|
|
|
715
704
|
);
|
|
716
705
|
}
|
|
717
706
|
await this.retryMessage(qname, message.id);
|
|
718
|
-
})
|
|
719
|
-
|
|
707
|
+
}),
|
|
708
|
+
);
|
|
709
|
+
await Promise.all(processingPromises);
|
|
710
|
+
} else {
|
|
711
|
+
await Bun.sleep(50);
|
|
720
712
|
}
|
|
721
713
|
} catch (error) {
|
|
722
714
|
if (!signal.aborted) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[{"_id":"6973b4f29af00ad243d8dfb1","index":0,"guid":"3da3f9d7-2406-4f07-8cc5-20c77a18ade4","isActive":false,"balance":"$1,361.82","picture":"http://placehold.it/32x32","age":37,"eyeColor":"green","name":"Hart Booth","gender":"male","company":"SULTRAX","email":"hartbooth@sultrax.com","phone":"+1 (966) 498-3673","address":"843 Hall Street, Trona, Oregon, 1712","about":"Deserunt fugiat nisi voluptate quis ex nisi reprehenderit est eiusmod officia sunt quis elit ea. Quis non mollit consectetur amet nulla anim ipsum consequat aliqua reprehenderit tempor reprehenderit. Sint pariatur pariatur laboris sint dolor sint voluptate pariatur ut adipisicing officia Lorem deserunt. Ullamco minim duis sit consequat aliqua in sunt nostrud amet nisi deserunt voluptate pariatur. Qui ullamco aliquip sunt veniam occaecat nulla ex incididunt. Aute mollit incididunt ad in dolor culpa pariatur non commodo magna nostrud non.\r\n","registered":"2025-07-22T10:26:43 -07:00","latitude":-3.647469,"longitude":69.437957,"tags":["qui","est","aliqua","ullamco","eiusmod","eu","velit"],"friends":[{"id":0,"name":"Lakisha Turner"},{"id":1,"name":"Leonor Ewing"},{"id":2,"name":"Frazier Irwin"}],"greeting":"Hello, Hart Booth! You have 6 unread messages.","favoriteFruit":"banana"},{"_id":"6973b4f2021b2c498f984bb6","index":1,"guid":"25034ff5-fbc8-4d09-8c63-e60f919e9ad4","isActive":false,"balance":"$2,141.41","picture":"http://placehold.it/32x32","age":33,"eyeColor":"brown","name":"Bethany Davenport","gender":"female","company":"STROZEN","email":"bethanydavenport@strozen.com","phone":"+1 (818) 499-2890","address":"506 Quay Street, Springville, Texas, 5249","about":"Consectetur occaecat sunt consectetur culpa nulla qui sunt labore proident et irure fugiat eu nulla. Voluptate est dolore labore aliqua velit duis. Proident occaecat culpa esse deserunt nulla aliqua. Nulla ea minim esse consectetur fugiat nostrud in anim esse cillum. Quis dolor quis reprehenderit ex ex ad esse minim est.\r\n","registered":"2020-08-03T11:36:56 -07:00","latitude":-10.479417,"longitude":28.341411,"tags":["non","eiusmod","amet","cillum","incididunt","elit","exercitation"],"friends":[{"id":0,"name":"Phyllis Bryan"},{"id":1,"name":"Mallory Gill"},{"id":2,"name":"Schneider Mercado"}],"greeting":"Hello, Bethany Davenport! You have 9 unread messages.","favoriteFruit":"apple"},{"_id":"6973b4f2220a607ed78df07a","index":2,"guid":"871776e1-d133-4ae7-8343-4fca929bb75c","isActive":true,"balance":"$2,630.76","picture":"http://placehold.it/32x32","age":35,"eyeColor":"brown","name":"Bertie Peters","gender":"female","company":"PERKLE","email":"bertiepeters@perkle.com","phone":"+1 (841) 517-3179","address":"972 Nassau Street, Ventress, Wyoming, 585","about":"Fugiat reprehenderit excepteur deserunt magna laboris aute culpa. Voluptate amet nisi commodo nostrud ipsum do nisi consectetur sint deserunt qui sint proident. Consequat cupidatat deserunt aliquip aliqua occaecat velit ad nostrud deserunt qui. Sunt amet sunt voluptate reprehenderit nisi eiusmod deserunt ea cillum Lorem qui anim aute duis.\r\n","registered":"2025-08-27T03:50:35 -07:00","latitude":32.284355,"longitude":-78.324272,"tags":["consequat","id","voluptate","tempor","proident","non","occaecat"],"friends":[{"id":0,"name":"Foreman Quinn"},{"id":1,"name":"Rojas Kemp"},{"id":2,"name":"Hanson Buck"}],"greeting":"Hello, Bertie Peters! You have 3 unread messages.","favoriteFruit":"banana"},{"_id":"6973b4f2bd348f1a31aca9f8","index":3,"guid":"fc19928a-b4f9-441e-ade9-efd7bad779af","isActive":false,"balance":"$1,273.51","picture":"http://placehold.it/32x32","age":40,"eyeColor":"blue","name":"Rosales Sims","gender":"male","company":"CANOPOLY","email":"rosalessims@canopoly.com","phone":"+1 (869) 427-3088","address":"153 Guernsey Street, Ona, New Jersey, 183","about":"Laborum sit sunt ad deserunt velit nisi culpa pariatur est ea mollit. Velit excepteur nulla cupidatat reprehenderit laboris sint amet duis exercitation dolore voluptate commodo sit Lorem. Velit exercitation ea incididunt adipisicing voluptate occaecat.\r\n","registered":"2017-11-04T12:50:51 -07:00","latitude":0.771702,"longitude":82.991386,"tags":["cillum","qui","sint","consectetur","eiusmod","consequat","ex"],"friends":[{"id":0,"name":"Imogene Lamb"},{"id":1,"name":"Key Burris"},{"id":2,"name":"Reyna Mayer"}],"greeting":"Hello, Rosales Sims! You have 7 unread messages.","favoriteFruit":"apple"},{"_id":"6973b4f207f65e544265d355","index":4,"guid":"abc15ba6-3214-4ef8-ac30-8afb642b82c2","isActive":true,"balance":"$2,945.08","picture":"http://placehold.it/32x32","age":26,"eyeColor":"brown","name":"Gretchen Jordan","gender":"female","company":"ANOCHA","email":"gretchenjordan@anocha.com","phone":"+1 (948) 454-2346","address":"890 Monaco Place, Loomis, Alabama, 4341","about":"Nulla excepteur est consequat velit aute laborum sunt voluptate aute eu eiusmod. Anim sunt eu veniam in commodo sit eu. Anim commodo incididunt ad reprehenderit anim culpa sit ut. Laborum esse in pariatur velit. Ut elit adipisicing magna ut officia non magna exercitation incididunt enim esse magna ad veniam. Deserunt irure ut dolor dolore labore pariatur veniam ipsum voluptate sint enim dolor. Ad exercitation sint sit occaecat excepteur eiusmod et sit.\r\n","registered":"2022-03-30T04:45:03 -07:00","latitude":29.089418,"longitude":-41.417872,"tags":["minim","amet","aliqua","excepteur","irure","et","culpa"],"friends":[{"id":0,"name":"Sonia Hayden"},{"id":1,"name":"Levy Burks"},{"id":2,"name":"Wolfe Hancock"}],"greeting":"Hello, Gretchen Jordan! You have 5 unread messages.","favoriteFruit":"banana"},{"_id":"6973b4f250d546997251a3d3","index":5,"guid":"ec6af806-cb4c-4ecc-b208-68b4b3cafd93","isActive":false,"balance":"$2,535.09","picture":"http://placehold.it/32x32","age":33,"eyeColor":"brown","name":"Ruiz Tran","gender":"male","company":"AQUASURE","email":"ruiztran@aquasure.com","phone":"+1 (962) 478-3889","address":"705 Farragut Road, Broadlands, Michigan, 1955","about":"Sunt enim Lorem excepteur sint mollit deserunt. Aute commodo amet sit cillum voluptate mollit exercitation ad cillum aute fugiat mollit. Quis ad cupidatat veniam reprehenderit aute cupidatat quis. Minim laboris est fugiat et in cillum id nisi dolore reprehenderit fugiat minim. Nulla ut consequat do sit dolor laboris.\r\n","registered":"2018-09-27T01:51:44 -07:00","latitude":-59.151306,"longitude":143.667188,"tags":["laboris","anim","eiusmod","quis","nulla","aliqua","duis"],"friends":[{"id":0,"name":"Ramona Brock"},{"id":1,"name":"Kayla Webb"},{"id":2,"name":"Rutledge Mcclure"}],"greeting":"Hello, Ruiz Tran! You have 6 unread messages.","favoriteFruit":"apple"},{"_id":"6973b4f20e1b602ed3098386","index":6,"guid":"d63efc08-287a-487e-a159-bbb4f231c37a","isActive":false,"balance":"$3,941.09","picture":"http://placehold.it/32x32","age":37,"eyeColor":"blue","name":"Reba Oneal","gender":"female","company":"NIQUENT","email":"rebaoneal@niquent.com","phone":"+1 (994) 443-2343","address":"229 Clifton Place, Cochranville, Pennsylvania, 6468","about":"Officia veniam do minim elit duis in nulla. Deserunt veniam in ut esse duis nulla cillum magna ullamco dolore veniam exercitation Lorem. Eiusmod pariatur irure dolor aute dolore minim adipisicing sint ullamco. Ipsum id voluptate est ipsum adipisicing est. Do anim exercitation commodo mollit fugiat minim est ea.\r\n","registered":"2020-05-02T09:23:38 -07:00","latitude":-45.360857,"longitude":-17.113491,"tags":["laborum","dolor","incididunt","elit","adipisicing","adipisicing","veniam"],"friends":[{"id":0,"name":"Janine Russell"},{"id":1,"name":"Abby Short"},{"id":2,"name":"Savannah Grant"}],"greeting":"Hello, Reba Oneal! You have 7 unread messages.","favoriteFruit":"banana"},{"_id":"6973b4f208d0cb4b5c53bb93","index":7,"guid":"152d21f2-05cd-41d2-a048-ba499944b2bf","isActive":false,"balance":"$1,155.29","picture":"http://placehold.it/32x32","age":25,"eyeColor":"green","name":"Vanessa Rodriquez","gender":"female","company":"OPTYK","email":"vanessarodriquez@optyk.com","phone":"+1 (873) 492-2951","address":"102 Thatford Avenue, Keyport, Minnesota, 7404","about":"Adipisicing sit dolor reprehenderit Lorem et voluptate culpa ullamco cillum officia dolor culpa et sit. Lorem minim eu laboris nulla do est labore nulla eu occaecat. Est occaecat sit id irure. Enim sint consequat amet mollit occaecat in mollit duis. Eiusmod et tempor laborum est tempor fugiat anim ullamco.\r\n","registered":"2019-11-03T12:06:46 -07:00","latitude":30.194412,"longitude":155.798353,"tags":["aliqua","cupidatat","quis","eiusmod","ad","veniam","velit"],"friends":[{"id":0,"name":"June Little"},{"id":1,"name":"Lamb Marsh"},{"id":2,"name":"Richards Conley"}],"greeting":"Hello, Vanessa Rodriquez! You have 5 unread messages.","favoriteFruit":"banana"},{"_id":"6973b4f244d84ce83babb8e8","index":8,"guid":"2d743ccf-cffe-46ac-821a-1a32180f8401","isActive":true,"balance":"$1,531.94","picture":"http://placehold.it/32x32","age":33,"eyeColor":"brown","name":"Kathy Warren","gender":"female","company":"NURPLEX","email":"kathywarren@nurplex.com","phone":"+1 (958) 514-2617","address":"211 Cypress Court, Rosewood, Massachusetts, 2530","about":"Cillum nisi ad esse aliqua do amet eu dolor. Culpa culpa adipisicing officia nisi magna occaecat aliquip labore nostrud anim. Eu esse in aliquip exercitation reprehenderit cupidatat eu veniam deserunt cillum excepteur id. Id dolor reprehenderit do deserunt. Enim eiusmod nostrud exercitation fugiat consequat. Nulla deserunt cillum mollit excepteur ea ad veniam. Id nostrud laboris ipsum cupidatat ex non commodo ad sunt.\r\n","registered":"2017-06-14T06:01:20 -07:00","latitude":34.733711,"longitude":-163.804679,"tags":["reprehenderit","elit","exercitation","voluptate","aute","adipisicing","occaecat"],"friends":[{"id":0,"name":"Allie Holcomb"},{"id":1,"name":"Muriel Weaver"},{"id":2,"name":"Tommie Carr"}],"greeting":"Hello, Kathy Warren! You have 4 unread messages.","favoriteFruit":"apple"},{"_id":"6973b4f297dc750e1750eb58","index":9,"guid":"1ccffd92-ff08-429d-9232-e86c565e70da","isActive":true,"balance":"$1,662.22","picture":"http://placehold.it/32x32","age":31,"eyeColor":"green","name":"Hodges Richardson","gender":"male","company":"POSHOME","email":"hodgesrichardson@poshome.com","phone":"+1 (970) 590-2870","address":"686 Anna Court, Elizaville, Marshall Islands, 5762","about":"Ullamco cupidatat nisi do ut nostrud est pariatur labore dolore exercitation quis minim ipsum quis. Aute enim excepteur voluptate ullamco laboris adipisicing commodo. Do amet sunt occaecat id commodo. Consectetur veniam excepteur nisi in commodo. Laborum anim dolor velit deserunt culpa. Exercitation do amet laborum do ipsum voluptate commodo. Aliqua exercitation consequat nisi pariatur ea veniam officia nostrud excepteur tempor.\r\n","registered":"2016-07-28T02:54:58 -07:00","latitude":-14.492817,"longitude":134.965697,"tags":["qui","aliquip","pariatur","magna","ad","et","irure"],"friends":[{"id":0,"name":"Robyn Willis"},{"id":1,"name":"Gabrielle Holt"},{"id":2,"name":"Wilkerson Bailey"}],"greeting":"Hello, Hodges Richardson! You have 5 unread messages.","favoriteFruit":"strawberry"},{"_id":"6973b4f277b5d5924e85e34c","index":10,"guid":"24b6f2d6-f153-4826-9c2f-f50c42d907e5","isActive":true,"balance":"$1,715.09","picture":"http://placehold.it/32x32","age":33,"eyeColor":"blue","name":"Floyd Petty","gender":"male","company":"GINKOGENE","email":"floydpetty@ginkogene.com","phone":"+1 (832) 499-3944","address":"910 Canal Avenue, Mammoth, North Dakota, 1708","about":"Eiusmod velit proident sit proident ipsum irure. Excepteur dolore consequat labore duis tempor nulla laborum do amet labore. Amet nisi ullamco ad enim officia id exercitation aliquip in fugiat in. Anim quis et enim proident dolore magna mollit consectetur ea elit velit nostrud. Consectetur ea labore esse esse est nisi consectetur magna ut ullamco nulla ipsum exercitation.\r\n","registered":"2023-09-18T01:14:07 -07:00","latitude":-51.559233,"longitude":134.694377,"tags":["cupidatat","elit","commodo","ullamco","do","reprehenderit","nostrud"],"friends":[{"id":0,"name":"Naomi Garrison"},{"id":1,"name":"Betty English"},{"id":2,"name":"Prince Singleton"}],"greeting":"Hello, Floyd Petty! You have 7 unread messages.","favoriteFruit":"strawberry"},{"_id":"6973b4f2e7ad4e31bb2510c3","index":11,"guid":"74ccb6d9-7f24-4451-a3a0-e632bab385b3","isActive":true,"balance":"$1,490.53","picture":"http://placehold.it/32x32","age":36,"eyeColor":"blue","name":"Johnnie Simon","gender":"female","company":"JAMNATION","email":"johnniesimon@jamnation.com","phone":"+1 (868) 417-3009","address":"125 Chester Street, Whipholt, Maryland, 9466","about":"Dolor anim esse enim Lorem nostrud id officia incididunt amet laboris laboris sunt. Pariatur dolor aute Lorem aute magna. Laborum enim non voluptate commodo.\r\n","registered":"2015-03-03T08:28:39 -07:00","latitude":-19.882734,"longitude":-45.527604,"tags":["qui","sit","culpa","id","dolor","irure","id"],"friends":[{"id":0,"name":"Fry Ayers"},{"id":1,"name":"Donovan Foley"},{"id":2,"name":"Finch Dunn"}],"greeting":"Hello, Johnnie Simon! You have 9 unread messages.","favoriteFruit":"apple"},{"_id":"6973b4f24d0d75c705a54911","index":12,"guid":"f972a1ef-0d3a-41ab-b080-eaf7d26184f1","isActive":true,"balance":"$3,429.83","picture":"http://placehold.it/32x32","age":36,"eyeColor":"brown","name":"Rosalind Duran","gender":"female","company":"ZORROMOP","email":"rosalindduran@zorromop.com","phone":"+1 (987) 589-3940","address":"720 Mill Avenue, Gardiner, Nebraska, 6579","about":"Dolor deserunt nisi laborum eiusmod aliquip adipisicing ullamco eiusmod non qui consectetur est nostrud. Incididunt nostrud labore minim Lorem elit qui commodo consectetur ex culpa veniam. Quis ad quis cillum esse nisi ea ipsum consequat dolore. Non minim minim sint excepteur anim consectetur est voluptate laborum commodo. Mollit ea magna dolor sit ut magna voluptate ipsum reprehenderit id ex cillum deserunt.\r\n","registered":"2014-07-03T10:56:30 -07:00","latitude":-39.091253,"longitude":-131.671201,"tags":["labore","enim","nulla","est","exercitation","ipsum","deserunt"],"friends":[{"id":0,"name":"Emerson Dalton"},{"id":1,"name":"Owen Bass"},{"id":2,"name":"Bell Shannon"}],"greeting":"Hello, Rosalind Duran! You have 1 unread messages.","favoriteFruit":"banana"},{"_id":"6973b4f2edea35a5d2cea142","index":13,"guid":"18cf8f91-9735-4fa6-9381-ae8c1060890c","isActive":true,"balance":"$1,811.69","picture":"http://placehold.it/32x32","age":26,"eyeColor":"blue","name":"Pauline Cain","gender":"female","company":"ENAUT","email":"paulinecain@enaut.com","phone":"+1 (972) 408-3809","address":"508 Rapelye Street, Thynedale, Maine, 9391","about":"Qui enim fugiat do eu in eu aliqua elit cillum occaecat. Consectetur amet pariatur ea dolore Lorem eu ipsum veniam commodo commodo. Mollit dolore velit aliqua cillum elit consequat sunt nostrud in qui ipsum sit eu irure. Cupidatat reprehenderit labore in officia laborum.\r\n","registered":"2023-12-23T01:34:49 -07:00","latitude":-18.152332,"longitude":6.220963,"tags":["quis","sint","proident","officia","dolore","elit","quis"],"friends":[{"id":0,"name":"Kristie Shepherd"},{"id":1,"name":"Jensen Webster"},{"id":2,"name":"Langley Young"}],"greeting":"Hello, Pauline Cain! You have 7 unread messages.","favoriteFruit":"apple"}]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"batch_id":"batch_analytics_2201","source_system":"inventory_management_v2","generated_at":"2023-10-27T10:00:00Z","record_count":5,"data":[{"sku":"KEY-MECH-RGB-001","warehouse_id":"WH-NY-01","stock_level":450,"reserved":12,"incoming":100,"last_audit":"2023-10-25","dimensions":{"w":15,"h":5,"l":40,"unit":"cm"},"tags":["electronics","peripherals","hot_item"]},{"sku":"MON-4K-IPS-002","warehouse_id":"WH-CA-02","stock_level":85,"reserved":5,"incoming":0,"last_audit":"2023-10-26","dimensions":{"w":60,"h":40,"l":10,"unit":"cm"},"tags":["electronics","display","fragile"]},{"sku":"LAP-PRO-M2-003","warehouse_id":"WH-TX-05","stock_level":200,"reserved":45,"incoming":50,"last_audit":"2023-10-20","dimensions":{"w":30,"h":2,"l":20,"unit":"cm"},"tags":["computer","high_value","insured"]},{"sku":"MOU-ERG-WL-004","warehouse_id":"WH-NY-01","stock_level":1200,"reserved":0,"incoming":200,"last_audit":"2023-10-22","dimensions":{"w":8,"h":5,"l":12,"unit":"cm"},"tags":["peripherals","office","sale"]},{"sku":"CAB-HDMI-2M-005","warehouse_id":"WH-WA-03","stock_level":5000,"reserved":120,"incoming":1000,"last_audit":"2023-10-01","dimensions":{"w":10,"h":2,"l":10,"unit":"cm"},"tags":["accessory","cable","generic"]}],"system_logs":{"warnings":[],"errors":[{"code":404,"msg":"SKU-IMG-MISSING for CAB-HDMI-2M-005","timestamp":1678892500}],"performance_metrics":{"query_time_ms":145,"db_reads":25,"cpu_load_percent":12}}}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import RedisQueue from "../app";
|
|
2
|
+
declare var self: Worker;
|
|
2
3
|
|
|
3
4
|
interface WorkerMessage {
|
|
4
5
|
type: "start";
|
|
@@ -23,15 +24,27 @@ self.addEventListener("message", async (event: MessageEvent<WorkerMessage>) => {
|
|
|
23
24
|
try {
|
|
24
25
|
const queue = new RedisQueue(redisConfig);
|
|
25
26
|
const latencies: number[] = [];
|
|
27
|
+
const CHUNK_SIZE = 1000;
|
|
26
28
|
|
|
27
|
-
for (let i = 0; i < messagesPerWorker; i
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
for (let i = 0; i < messagesPerWorker; i += CHUNK_SIZE) {
|
|
30
|
+
const promises = [];
|
|
31
|
+
const chunkEnd = Math.min(i + CHUNK_SIZE, messagesPerWorker);
|
|
32
|
+
|
|
33
|
+
for (let j = i; j < chunkEnd; j++) {
|
|
34
|
+
const start = performance.now();
|
|
35
|
+
promises.push(
|
|
36
|
+
queue
|
|
37
|
+
.sendMessage({
|
|
38
|
+
message: testMessage,
|
|
39
|
+
qname,
|
|
40
|
+
})
|
|
41
|
+
.then(() => {
|
|
42
|
+
const latency = performance.now() - start;
|
|
43
|
+
latencies.push(latency);
|
|
44
|
+
}),
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
await Promise.all(promises);
|
|
35
48
|
}
|
|
36
49
|
|
|
37
50
|
await queue.close();
|
package/benchmark/stress.ts
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import type { Worker } from "bun";
|
|
4
4
|
import RedisQueue from "../app";
|
|
5
|
+
import mediumMsg from "./medium.txt";
|
|
6
|
+
import smallMsg from "./small.txt";
|
|
7
|
+
import tinyMsg from "./tiny.txt";
|
|
5
8
|
|
|
6
9
|
const COLORS = {
|
|
7
10
|
blue: "\x1b[34m",
|
|
@@ -14,8 +17,8 @@ const COLORS = {
|
|
|
14
17
|
yellow: "\x1b[33m",
|
|
15
18
|
};
|
|
16
19
|
|
|
17
|
-
const WORKER_COUNT =
|
|
18
|
-
const CONCURRENCY =
|
|
20
|
+
const WORKER_COUNT = 8;
|
|
21
|
+
const CONCURRENCY = 2;
|
|
19
22
|
const MSG_COUNT = 100_000;
|
|
20
23
|
|
|
21
24
|
interface StressTestConfig {
|
|
@@ -112,7 +115,7 @@ async function testRegularQueueParallel(
|
|
|
112
115
|
});
|
|
113
116
|
|
|
114
117
|
const qname = "stress-regular";
|
|
115
|
-
await queue.createQueue({ maxRetries: 0,
|
|
118
|
+
await queue.createQueue({ maxRetries: 0, maxsize: 150_000, qname });
|
|
116
119
|
|
|
117
120
|
const allLatencies: number[] = [];
|
|
118
121
|
let receivedCount = 0;
|
|
@@ -173,7 +176,6 @@ async function testRegularQueueParallel(
|
|
|
173
176
|
|
|
174
177
|
worker.postMessage({
|
|
175
178
|
data: {
|
|
176
|
-
testMessage: config.testMessage,
|
|
177
179
|
messagesPerWorker,
|
|
178
180
|
qname,
|
|
179
181
|
redisConfig: {
|
|
@@ -181,6 +183,7 @@ async function testRegularQueueParallel(
|
|
|
181
183
|
namespace: "stress-test",
|
|
182
184
|
port: process.env.REDIS_PORT || "6379",
|
|
183
185
|
},
|
|
186
|
+
testMessage: config.testMessage,
|
|
184
187
|
workerIndex: i,
|
|
185
188
|
},
|
|
186
189
|
type: "start",
|
|
@@ -261,91 +264,93 @@ async function main() {
|
|
|
261
264
|
|
|
262
265
|
await cleanup();
|
|
263
266
|
|
|
264
|
-
|
|
265
|
-
const mediumMessage = '{"batch_id":"batch_analytics_2201","source_system":"inventory_management_v2","generated_at":"2023-10-27T10:00:00Z","record_count":5,"data":[{"sku":"KEY-MECH-RGB-001","warehouse_id":"WH-NY-01","stock_level":450,"reserved":12,"incoming":100,"last_audit":"2023-10-25","dimensions":{"w":15,"h":5,"l":40,"unit":"cm"},"tags":["electronics","peripherals","hot_item"]},{"sku":"MON-4K-IPS-002","warehouse_id":"WH-CA-02","stock_level":85,"reserved":5,"incoming":0,"last_audit":"2023-10-26","dimensions":{"w":60,"h":40,"l":10,"unit":"cm"},"tags":["electronics","display","fragile"]},{"sku":"LAP-PRO-M2-003","warehouse_id":"WH-TX-05","stock_level":200,"reserved":45,"incoming":50,"last_audit":"2023-10-20","dimensions":{"w":30,"h":2,"l":20,"unit":"cm"},"tags":["computer","high_value","insured"]},{"sku":"MOU-ERG-WL-004","warehouse_id":"WH-NY-01","stock_level":1200,"reserved":0,"incoming":200,"last_audit":"2023-10-22","dimensions":{"w":8,"h":5,"l":12,"unit":"cm"},"tags":["peripherals","office","sale"]},{"sku":"CAB-HDMI-2M-005","warehouse_id":"WH-WA-03","stock_level":5000,"reserved":120,"incoming":1000,"last_audit":"2023-10-01","dimensions":{"w":10,"h":2,"l":10,"unit":"cm"},"tags":["accessory","cable","generic"]}],"system_logs":{"warnings":[],"errors":[{"code":404,"msg":"SKU-IMG-MISSING for CAB-HDMI-2M-005","timestamp":1678892500}],"performance_metrics":{"query_time_ms":145,"db_reads":25,"cpu_load_percent":12}}}'
|
|
266
|
-
|
|
267
267
|
const availableCPUs = navigator.hardwareConcurrency;
|
|
268
268
|
log("yellow", `\nš» Detected ${availableCPUs} CPU cores`);
|
|
269
269
|
|
|
270
270
|
log("blue", `\nš§ Using ${WORKER_COUNT} workers for tests`);
|
|
271
271
|
|
|
272
272
|
try {
|
|
273
|
-
|
|
274
|
-
log("cyan", "\nš Test 1: Small messages (100 bytes)");
|
|
273
|
+
log("cyan", "\nš Test 1: Tiny messages (100 bytes)");
|
|
275
274
|
const test1Results = await testRegularQueueParallel({
|
|
276
275
|
concurrency: CONCURRENCY,
|
|
277
276
|
messageCount: MSG_COUNT,
|
|
278
|
-
testMessage:
|
|
279
|
-
workerCount:WORKER_COUNT,
|
|
277
|
+
testMessage: tinyMsg,
|
|
278
|
+
workerCount: WORKER_COUNT,
|
|
280
279
|
});
|
|
281
280
|
printResults(
|
|
282
|
-
"Test 1:
|
|
281
|
+
"Test 1: Tiny Messages (100K msgs, 100 bytes)",
|
|
283
282
|
test1Results,
|
|
284
283
|
);
|
|
285
284
|
|
|
285
|
+
await cleanup();
|
|
286
286
|
|
|
287
|
-
|
|
288
|
-
log("cyan", "\nš Test 2: Medium messages (1KB)");
|
|
287
|
+
log("cyan", "\nš Test 2: Small messages (1KB)");
|
|
289
288
|
const test2Results = await testRegularQueueParallel({
|
|
290
289
|
concurrency: CONCURRENCY,
|
|
291
290
|
messageCount: MSG_COUNT,
|
|
292
|
-
testMessage:
|
|
293
|
-
workerCount:
|
|
291
|
+
testMessage: smallMsg,
|
|
292
|
+
workerCount: WORKER_COUNT,
|
|
294
293
|
});
|
|
295
|
-
printResults(
|
|
296
|
-
"Test 2: Medium Messages (50K msgs, 1KB)",
|
|
297
|
-
test2Results,
|
|
298
|
-
);
|
|
294
|
+
printResults("Test 2: Small Messages (100K msgs, 1KB)", test2Results);
|
|
299
295
|
|
|
296
|
+
await cleanup();
|
|
300
297
|
|
|
301
|
-
|
|
302
|
-
log("cyan", "\nš Test 3: Large messages (10KB)");
|
|
298
|
+
log("cyan", "\nš Test 3: Medium messages (10KB)");
|
|
303
299
|
const test3Results = await testRegularQueueParallel({
|
|
304
300
|
concurrency: CONCURRENCY,
|
|
305
301
|
messageCount: MSG_COUNT,
|
|
306
|
-
testMessage: '[{"_id":"6973b4f29af00ad243d8dfb1","index":0,"guid":"3da3f9d7-2406-4f07-8cc5-20c77a18ade4","isActive":false,"balance":"$1,361.82","picture":"http://placehold.it/32x32","age":37,"eyeColor":"green","name":"Hart Booth","gender":"male","company":"SULTRAX","email":"hartbooth@sultrax.com","phone":"+1 (966) 498-3673","address":"843 Hall Street, Trona, Oregon, 1712","about":"Deserunt fugiat nisi voluptate quis ex nisi reprehenderit est eiusmod officia sunt quis elit ea. Quis non mollit consectetur amet nulla anim ipsum consequat aliqua reprehenderit tempor reprehenderit. Sint pariatur pariatur laboris sint dolor sint voluptate pariatur ut adipisicing officia Lorem deserunt. Ullamco minim duis sit consequat aliqua in sunt nostrud amet nisi deserunt voluptate pariatur. Qui ullamco aliquip sunt veniam occaecat nulla ex incididunt. Aute mollit incididunt ad in dolor culpa pariatur non commodo magna nostrud non.\r\n","registered":"2025-07-22T10:26:43 -07:00","latitude":-3.647469,"longitude":69.437957,"tags":["qui","est","aliqua","ullamco","eiusmod","eu","velit"],"friends":[{"id":0,"name":"Lakisha Turner"},{"id":1,"name":"Leonor Ewing"},{"id":2,"name":"Frazier Irwin"}],"greeting":"Hello, Hart Booth! You have 6 unread messages.","favoriteFruit":"banana"},{"_id":"6973b4f2021b2c498f984bb6","index":1,"guid":"25034ff5-fbc8-4d09-8c63-e60f919e9ad4","isActive":false,"balance":"$2,141.41","picture":"http://placehold.it/32x32","age":33,"eyeColor":"brown","name":"Bethany Davenport","gender":"female","company":"STROZEN","email":"bethanydavenport@strozen.com","phone":"+1 (818) 499-2890","address":"506 Quay Street, Springville, Texas, 5249","about":"Consectetur occaecat sunt consectetur culpa nulla qui sunt labore proident et irure fugiat eu nulla. Voluptate est dolore labore aliqua velit duis. Proident occaecat culpa esse deserunt nulla aliqua. Nulla ea minim esse consectetur fugiat nostrud in anim esse cillum. Quis dolor quis reprehenderit ex ex ad esse minim est.\r\n","registered":"2020-08-03T11:36:56 -07:00","latitude":-10.479417,"longitude":28.341411,"tags":["non","eiusmod","amet","cillum","incididunt","elit","exercitation"],"friends":[{"id":0,"name":"Phyllis Bryan"},{"id":1,"name":"Mallory Gill"},{"id":2,"name":"Schneider Mercado"}],"greeting":"Hello, Bethany Davenport! You have 9 unread messages.","favoriteFruit":"apple"},{"_id":"6973b4f2220a607ed78df07a","index":2,"guid":"871776e1-d133-4ae7-8343-4fca929bb75c","isActive":true,"balance":"$2,630.76","picture":"http://placehold.it/32x32","age":35,"eyeColor":"brown","name":"Bertie Peters","gender":"female","company":"PERKLE","email":"bertiepeters@perkle.com","phone":"+1 (841) 517-3179","address":"972 Nassau Street, Ventress, Wyoming, 585","about":"Fugiat reprehenderit excepteur deserunt magna laboris aute culpa. Voluptate amet nisi commodo nostrud ipsum do nisi consectetur sint deserunt qui sint proident. Consequat cupidatat deserunt aliquip aliqua occaecat velit ad nostrud deserunt qui. Sunt amet sunt voluptate reprehenderit nisi eiusmod deserunt ea cillum Lorem qui anim aute duis.\r\n","registered":"2025-08-27T03:50:35 -07:00","latitude":32.284355,"longitude":-78.324272,"tags":["consequat","id","voluptate","tempor","proident","non","occaecat"],"friends":[{"id":0,"name":"Foreman Quinn"},{"id":1,"name":"Rojas Kemp"},{"id":2,"name":"Hanson Buck"}],"greeting":"Hello, Bertie Peters! You have 3 unread messages.","favoriteFruit":"banana"},{"_id":"6973b4f2bd348f1a31aca9f8","index":3,"guid":"fc19928a-b4f9-441e-ade9-efd7bad779af","isActive":false,"balance":"$1,273.51","picture":"http://placehold.it/32x32","age":40,"eyeColor":"blue","name":"Rosales Sims","gender":"male","company":"CANOPOLY","email":"rosalessims@canopoly.com","phone":"+1 (869) 427-3088","address":"153 Guernsey Street, Ona, New Jersey, 183","about":"Laborum sit sunt ad deserunt velit nisi culpa pariatur est ea mollit. Velit excepteur nulla cupidatat reprehenderit laboris sint amet duis exercitation dolore voluptate commodo sit Lorem. Velit exercitation ea incididunt adipisicing voluptate occaecat.\r\n","registered":"2017-11-04T12:50:51 -07:00","latitude":0.771702,"longitude":82.991386,"tags":["cillum","qui","sint","consectetur","eiusmod","consequat","ex"],"friends":[{"id":0,"name":"Imogene Lamb"},{"id":1,"name":"Key Burris"},{"id":2,"name":"Reyna Mayer"}],"greeting":"Hello, Rosales Sims! You have 7 unread messages.","favoriteFruit":"apple"},{"_id":"6973b4f207f65e544265d355","index":4,"guid":"abc15ba6-3214-4ef8-ac30-8afb642b82c2","isActive":true,"balance":"$2,945.08","picture":"http://placehold.it/32x32","age":26,"eyeColor":"brown","name":"Gretchen Jordan","gender":"female","company":"ANOCHA","email":"gretchenjordan@anocha.com","phone":"+1 (948) 454-2346","address":"890 Monaco Place, Loomis, Alabama, 4341","about":"Nulla excepteur est consequat velit aute laborum sunt voluptate aute eu eiusmod. Anim sunt eu veniam in commodo sit eu. Anim commodo incididunt ad reprehenderit anim culpa sit ut. Laborum esse in pariatur velit. Ut elit adipisicing magna ut officia non magna exercitation incididunt enim esse magna ad veniam. Deserunt irure ut dolor dolore labore pariatur veniam ipsum voluptate sint enim dolor. Ad exercitation sint sit occaecat excepteur eiusmod et sit.\r\n","registered":"2022-03-30T04:45:03 -07:00","latitude":29.089418,"longitude":-41.417872,"tags":["minim","amet","aliqua","excepteur","irure","et","culpa"],"friends":[{"id":0,"name":"Sonia Hayden"},{"id":1,"name":"Levy Burks"},{"id":2,"name":"Wolfe Hancock"}],"greeting":"Hello, Gretchen Jordan! You have 5 unread messages.","favoriteFruit":"banana"},{"_id":"6973b4f250d546997251a3d3","index":5,"guid":"ec6af806-cb4c-4ecc-b208-68b4b3cafd93","isActive":false,"balance":"$2,535.09","picture":"http://placehold.it/32x32","age":33,"eyeColor":"brown","name":"Ruiz Tran","gender":"male","company":"AQUASURE","email":"ruiztran@aquasure.com","phone":"+1 (962) 478-3889","address":"705 Farragut Road, Broadlands, Michigan, 1955","about":"Sunt enim Lorem excepteur sint mollit deserunt. Aute commodo amet sit cillum voluptate mollit exercitation ad cillum aute fugiat mollit. Quis ad cupidatat veniam reprehenderit aute cupidatat quis. Minim laboris est fugiat et in cillum id nisi dolore reprehenderit fugiat minim. Nulla ut consequat do sit dolor laboris.\r\n","registered":"2018-09-27T01:51:44 -07:00","latitude":-59.151306,"longitude":143.667188,"tags":["laboris","anim","eiusmod","quis","nulla","aliqua","duis"],"friends":[{"id":0,"name":"Ramona Brock"},{"id":1,"name":"Kayla Webb"},{"id":2,"name":"Rutledge Mcclure"}],"greeting":"Hello, Ruiz Tran! You have 6 unread messages.","favoriteFruit":"apple"},{"_id":"6973b4f20e1b602ed3098386","index":6,"guid":"d63efc08-287a-487e-a159-bbb4f231c37a","isActive":false,"balance":"$3,941.09","picture":"http://placehold.it/32x32","age":37,"eyeColor":"blue","name":"Reba Oneal","gender":"female","company":"NIQUENT","email":"rebaoneal@niquent.com","phone":"+1 (994) 443-2343","address":"229 Clifton Place, Cochranville, Pennsylvania, 6468","about":"Officia veniam do minim elit duis in nulla. Deserunt veniam in ut esse duis nulla cillum magna ullamco dolore veniam exercitation Lorem. Eiusmod pariatur irure dolor aute dolore minim adipisicing sint ullamco. Ipsum id voluptate est ipsum adipisicing est. Do anim exercitation commodo mollit fugiat minim est ea.\r\n","registered":"2020-05-02T09:23:38 -07:00","latitude":-45.360857,"longitude":-17.113491,"tags":["laborum","dolor","incididunt","elit","adipisicing","adipisicing","veniam"],"friends":[{"id":0,"name":"Janine Russell"},{"id":1,"name":"Abby Short"},{"id":2,"name":"Savannah Grant"}],"greeting":"Hello, Reba Oneal! You have 7 unread messages.","favoriteFruit":"banana"},{"_id":"6973b4f208d0cb4b5c53bb93","index":7,"guid":"152d21f2-05cd-41d2-a048-ba499944b2bf","isActive":false,"balance":"$1,155.29","picture":"http://placehold.it/32x32","age":25,"eyeColor":"green","name":"Vanessa Rodriquez","gender":"female","company":"OPTYK","email":"vanessarodriquez@optyk.com","phone":"+1 (873) 492-2951","address":"102 Thatford Avenue, Keyport, Minnesota, 7404","about":"Adipisicing sit dolor reprehenderit Lorem et voluptate culpa ullamco cillum officia dolor culpa et sit. Lorem minim eu laboris nulla do est labore nulla eu occaecat. Est occaecat sit id irure. Enim sint consequat amet mollit occaecat in mollit duis. Eiusmod et tempor laborum est tempor fugiat anim ullamco.\r\n","registered":"2019-11-03T12:06:46 -07:00","latitude":30.194412,"longitude":155.798353,"tags":["aliqua","cupidatat","quis","eiusmod","ad","veniam","velit"],"friends":[{"id":0,"name":"June Little"},{"id":1,"name":"Lamb Marsh"},{"id":2,"name":"Richards Conley"}],"greeting":"Hello, Vanessa Rodriquez! You have 5 unread messages.","favoriteFruit":"banana"},{"_id":"6973b4f244d84ce83babb8e8","index":8,"guid":"2d743ccf-cffe-46ac-821a-1a32180f8401","isActive":true,"balance":"$1,531.94","picture":"http://placehold.it/32x32","age":33,"eyeColor":"brown","name":"Kathy Warren","gender":"female","company":"NURPLEX","email":"kathywarren@nurplex.com","phone":"+1 (958) 514-2617","address":"211 Cypress Court, Rosewood, Massachusetts, 2530","about":"Cillum nisi ad esse aliqua do amet eu dolor. Culpa culpa adipisicing officia nisi magna occaecat aliquip labore nostrud anim. Eu esse in aliquip exercitation reprehenderit cupidatat eu veniam deserunt cillum excepteur id. Id dolor reprehenderit do deserunt. Enim eiusmod nostrud exercitation fugiat consequat. Nulla deserunt cillum mollit excepteur ea ad veniam. Id nostrud laboris ipsum cupidatat ex non commodo ad sunt.\r\n","registered":"2017-06-14T06:01:20 -07:00","latitude":34.733711,"longitude":-163.804679,"tags":["reprehenderit","elit","exercitation","voluptate","aute","adipisicing","occaecat"],"friends":[{"id":0,"name":"Allie Holcomb"},{"id":1,"name":"Muriel Weaver"},{"id":2,"name":"Tommie Carr"}],"greeting":"Hello, Kathy Warren! You have 4 unread messages.","favoriteFruit":"apple"},{"_id":"6973b4f297dc750e1750eb58","index":9,"guid":"1ccffd92-ff08-429d-9232-e86c565e70da","isActive":true,"balance":"$1,662.22","picture":"http://placehold.it/32x32","age":31,"eyeColor":"green","name":"Hodges Richardson","gender":"male","company":"POSHOME","email":"hodgesrichardson@poshome.com","phone":"+1 (970) 590-2870","address":"686 Anna Court, Elizaville, Marshall Islands, 5762","about":"Ullamco cupidatat nisi do ut nostrud est pariatur labore dolore exercitation quis minim ipsum quis. Aute enim excepteur voluptate ullamco laboris adipisicing commodo. Do amet sunt occaecat id commodo. Consectetur veniam excepteur nisi in commodo. Laborum anim dolor velit deserunt culpa. Exercitation do amet laborum do ipsum voluptate commodo. Aliqua exercitation consequat nisi pariatur ea veniam officia nostrud excepteur tempor.\r\n","registered":"2016-07-28T02:54:58 -07:00","latitude":-14.492817,"longitude":134.965697,"tags":["qui","aliquip","pariatur","magna","ad","et","irure"],"friends":[{"id":0,"name":"Robyn Willis"},{"id":1,"name":"Gabrielle Holt"},{"id":2,"name":"Wilkerson Bailey"}],"greeting":"Hello, Hodges Richardson! You have 5 unread messages.","favoriteFruit":"strawberry"},{"_id":"6973b4f277b5d5924e85e34c","index":10,"guid":"24b6f2d6-f153-4826-9c2f-f50c42d907e5","isActive":true,"balance":"$1,715.09","picture":"http://placehold.it/32x32","age":33,"eyeColor":"blue","name":"Floyd Petty","gender":"male","company":"GINKOGENE","email":"floydpetty@ginkogene.com","phone":"+1 (832) 499-3944","address":"910 Canal Avenue, Mammoth, North Dakota, 1708","about":"Eiusmod velit proident sit proident ipsum irure. Excepteur dolore consequat labore duis tempor nulla laborum do amet labore. Amet nisi ullamco ad enim officia id exercitation aliquip in fugiat in. Anim quis et enim proident dolore magna mollit consectetur ea elit velit nostrud. Consectetur ea labore esse esse est nisi consectetur magna ut ullamco nulla ipsum exercitation.\r\n","registered":"2023-09-18T01:14:07 -07:00","latitude":-51.559233,"longitude":134.694377,"tags":["cupidatat","elit","commodo","ullamco","do","reprehenderit","nostrud"],"friends":[{"id":0,"name":"Naomi Garrison"},{"id":1,"name":"Betty English"},{"id":2,"name":"Prince Singleton"}],"greeting":"Hello, Floyd Petty! You have 7 unread messages.","favoriteFruit":"strawberry"},{"_id":"6973b4f2e7ad4e31bb2510c3","index":11,"guid":"74ccb6d9-7f24-4451-a3a0-e632bab385b3","isActive":true,"balance":"$1,490.53","picture":"http://placehold.it/32x32","age":36,"eyeColor":"blue","name":"Johnnie Simon","gender":"female","company":"JAMNATION","email":"johnniesimon@jamnation.com","phone":"+1 (868) 417-3009","address":"125 Chester Street, Whipholt, Maryland, 9466","about":"Dolor anim esse enim Lorem nostrud id officia incididunt amet laboris laboris sunt. Pariatur dolor aute Lorem aute magna. Laborum enim non voluptate commodo.\r\n","registered":"2015-03-03T08:28:39 -07:00","latitude":-19.882734,"longitude":-45.527604,"tags":["qui","sit","culpa","id","dolor","irure","id"],"friends":[{"id":0,"name":"Fry Ayers"},{"id":1,"name":"Donovan Foley"},{"id":2,"name":"Finch Dunn"}],"greeting":"Hello, Johnnie Simon! You have 9 unread messages.","favoriteFruit":"apple"},{"_id":"6973b4f24d0d75c705a54911","index":12,"guid":"f972a1ef-0d3a-41ab-b080-eaf7d26184f1","isActive":true,"balance":"$3,429.83","picture":"http://placehold.it/32x32","age":36,"eyeColor":"brown","name":"Rosalind Duran","gender":"female","company":"ZORROMOP","email":"rosalindduran@zorromop.com","phone":"+1 (987) 589-3940","address":"720 Mill Avenue, Gardiner, Nebraska, 6579","about":"Dolor deserunt nisi laborum eiusmod aliquip adipisicing ullamco eiusmod non qui consectetur est nostrud. Incididunt nostrud labore minim Lorem elit qui commodo consectetur ex culpa veniam. Quis ad quis cillum esse nisi ea ipsum consequat dolore. Non minim minim sint excepteur anim consectetur est voluptate laborum commodo. Mollit ea magna dolor sit ut magna voluptate ipsum reprehenderit id ex cillum deserunt.\r\n","registered":"2014-07-03T10:56:30 -07:00","latitude":-39.091253,"longitude":-131.671201,"tags":["labore","enim","nulla","est","exercitation","ipsum","deserunt"],"friends":[{"id":0,"name":"Emerson Dalton"},{"id":1,"name":"Owen Bass"},{"id":2,"name":"Bell Shannon"}],"greeting":"Hello, Rosalind Duran! You have 1 unread messages.","favoriteFruit":"banana"},{"_id":"6973b4f2edea35a5d2cea142","index":13,"guid":"18cf8f91-9735-4fa6-9381-ae8c1060890c","isActive":true,"balance":"$1,811.69","picture":"http://placehold.it/32x32","age":26,"eyeColor":"blue","name":"Pauline Cain","gender":"female","company":"ENAUT","email":"paulinecain@enaut.com","phone":"+1 (972) 408-3809","address":"508 Rapelye Street, Thynedale, Maine, 9391","about":"Qui enim fugiat do eu in eu aliqua elit cillum occaecat. Consectetur amet pariatur ea dolore Lorem eu ipsum veniam commodo commodo. Mollit dolore velit aliqua cillum elit consequat sunt nostrud in qui ipsum sit eu irure. Cupidatat reprehenderit labore in officia laborum.\r\n","registered":"2023-12-23T01:34:49 -07:00","latitude":-18.152332,"longitude":6.220963,"tags":["quis","sint","proident","officia","dolore","elit","quis"],"friends":[{"id":0,"name":"Kristie Shepherd"},{"id":1,"name":"Jensen Webster"},{"id":2,"name":"Langley Young"}],"greeting":"Hello, Pauline Cain! You have 7 unread messages.","favoriteFruit":"apple"}]',
|
|
302
|
+
testMessage: mediumMsg,
|
|
307
303
|
workerCount: WORKER_COUNT,
|
|
308
304
|
});
|
|
309
|
-
printResults(
|
|
310
|
-
"Test 3: Large Messages (50K msgs, 10KB)",
|
|
311
|
-
test3Results,
|
|
312
|
-
);
|
|
305
|
+
printResults("Test 3: Medium Messages (100K msgs, 10KB)", test3Results);
|
|
313
306
|
|
|
314
307
|
await cleanup();
|
|
315
308
|
|
|
316
|
-
|
|
309
|
+
// Calculate combined averages
|
|
310
|
+
const avgThroughput =
|
|
311
|
+
(test1Results.throughput +
|
|
312
|
+
test2Results.throughput +
|
|
313
|
+
test3Results.throughput) /
|
|
314
|
+
3;
|
|
315
|
+
const avgP50 =
|
|
316
|
+
(test1Results.p50 + test2Results.p50 + test3Results.p50) / 3;
|
|
317
|
+
const avgP95 =
|
|
318
|
+
(test1Results.p95 + test2Results.p95 + test3Results.p95) / 3;
|
|
319
|
+
const avgP99 =
|
|
320
|
+
(test1Results.p99 + test2Results.p99 + test3Results.p99) / 3;
|
|
317
321
|
|
|
318
322
|
// Summary
|
|
319
323
|
log("bright", `\n${"=".repeat(60)}`);
|
|
320
324
|
log("magenta", " š BENCHMARK SUMMARY");
|
|
321
325
|
log("bright", "=".repeat(60));
|
|
322
326
|
|
|
323
|
-
console.log("\n
|
|
327
|
+
console.log("\n Individual Queue Performance:");
|
|
324
328
|
console.log(
|
|
325
|
-
` -
|
|
329
|
+
` - Tiny messages (100B): ${test1Results.throughput.toFixed(0)} msg/s (p50: ${test1Results.p50.toFixed(2)}ms)`,
|
|
326
330
|
);
|
|
327
331
|
console.log(
|
|
328
|
-
` -
|
|
332
|
+
` - Small messages (1KB): ${test2Results.throughput.toFixed(0)} msg/s (p50: ${test2Results.p50.toFixed(2)}ms)`,
|
|
329
333
|
);
|
|
330
334
|
console.log(
|
|
331
|
-
` -
|
|
335
|
+
` - Medium messages (10KB): ${test3Results.throughput.toFixed(0)} msg/s (p50: ${test3Results.p50.toFixed(2)}ms)`,
|
|
332
336
|
);
|
|
333
337
|
|
|
334
|
-
log("bright",
|
|
338
|
+
log("bright", `\n${"=".repeat(60)}`);
|
|
335
339
|
|
|
336
340
|
log("green", "\nā
All stress tests completed successfully!");
|
|
337
341
|
|
|
338
342
|
log(
|
|
339
343
|
"yellow",
|
|
340
|
-
"\nš” To update README.md Performance section, use these values:",
|
|
344
|
+
"\nš” To update README.md Performance section, use these values (averaged across all tests):",
|
|
341
345
|
);
|
|
346
|
+
console.log("\n Overall:");
|
|
342
347
|
log(
|
|
343
348
|
"cyan",
|
|
344
|
-
` - Throughput
|
|
349
|
+
` - **Throughput**: ~${Math.round(avgThroughput).toLocaleString()} messages/second`,
|
|
345
350
|
);
|
|
346
|
-
log("cyan", ` - Latency (p50)
|
|
347
|
-
log("cyan", ` - Latency (p95)
|
|
348
|
-
log("cyan", ` - Latency (p99)
|
|
351
|
+
log("cyan", ` - **Latency (p50)**: ${avgP50.toFixed(2)} ms`);
|
|
352
|
+
log("cyan", ` - **Latency (p95)**: ${avgP95.toFixed(2)} ms`);
|
|
353
|
+
log("cyan", ` - **Latency (p99)**: ${avgP99.toFixed(2)} ms`);
|
|
349
354
|
} catch (error) {
|
|
350
355
|
log(
|
|
351
356
|
"red",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"id":"msg_82103","type":"notification","timestamp":1678892301,"payload":{"user_id":4092,"event":"login_attempt","status":"success"}}
|
package/biome.json
CHANGED
package/compose.yml
CHANGED
package/package.json
CHANGED