n8n-nodes-bozonx-redis-sugar 1.21.0 → 1.23.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 +22 -5
- package/dist/nodes/RedisListSugar/BozonxRedisListSugar.node.js +14 -3
- package/dist/nodes/RedisListSugar/BozonxRedisListSugar.node.js.map +1 -1
- package/dist/nodes/RedisQueueComplete/BozonxRedisQueueComplete.node.js +15 -27
- package/dist/nodes/RedisQueueComplete/BozonxRedisQueueComplete.node.js.map +1 -1
- package/dist/nodes/RedisQueueConsumer/BozonxRedisQueueConsumer.node.js +76 -114
- package/dist/nodes/RedisQueueConsumer/BozonxRedisQueueConsumer.node.js.map +1 -1
- package/dist/nodes/RedisQueueProducer/BozonxRedisQueueProducer.node.js +21 -19
- package/dist/nodes/RedisQueueProducer/BozonxRedisQueueProducer.node.js.map +1 -1
- package/dist/nodes/RedisStreamTrigger/BozonxRedisStreamTrigger.node.js +2 -2
- package/dist/nodes/RedisStreamTrigger/BozonxRedisStreamTrigger.node.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -83,13 +83,13 @@ Emitted item example:
|
|
|
83
83
|
|
|
84
84
|
### 4) Redis Queue Add
|
|
85
85
|
|
|
86
|
-
Add jobs to a Redis-based queue for sequential processing.
|
|
86
|
+
Add jobs to a Redis-based queue for **strictly sequential** (one-by-one) processing. This queue is designed to handle tasks that must not run in parallel for the same Job Name.
|
|
87
87
|
|
|
88
88
|
- **Queue ID**: unique identifier for the queue (leave empty to use current workflow ID)
|
|
89
|
-
- **Job Name**: optional name to group jobs within the same queue (e.g., separate queues per user: `user-123`)
|
|
89
|
+
- **Job Name**: optional name to group jobs within the same queue (e.g., separate queues per user: `user-123`). Jobs with the same Name are processed strictly one-by-one.
|
|
90
90
|
- **Data**: job data in YAML/JSON format (leave empty to use incoming item)
|
|
91
|
-
- **
|
|
92
|
-
-
|
|
91
|
+
- **Lock TTL (seconds)**: maximum allowed processing time for the job. If the job isn't finished within this time, the producer will error out and the lock will eventually expire, allowing the next job to start.
|
|
92
|
+
- **Response Timeout (seconds)**: how long the Producer should wait for the Worker to finish before giving up with an error.
|
|
93
93
|
|
|
94
94
|
**Redis structure:**
|
|
95
95
|
- Without Job Name: `queue:{queueId}`
|
|
@@ -151,7 +151,24 @@ Output:
|
|
|
151
151
|
```
|
|
152
152
|
|
|
153
153
|
- `isLast`: `true` if this was the last job in the queue (queue is now empty)
|
|
154
|
-
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
### Understanding the Queue (Concurrency & Locks)
|
|
158
|
+
|
|
159
|
+
#### Strictly Sequential Execution
|
|
160
|
+
This queue implementation is **intentionally non-concurrent**.
|
|
161
|
+
- Within a single `Queue ID` + `Job Name` combination, only **one job is processed at a time**.
|
|
162
|
+
- If a new job is added while another is running, it will stay in the Redis list until the current job calls **Redis Queue Complete**.
|
|
163
|
+
- Different `Job Names` (e.g., different users) are processed in parallel.
|
|
164
|
+
|
|
165
|
+
#### The "Leaked Lock" Problem
|
|
166
|
+
If a consumer workflow crashes or stops before reaching the **Redis Queue Complete** node, the queue for that specific `Job Name` will "freeze" because the lock key still exists in Redis.
|
|
167
|
+
|
|
168
|
+
**How to fix/prevent this:**
|
|
169
|
+
1. **Set a reasonable Lock TTL**: Don't use 1 hour if your task takes 10 seconds. The queue will automatically unfreeze once the TTL expires.
|
|
170
|
+
2. **Use Error Handling**: In n8n, create an **Error Stub** or use the **Error Trigger** node to call the **Redis Queue Complete** node even if your main logic fails.
|
|
171
|
+
3. **Manual Release**: You can manually delete the lock key in Redis to unfreeze the queue. The key format is `queue:{queueId}:{jobName}:lock`.
|
|
155
172
|
|
|
156
173
|
### 7) Redis List Sugar
|
|
157
174
|
|
|
@@ -171,9 +171,20 @@ class BozonxRedisListSugar {
|
|
|
171
171
|
}
|
|
172
172
|
else if (operation === 'deleteIndex') {
|
|
173
173
|
const index = this.getNodeParameter('index', i);
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
174
|
+
const script = `
|
|
175
|
+
local key = KEYS[1]
|
|
176
|
+
local index = tonumber(ARGV[1])
|
|
177
|
+
local sentinel = ARGV[2]
|
|
178
|
+
local exists = redis.call('LINDEX', key, index)
|
|
179
|
+
if exists then
|
|
180
|
+
redis.call('LSET', key, index, sentinel)
|
|
181
|
+
return redis.call('LREM', key, 1, sentinel)
|
|
182
|
+
else
|
|
183
|
+
return 0
|
|
184
|
+
end
|
|
185
|
+
`;
|
|
186
|
+
const sentinel = `__DELETED_${Math.random().toString(36).substring(2)}_${Date.now()}__`;
|
|
187
|
+
result = (await c.sendCommand(['EVAL', script, '1', listId, String(index), sentinel]));
|
|
177
188
|
}
|
|
178
189
|
else if (operation === 'replace') {
|
|
179
190
|
const index = this.getNodeParameter('index', i);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BozonxRedisListSugar.node.js","sourceRoot":"","sources":["../../../nodes/RedisListSugar/BozonxRedisListSugar.node.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"BozonxRedisListSugar.node.js","sourceRoot":"","sources":["../../../nodes/RedisListSugar/BozonxRedisListSugar.node.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,7 +10,7 @@ class BozonxRedisQueueComplete {
|
|
|
10
10
|
name: 'bozonxRedisQueueComplete',
|
|
11
11
|
group: ['transform'],
|
|
12
12
|
version: 1,
|
|
13
|
-
description: 'Release queue lock
|
|
13
|
+
description: 'Release queue lock (ESSENTIAL to allow next job to start) and check status',
|
|
14
14
|
defaults: { name: 'Redis Queue Complete' },
|
|
15
15
|
icon: 'file:redis-queue-complete.svg',
|
|
16
16
|
inputs: ['main'],
|
|
@@ -22,21 +22,6 @@ class BozonxRedisQueueComplete {
|
|
|
22
22
|
},
|
|
23
23
|
],
|
|
24
24
|
properties: [
|
|
25
|
-
{
|
|
26
|
-
displayName: 'Queue ID',
|
|
27
|
-
name: 'queueId',
|
|
28
|
-
type: 'string',
|
|
29
|
-
default: '={{ $json.queueId }}',
|
|
30
|
-
required: true,
|
|
31
|
-
description: 'Queue identifier from the trigger node',
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
displayName: 'Job Name',
|
|
35
|
-
name: 'jobName',
|
|
36
|
-
type: 'string',
|
|
37
|
-
default: '={{ $json.jobName }}',
|
|
38
|
-
description: 'Optional job name from the trigger node (for grouped queues)',
|
|
39
|
-
},
|
|
40
25
|
{
|
|
41
26
|
displayName: 'Job ID',
|
|
42
27
|
name: 'jobId',
|
|
@@ -70,19 +55,20 @@ class BozonxRedisQueueComplete {
|
|
|
70
55
|
const client = await (0, redisClient_1.getRedisClientConnected)({ host, port, username, password, tls, db });
|
|
71
56
|
for (let i = 0; i < items.length; i++) {
|
|
72
57
|
try {
|
|
73
|
-
const queueId = String(this.getNodeParameter('queueId', i) || '').trim();
|
|
74
|
-
const jobName = String(this.getNodeParameter('jobName', i, '') || '').trim();
|
|
75
58
|
const jobId = String(this.getNodeParameter('jobId', i) || '').trim();
|
|
76
59
|
const includeInputFields = this.getNodeParameter('includeInputFields', i, false);
|
|
77
|
-
if (!queueId) {
|
|
78
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Queue ID is required', { itemIndex: i });
|
|
79
|
-
}
|
|
80
60
|
if (!jobId) {
|
|
81
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Job ID is
|
|
61
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Job ID is missing. Ensure the input data contains "jobId" (usually comes from the Redis Queue Trigger).', { itemIndex: i });
|
|
62
|
+
}
|
|
63
|
+
const jobIdParts = jobId.split(':');
|
|
64
|
+
if (jobIdParts.length < 2) {
|
|
65
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid jobId format. Expected format: callbackId:queueIdentifier:executionId:itemIndex:random, got: ${jobId}`, { itemIndex: i });
|
|
82
66
|
}
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
const
|
|
67
|
+
const callbackId = jobIdParts[0];
|
|
68
|
+
const queueIdentifier = jobIdParts[1];
|
|
69
|
+
const queueKey = `queue:${callbackId}`;
|
|
70
|
+
const lockKey = `lock:${callbackId}:${queueIdentifier}`;
|
|
71
|
+
const responseKey = `response:${callbackId}:${jobId}`;
|
|
86
72
|
const c = client;
|
|
87
73
|
const queueLength = (await c.sendCommand(['LLEN', queueKey]));
|
|
88
74
|
const isLast = queueLength === 0;
|
|
@@ -92,14 +78,16 @@ class BozonxRedisQueueComplete {
|
|
|
92
78
|
isLast,
|
|
93
79
|
};
|
|
94
80
|
const responseData = JSON.stringify(responsePayload);
|
|
81
|
+
this.logger.debug(`Sending response for job ${jobId} to ${responseKey}`);
|
|
95
82
|
await c.sendCommand(['RPUSH', responseKey, responseData]);
|
|
96
83
|
await c.sendCommand(['EXPIRE', responseKey, '60']);
|
|
84
|
+
this.logger.debug(`Releasing lock for identifier ${queueIdentifier} (key: ${lockKey})`);
|
|
97
85
|
await c.sendCommand(['DEL', lockKey]);
|
|
98
86
|
const result = {
|
|
99
87
|
data: inputData,
|
|
100
88
|
isLast,
|
|
101
|
-
|
|
102
|
-
|
|
89
|
+
callbackId,
|
|
90
|
+
queueIdentifier,
|
|
103
91
|
jobId,
|
|
104
92
|
};
|
|
105
93
|
returnData.push({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BozonxRedisQueueComplete.node.js","sourceRoot":"","sources":["../../../nodes/RedisQueueComplete/BozonxRedisQueueComplete.node.ts"],"names":[],"mappings":";;;AAAA,+CAOsB;AACtB,+CAAwD;AAExD,MAAa,wBAAwB;IAArC;QACC,gBAAW,GAAyB;YACnC,WAAW,EAAE,sBAAsB;YACnC,IAAI,EAAE,0BAA0B;YAChC,KAAK,EAAE,CAAC,WAAW,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"BozonxRedisQueueComplete.node.js","sourceRoot":"","sources":["../../../nodes/RedisQueueComplete/BozonxRedisQueueComplete.node.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,7 +9,7 @@ class BozonxRedisQueueConsumer {
|
|
|
9
9
|
name: 'bozonxRedisQueueConsumer',
|
|
10
10
|
group: ['trigger'],
|
|
11
11
|
version: 1,
|
|
12
|
-
description: 'Process jobs from a Redis-based queue',
|
|
12
|
+
description: 'Process jobs from a Redis-based queue. Automatically handles parallel processing per queue identifier while maintaining sequential order within each identifier.',
|
|
13
13
|
defaults: { name: 'Redis Queue Trigger' },
|
|
14
14
|
icon: 'file:redis-queue-consumer.svg',
|
|
15
15
|
inputs: [],
|
|
@@ -22,20 +22,22 @@ class BozonxRedisQueueConsumer {
|
|
|
22
22
|
],
|
|
23
23
|
properties: [
|
|
24
24
|
{
|
|
25
|
-
displayName: '
|
|
26
|
-
name: '
|
|
25
|
+
displayName: 'Callback ID',
|
|
26
|
+
name: 'callbackId',
|
|
27
27
|
type: 'string',
|
|
28
28
|
default: '',
|
|
29
29
|
placeholder: 'Leave empty to use current workflow ID',
|
|
30
|
-
description: '
|
|
30
|
+
description: 'Identifier that links this trigger to producers. Leave empty to use the current workflow ID.',
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
|
-
displayName: '
|
|
34
|
-
name: '
|
|
35
|
-
type: '
|
|
36
|
-
default:
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
displayName: 'Polling Interval (ms)',
|
|
34
|
+
name: 'pollingInterval',
|
|
35
|
+
type: 'number',
|
|
36
|
+
default: 1000,
|
|
37
|
+
typeOptions: {
|
|
38
|
+
minValue: 100,
|
|
39
|
+
},
|
|
40
|
+
description: 'How long to wait (in milliseconds) before checking for the lock to be released or retrying an operation. Lower values increase responsiveness but also Redis CPU usage.',
|
|
39
41
|
},
|
|
40
42
|
],
|
|
41
43
|
usableAsTool: true,
|
|
@@ -52,125 +54,85 @@ class BozonxRedisQueueConsumer {
|
|
|
52
54
|
const db = (_b = creds === null || creds === void 0 ? void 0 : creds.db) !== null && _b !== void 0 ? _b : 0;
|
|
53
55
|
const client = await (0, redisClient_1.getRedisClientConnected)({ host, port, username, password, tls, db });
|
|
54
56
|
const c = client;
|
|
55
|
-
let
|
|
56
|
-
const
|
|
57
|
-
const blpopTimeout = 60;
|
|
57
|
+
let callbackId = String(this.getNodeParameter('callbackId', 0) || '').trim();
|
|
58
|
+
const blpopTimeout = 5;
|
|
58
59
|
const lockTTL = 3600;
|
|
59
|
-
|
|
60
|
+
const pollingInterval = this.getNodeParameter('pollingInterval', 1000);
|
|
61
|
+
if (!callbackId) {
|
|
60
62
|
const workflow = this.getWorkflow();
|
|
61
|
-
|
|
63
|
+
callbackId = workflow.id || 'default-queue';
|
|
62
64
|
}
|
|
63
|
-
const queueKey =
|
|
64
|
-
|
|
65
|
+
const queueKey = `queue:${callbackId}`;
|
|
66
|
+
this.logger.debug(`Redis Queue Trigger started for queue: ${queueKey}`);
|
|
65
67
|
let running = true;
|
|
66
|
-
const
|
|
67
|
-
var _a
|
|
68
|
-
|
|
68
|
+
const processJob = async (isManualTrigger = false) => {
|
|
69
|
+
var _a;
|
|
70
|
+
try {
|
|
71
|
+
const timeout = isManualTrigger ? '1' : String(blpopTimeout);
|
|
72
|
+
const res = await c.sendCommand(['BLPOP', queueKey, timeout]);
|
|
73
|
+
if (!res || !Array.isArray(res) || res.length < 2) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
const jobData = res[1];
|
|
77
|
+
let parsedPayload;
|
|
69
78
|
try {
|
|
70
|
-
|
|
71
|
-
if (lockExists === 1) {
|
|
72
|
-
await new Promise((r) => setTimeout(r, 1000));
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
if (!running)
|
|
76
|
-
break;
|
|
77
|
-
const res = await c.sendCommand(['BLPOP', queueKey, String(blpopTimeout)]);
|
|
78
|
-
if (!res || !Array.isArray(res) || res.length < 2) {
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
const jobData = res[1];
|
|
82
|
-
let parsedPayload;
|
|
83
|
-
try {
|
|
84
|
-
parsedPayload = JSON.parse(jobData);
|
|
85
|
-
}
|
|
86
|
-
catch (parseError) {
|
|
87
|
-
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.error(`Failed to parse job data from queue ${queueId}: ${parseError.message}`);
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
if (!parsedPayload.jobId) {
|
|
91
|
-
(_b = this.logger) === null || _b === void 0 ? void 0 : _b.error(`Missing jobId in job payload from queue ${queueId}`);
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
const effectiveLockTTL = (_c = parsedPayload.lockTTL) !== null && _c !== void 0 ? _c : lockTTL;
|
|
95
|
-
const acquired = await c.sendCommand([
|
|
96
|
-
'SET',
|
|
97
|
-
lockKey,
|
|
98
|
-
'1',
|
|
99
|
-
'NX',
|
|
100
|
-
'EX',
|
|
101
|
-
String(effectiveLockTTL),
|
|
102
|
-
]);
|
|
103
|
-
if (!acquired) {
|
|
104
|
-
await c.sendCommand(['LPUSH', queueKey, jobData]);
|
|
105
|
-
await new Promise((r) => setTimeout(r, 1000));
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
const result = {
|
|
109
|
-
data: parsedPayload.data,
|
|
110
|
-
queueId,
|
|
111
|
-
jobName: jobName || null,
|
|
112
|
-
jobId: parsedPayload.jobId,
|
|
113
|
-
};
|
|
114
|
-
this.emit([[{ json: { result } }]]);
|
|
79
|
+
parsedPayload = JSON.parse(jobData);
|
|
115
80
|
}
|
|
116
|
-
catch (
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
81
|
+
catch (parseError) {
|
|
82
|
+
this.logger.error(`Failed to parse job data from queue ${callbackId}: ${parseError.message}`);
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
if (!parsedPayload.jobId) {
|
|
86
|
+
this.logger.error(`Missing jobId in job payload from queue ${callbackId}`);
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const queueIdentifier = parsedPayload.queueIdentifier || 'default';
|
|
90
|
+
const lockKey = `lock:${callbackId}:${queueIdentifier}`;
|
|
91
|
+
const effectiveLockTTL = (_a = parsedPayload.lockTTL) !== null && _a !== void 0 ? _a : lockTTL;
|
|
92
|
+
this.logger.debug(`Processing job ${parsedPayload.jobId} for identifier ${queueIdentifier}`);
|
|
93
|
+
const acquired = await c.sendCommand([
|
|
94
|
+
'SET',
|
|
95
|
+
lockKey,
|
|
96
|
+
'1',
|
|
97
|
+
'NX',
|
|
98
|
+
'EX',
|
|
99
|
+
String(effectiveLockTTL),
|
|
100
|
+
]);
|
|
101
|
+
if (!acquired) {
|
|
102
|
+
this.logger.debug(`Job ${parsedPayload.jobId} is deferred because ${queueIdentifier} is locked`);
|
|
103
|
+
await c.sendCommand(['RPUSH', queueKey, jobData]);
|
|
104
|
+
if (!isManualTrigger) {
|
|
105
|
+
await new Promise((r) => setTimeout(r, pollingInterval));
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
120
108
|
}
|
|
109
|
+
const result = {
|
|
110
|
+
data: parsedPayload.data,
|
|
111
|
+
jobId: parsedPayload.jobId,
|
|
112
|
+
};
|
|
113
|
+
this.emit([[{ json: result }]]);
|
|
114
|
+
return [result];
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
this.logger.error(`Error processing job: ${error.message}`);
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const readLoop = async () => {
|
|
122
|
+
while (running) {
|
|
123
|
+
if (!running)
|
|
124
|
+
break;
|
|
125
|
+
await processJob(false);
|
|
121
126
|
}
|
|
122
127
|
};
|
|
123
128
|
void readLoop();
|
|
124
129
|
return {
|
|
125
130
|
closeFunction: async () => {
|
|
126
131
|
running = false;
|
|
132
|
+
this.logger.debug(`Redis Queue Trigger stopping for queue: ${queueKey}`);
|
|
127
133
|
},
|
|
128
134
|
manualTriggerFunction: async () => {
|
|
129
|
-
|
|
130
|
-
try {
|
|
131
|
-
const lockExists = (await c.sendCommand(['EXISTS', lockKey]));
|
|
132
|
-
if (lockExists === 1) {
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
const res = await c.sendCommand(['BLPOP', queueKey, String(blpopTimeout)]);
|
|
136
|
-
if (!res || !Array.isArray(res) || res.length < 2) {
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
const jobData = res[1];
|
|
140
|
-
let parsedPayload;
|
|
141
|
-
try {
|
|
142
|
-
parsedPayload = JSON.parse(jobData);
|
|
143
|
-
}
|
|
144
|
-
catch {
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
if (!parsedPayload.jobId) {
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
const effectiveLockTTL = (_a = parsedPayload.lockTTL) !== null && _a !== void 0 ? _a : lockTTL;
|
|
151
|
-
const acquired = await c.sendCommand([
|
|
152
|
-
'SET',
|
|
153
|
-
lockKey,
|
|
154
|
-
'1',
|
|
155
|
-
'NX',
|
|
156
|
-
'EX',
|
|
157
|
-
String(effectiveLockTTL),
|
|
158
|
-
]);
|
|
159
|
-
if (!acquired) {
|
|
160
|
-
await c.sendCommand(['LPUSH', queueKey, jobData]);
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
const result = {
|
|
164
|
-
data: parsedPayload.data,
|
|
165
|
-
queueId,
|
|
166
|
-
jobName: jobName || null,
|
|
167
|
-
jobId: parsedPayload.jobId,
|
|
168
|
-
};
|
|
169
|
-
this.emit([[{ json: { result } }]]);
|
|
170
|
-
}
|
|
171
|
-
catch (error) {
|
|
172
|
-
(_b = this.logger) === null || _b === void 0 ? void 0 : _b.error(`Error in manual trigger: ${error.message}`);
|
|
173
|
-
}
|
|
135
|
+
await processJob(true);
|
|
174
136
|
},
|
|
175
137
|
};
|
|
176
138
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BozonxRedisQueueConsumer.node.js","sourceRoot":"","sources":["../../../nodes/RedisQueueConsumer/BozonxRedisQueueConsumer.node.ts"],"names":[],"mappings":";;;AAOA,+CAAwD;AAQxD,MAAa,wBAAwB;IAArC;QACC,gBAAW,GAAyB;YACnC,WAAW,EAAE,qBAAqB;YAClC,IAAI,EAAE,0BAA0B;YAChC,KAAK,EAAE,CAAC,SAAS,CAAC;YAClB,OAAO,EAAE,CAAC;YACV,WAAW,
|
|
1
|
+
{"version":3,"file":"BozonxRedisQueueConsumer.node.js","sourceRoot":"","sources":["../../../nodes/RedisQueueConsumer/BozonxRedisQueueConsumer.node.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,7 +11,7 @@ class BozonxRedisQueueProducer {
|
|
|
11
11
|
name: 'bozonxRedisQueueProducer',
|
|
12
12
|
group: ['output'],
|
|
13
13
|
version: 1,
|
|
14
|
-
description: 'Add jobs to a Redis-based queue',
|
|
14
|
+
description: 'Add jobs to a Redis-based queue for strictly sequential processing',
|
|
15
15
|
defaults: { name: 'Redis Queue Add' },
|
|
16
16
|
icon: 'file:redis-queue-producer.svg',
|
|
17
17
|
inputs: ['main'],
|
|
@@ -24,20 +24,20 @@ class BozonxRedisQueueProducer {
|
|
|
24
24
|
],
|
|
25
25
|
properties: [
|
|
26
26
|
{
|
|
27
|
-
displayName: '
|
|
28
|
-
name: '
|
|
27
|
+
displayName: 'Callback ID',
|
|
28
|
+
name: 'callbackId',
|
|
29
29
|
type: 'string',
|
|
30
30
|
default: '',
|
|
31
31
|
placeholder: 'Leave empty to use current workflow ID',
|
|
32
|
-
description: '
|
|
32
|
+
description: 'Identifier that links this producer to a specific trigger. Leave empty to use the current workflow ID.',
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
|
-
displayName: '
|
|
36
|
-
name: '
|
|
35
|
+
displayName: 'Queue Identifier',
|
|
36
|
+
name: 'queueIdentifier',
|
|
37
37
|
type: 'string',
|
|
38
38
|
default: '',
|
|
39
|
-
placeholder: 'e.g., user-123,
|
|
40
|
-
description: 'Optional
|
|
39
|
+
placeholder: 'e.g., user-123, chat-456',
|
|
40
|
+
description: 'Optional identifier to create parallel queues (e.g., per user or chat). Jobs with the same identifier are processed sequentially, but different identifiers can run in parallel.',
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
displayName: 'Data (YAML / JSON)',
|
|
@@ -54,9 +54,9 @@ class BozonxRedisQueueProducer {
|
|
|
54
54
|
displayName: 'Lock TTL (seconds)',
|
|
55
55
|
name: 'lockTTL',
|
|
56
56
|
type: 'number',
|
|
57
|
-
default:
|
|
57
|
+
default: 60,
|
|
58
58
|
typeOptions: { minValue: 1 },
|
|
59
|
-
description: 'Maximum allowed processing time for the job. If the job
|
|
59
|
+
description: 'Maximum allowed processing time for the job. If the job doesn\'t finish within this time, the queue will "unfreeze" after this TTL expires. Set this as low as possible to avoid long lockups.',
|
|
60
60
|
},
|
|
61
61
|
{
|
|
62
62
|
displayName: 'Response Timeout (seconds)',
|
|
@@ -91,14 +91,14 @@ class BozonxRedisQueueProducer {
|
|
|
91
91
|
const client = await (0, redisClient_1.getRedisClientConnected)({ host, port, username, password, tls, db });
|
|
92
92
|
for (let i = 0; i < items.length; i++) {
|
|
93
93
|
try {
|
|
94
|
-
let
|
|
95
|
-
const
|
|
94
|
+
let callbackId = String(this.getNodeParameter('callbackId', i, '') || '').trim();
|
|
95
|
+
const queueIdentifier = String(this.getNodeParameter('queueIdentifier', i, '') || '').trim();
|
|
96
96
|
const lockTTL = this.getNodeParameter('lockTTL', i);
|
|
97
97
|
const responseTimeout = this.getNodeParameter('responseTimeout', i);
|
|
98
98
|
const includeInputFields = this.getNodeParameter('includeInputFields', i, false);
|
|
99
|
-
if (!
|
|
99
|
+
if (!callbackId) {
|
|
100
100
|
const workflow = this.getWorkflow();
|
|
101
|
-
|
|
101
|
+
callbackId = workflow.id || 'default-queue';
|
|
102
102
|
}
|
|
103
103
|
if (lockTTL < 1) {
|
|
104
104
|
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Lock TTL must be at least 1 second', {
|
|
@@ -126,15 +126,17 @@ class BozonxRedisQueueProducer {
|
|
|
126
126
|
else {
|
|
127
127
|
dataObj = dataParam;
|
|
128
128
|
}
|
|
129
|
-
const
|
|
129
|
+
const executionId = this.getExecutionId();
|
|
130
|
+
const jobId = `${callbackId}:${queueIdentifier || 'default'}:${executionId}:${i}:${Math.random().toString(36).substring(2, 7)}`;
|
|
130
131
|
const jobPayload = {
|
|
131
132
|
jobId,
|
|
132
133
|
data: dataObj,
|
|
133
134
|
lockTTL,
|
|
135
|
+
queueIdentifier,
|
|
134
136
|
};
|
|
135
137
|
const jobData = JSON.stringify(jobPayload);
|
|
136
|
-
const queueKey =
|
|
137
|
-
const responseKey = `response:${
|
|
138
|
+
const queueKey = `queue:${callbackId}`;
|
|
139
|
+
const responseKey = `response:${callbackId}:${jobId}`;
|
|
138
140
|
const queueTTL = (0, redisClient_1.calculateQueueTTL)(lockTTL);
|
|
139
141
|
const c = client;
|
|
140
142
|
const position = (await c.sendCommand(['RPUSH', queueKey, jobData]));
|
|
@@ -178,8 +180,8 @@ class BozonxRedisQueueProducer {
|
|
|
178
180
|
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to parse response data: ${parseError.message}`, { itemIndex: i });
|
|
179
181
|
}
|
|
180
182
|
const result = {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
+
callbackId,
|
|
184
|
+
queueIdentifier: queueIdentifier || null,
|
|
183
185
|
jobId,
|
|
184
186
|
position,
|
|
185
187
|
isFirst,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BozonxRedisQueueProducer.node.js","sourceRoot":"","sources":["../../../nodes/RedisQueueProducer/BozonxRedisQueueProducer.node.ts"],"names":[],"mappings":";;;AAAA,+CAOsB;AACtB,qCAA2C;AAC3C,+CAA2E;AAE3E,MAAa,wBAAwB;IAArC;QACC,gBAAW,GAAyB;YACnC,WAAW,EAAE,iBAAiB;YAC9B,IAAI,EAAE,0BAA0B;YAChC,KAAK,EAAE,CAAC,QAAQ,CAAC;YACjB,OAAO,EAAE,CAAC;YACV,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"BozonxRedisQueueProducer.node.js","sourceRoot":"","sources":["../../../nodes/RedisQueueProducer/BozonxRedisQueueProducer.node.ts"],"names":[],"mappings":"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"}
|