power-queues 2.1.8 → 2.1.10
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 +61 -36
- package/dist/index.cjs +5 -7
- package/dist/index.d.cts +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +5 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,15 +41,18 @@ const queue = new PowerQueues({
|
|
|
41
41
|
|
|
42
42
|
await queue.loadScripts(true);
|
|
43
43
|
|
|
44
|
-
await queue.addTasks('
|
|
45
|
-
{
|
|
46
|
-
{
|
|
44
|
+
await queue.addTasks('ws', [
|
|
45
|
+
{ body: 'welcome', userId: 42 },
|
|
46
|
+
{ body: 'hello', userId: 51 }
|
|
47
47
|
]);
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
Example of
|
|
50
|
+
Example of queue worker for sending message to client via WebSocket and executing a MySQL insert transaction:
|
|
51
51
|
|
|
52
52
|
``` ts
|
|
53
|
+
import express from 'express';
|
|
54
|
+
import http from 'http';
|
|
55
|
+
import { Server } from 'socket.io';
|
|
53
56
|
import mysql from 'mysql2/promise';
|
|
54
57
|
import Redis from 'ioredis';
|
|
55
58
|
import type { IORedisLike } from 'power-redis';
|
|
@@ -70,7 +73,11 @@ const pool = mysql.createPool({
|
|
|
70
73
|
});
|
|
71
74
|
const redis = new Redis('redis://127.0.0.1:6379');
|
|
72
75
|
|
|
73
|
-
|
|
76
|
+
const app = express();
|
|
77
|
+
const server = http.createServer(app);
|
|
78
|
+
const io = new Server(server);
|
|
79
|
+
|
|
80
|
+
export class WebSocketAndMysqlCreateQueue extends PowerQueues {
|
|
74
81
|
public readonly selectStuckCount: number = 256;
|
|
75
82
|
public readonly selectCount: number = 256;
|
|
76
83
|
public readonly retryCount: number = 3;
|
|
@@ -84,50 +91,68 @@ export class ExampleQueue extends PowerQueues {
|
|
|
84
91
|
this.redis = redis;
|
|
85
92
|
}
|
|
86
93
|
|
|
87
|
-
async
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
94
|
+
async onExecute(queueName: string, task: Task) {
|
|
95
|
+
const id = uuid();
|
|
96
|
+
|
|
97
|
+
io.to(`user:${task.payload.userId}`).emit('alerts', {
|
|
98
|
+
body: task.payload.body,
|
|
99
|
+
id,
|
|
100
|
+
});
|
|
101
|
+
return {
|
|
102
|
+
...task,
|
|
103
|
+
payload: {
|
|
104
|
+
...task.payload,
|
|
105
|
+
id,
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
102
109
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
110
|
+
async onBatchReady(queueName: string, tasks: Task[]) {
|
|
111
|
+
const values = tasks.map((task) => task.payload);
|
|
112
|
+
const conn = await pool.getConnection();
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
await conn.beginTransaction();
|
|
116
|
+
|
|
117
|
+
const cols = Object.keys(values[0]);
|
|
118
|
+
const placeholder = `(${cols.map(() => '?').join(',')})`;
|
|
119
|
+
const sql = `INSERT INTO \`alerts\` (${cols.map((c) => `\`${c}\``).join(',')}) VALUES ${values.map(() => placeholder).join(',')}`;
|
|
120
|
+
const params = [];
|
|
121
|
+
|
|
122
|
+
for (const row of values) {
|
|
123
|
+
for (const c of cols) {
|
|
124
|
+
params.push(row[c]);
|
|
107
125
|
}
|
|
108
|
-
await conn.execute(sql, params);
|
|
109
|
-
await conn.commit();
|
|
110
|
-
}
|
|
111
|
-
catch (err) {
|
|
112
|
-
await conn.rollback();
|
|
113
|
-
throw err;
|
|
114
|
-
}
|
|
115
|
-
finally {
|
|
116
|
-
conn.release();
|
|
117
126
|
}
|
|
127
|
+
await conn.execute(sql, params);
|
|
128
|
+
await conn.commit();
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
await queryRunner.rollbackTransaction();
|
|
132
|
+
throw err;
|
|
133
|
+
}
|
|
134
|
+
finally {
|
|
135
|
+
await queryRunner.release();
|
|
118
136
|
}
|
|
119
137
|
}
|
|
120
138
|
|
|
139
|
+
async onError(err: any, queueName: string, task: Task): Promise<Task> {
|
|
140
|
+
console.error('Alert error', queueName, task, (process.env.NODE_ENV === 'production')
|
|
141
|
+
? err.message
|
|
142
|
+
: err);
|
|
143
|
+
return task;
|
|
144
|
+
}
|
|
145
|
+
|
|
121
146
|
async onBatchError(err: any, queueName: string, tasks: Array<[ string, any, number, string, string, number ]>) {
|
|
122
|
-
|
|
147
|
+
console.error('Batch error', queueName, tasks.length, (process.env.NODE_ENV === 'production')
|
|
123
148
|
? err.message
|
|
124
|
-
: err
|
|
149
|
+
: err);
|
|
125
150
|
}
|
|
126
151
|
}
|
|
127
152
|
|
|
128
153
|
const exampleQueue = new ExampleQueue();
|
|
129
154
|
|
|
130
|
-
exampleQueue.runQueue('
|
|
155
|
+
exampleQueue.runQueue('ws');
|
|
131
156
|
```
|
|
132
157
|
|
|
133
158
|
## ⚖️ power-queues vs Existing Solutions
|
package/dist/index.cjs
CHANGED
|
@@ -569,22 +569,20 @@ var PowerQueues = class extends import_power_redis.PowerRedis {
|
|
|
569
569
|
const taskP = { ...task };
|
|
570
570
|
if (!(taskP.attempt >= this.retryCount - 1)) {
|
|
571
571
|
await this.onRetry(err, queueName, taskP);
|
|
572
|
-
await this.addTasks(queueName, [{ ...taskP.payload }], {
|
|
572
|
+
await this.addTasks(queueName, [{ ...taskP.payload, idemKey: taskP.idemKey }], {
|
|
573
573
|
createdAt: taskP.createdAt,
|
|
574
574
|
job: taskP.job,
|
|
575
|
-
attempt: (taskP.attempt || 0) + 1
|
|
576
|
-
idemKey: taskP.idemKey
|
|
575
|
+
attempt: (taskP.attempt || 0) + 1
|
|
577
576
|
});
|
|
578
577
|
} else if (this.logStatus) {
|
|
579
578
|
const dlqKey = queueName + ":dlq";
|
|
580
579
|
const statusKey = `${queueName}:${taskP.job}:`;
|
|
581
580
|
await this.incr(statusKey + "err", this.logStatusTimeout);
|
|
582
581
|
await this.incr(statusKey + "ready", this.logStatusTimeout);
|
|
583
|
-
await this.addTasks(dlqKey, [{ ...taskP.payload }], {
|
|
582
|
+
await this.addTasks(dlqKey, [{ ...taskP.payload, idemKey: taskP.idemKey }], {
|
|
584
583
|
createdAt: taskP.createdAt,
|
|
585
584
|
job: taskP.job,
|
|
586
|
-
attempt: taskP.attempt
|
|
587
|
-
idemKey: taskP.idemKey
|
|
585
|
+
attempt: taskP.attempt
|
|
588
586
|
});
|
|
589
587
|
}
|
|
590
588
|
return await this.onError(err, queueName, { ...taskP, attempt: (taskP.attempt || 0) + 1 });
|
|
@@ -773,7 +771,7 @@ var PowerQueues = class extends import_power_redis.PowerRedis {
|
|
|
773
771
|
payload: JSON.stringify(taskP),
|
|
774
772
|
attempt: Number(opts.attempt || 0),
|
|
775
773
|
job: opts.job ?? (0, import_uuid.v4)(),
|
|
776
|
-
idemKey: String(
|
|
774
|
+
idemKey: String(idemKey || (0, import_uuid.v4)()),
|
|
777
775
|
createdAt
|
|
778
776
|
};
|
|
779
777
|
const reqKeysLength = this.keysLength(entry);
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -549,22 +549,20 @@ var PowerQueues = class extends PowerRedis {
|
|
|
549
549
|
const taskP = { ...task };
|
|
550
550
|
if (!(taskP.attempt >= this.retryCount - 1)) {
|
|
551
551
|
await this.onRetry(err, queueName, taskP);
|
|
552
|
-
await this.addTasks(queueName, [{ ...taskP.payload }], {
|
|
552
|
+
await this.addTasks(queueName, [{ ...taskP.payload, idemKey: taskP.idemKey }], {
|
|
553
553
|
createdAt: taskP.createdAt,
|
|
554
554
|
job: taskP.job,
|
|
555
|
-
attempt: (taskP.attempt || 0) + 1
|
|
556
|
-
idemKey: taskP.idemKey
|
|
555
|
+
attempt: (taskP.attempt || 0) + 1
|
|
557
556
|
});
|
|
558
557
|
} else if (this.logStatus) {
|
|
559
558
|
const dlqKey = queueName + ":dlq";
|
|
560
559
|
const statusKey = `${queueName}:${taskP.job}:`;
|
|
561
560
|
await this.incr(statusKey + "err", this.logStatusTimeout);
|
|
562
561
|
await this.incr(statusKey + "ready", this.logStatusTimeout);
|
|
563
|
-
await this.addTasks(dlqKey, [{ ...taskP.payload }], {
|
|
562
|
+
await this.addTasks(dlqKey, [{ ...taskP.payload, idemKey: taskP.idemKey }], {
|
|
564
563
|
createdAt: taskP.createdAt,
|
|
565
564
|
job: taskP.job,
|
|
566
|
-
attempt: taskP.attempt
|
|
567
|
-
idemKey: taskP.idemKey
|
|
565
|
+
attempt: taskP.attempt
|
|
568
566
|
});
|
|
569
567
|
}
|
|
570
568
|
return await this.onError(err, queueName, { ...taskP, attempt: (taskP.attempt || 0) + 1 });
|
|
@@ -753,7 +751,7 @@ var PowerQueues = class extends PowerRedis {
|
|
|
753
751
|
payload: JSON.stringify(taskP),
|
|
754
752
|
attempt: Number(opts.attempt || 0),
|
|
755
753
|
job: opts.job ?? uuid(),
|
|
756
|
-
idemKey: String(
|
|
754
|
+
idemKey: String(idemKey || uuid()),
|
|
757
755
|
createdAt
|
|
758
756
|
};
|
|
759
757
|
const reqKeysLength = this.keysLength(entry);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "power-queues",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.10",
|
|
4
4
|
"description": "High-performance Redis Streams queue for Node.js with Lua-powered bulk XADD, idempotent workers, heartbeat locks, stuck-task recovery, retries, DLQ, and distributed processing.",
|
|
5
5
|
"author": "ihor-bielchenko",
|
|
6
6
|
"license": "MIT",
|