@zintrust/workers 0.4.27 → 0.4.34
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/dist/WorkerFactory.js +39 -15
- package/dist/build-manifest.json +28 -29
- package/dist/createQueueWorker.js +14 -9
- package/dist/index.d.ts +2 -1
- package/package.json +2 -2
- package/src/WorkerFactory.ts +54 -16
- package/src/createQueueWorker.ts +27 -13
- package/src/index.ts +3 -2
package/dist/WorkerFactory.js
CHANGED
|
@@ -100,7 +100,6 @@ const resolvePackageSpecifierUrl = (specifier) => {
|
|
|
100
100
|
return resolveLocalPackageFallback(specifier);
|
|
101
101
|
}
|
|
102
102
|
};
|
|
103
|
-
const escapeRegExp = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw `\$&`);
|
|
104
103
|
const rewriteProcessorImports = (code) => {
|
|
105
104
|
const replacements = [];
|
|
106
105
|
const coreUrl = resolvePackageSpecifierUrl('@zintrust/core');
|
|
@@ -113,8 +112,8 @@ const rewriteProcessorImports = (code) => {
|
|
|
113
112
|
return code;
|
|
114
113
|
let updated = code;
|
|
115
114
|
for (const { from, to } of replacements) {
|
|
116
|
-
|
|
117
|
-
updated = updated.
|
|
115
|
+
updated = updated.replaceAll(`'${from}'`, `'${to}'`);
|
|
116
|
+
updated = updated.replaceAll(`"${from}"`, `"${to}"`);
|
|
118
117
|
}
|
|
119
118
|
return updated;
|
|
120
119
|
};
|
|
@@ -330,14 +329,43 @@ const parseCacheControl = (value) => {
|
|
|
330
329
|
};
|
|
331
330
|
const getProcessorSpecConfig = () => workersConfig.processorSpec;
|
|
332
331
|
const toPosixPath = (value) => value.split(path.sep).join('/');
|
|
332
|
+
const isUpperAlpha = (value) => /^[A-Z]$/.test(value);
|
|
333
|
+
const isLowerAlphaOrDigit = (value) => /^[a-z\d]$/.test(value);
|
|
334
|
+
const isAlphaNumeric = (value) => /^[A-Za-z\d]$/.test(value);
|
|
335
|
+
const shouldInsertWorkerNameDash = (previous, current, next) => {
|
|
336
|
+
if (!isAlphaNumeric(previous) || !isAlphaNumeric(current))
|
|
337
|
+
return false;
|
|
338
|
+
if (isLowerAlphaOrDigit(previous) && isUpperAlpha(current)) {
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
341
|
+
if (isUpperAlpha(previous) && isUpperAlpha(current) && isLowerAlphaOrDigit(next ?? '')) {
|
|
342
|
+
return true;
|
|
343
|
+
}
|
|
344
|
+
return false;
|
|
345
|
+
};
|
|
346
|
+
const toKebabWorkerName = (value) => {
|
|
347
|
+
if (!isNonEmptyString(value))
|
|
348
|
+
return value;
|
|
349
|
+
let normalized = '';
|
|
350
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
351
|
+
const current = value[index] ?? '';
|
|
352
|
+
const previous = index > 0 ? (value[index - 1] ?? '') : '';
|
|
353
|
+
const next = value[index + 1];
|
|
354
|
+
if (current === ' ' || current === '_') {
|
|
355
|
+
if (!normalized.endsWith('-'))
|
|
356
|
+
normalized += '-';
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
if (shouldInsertWorkerNameDash(previous, current, next) && !normalized.endsWith('-')) {
|
|
360
|
+
normalized += '-';
|
|
361
|
+
}
|
|
362
|
+
normalized += current;
|
|
363
|
+
}
|
|
364
|
+
return normalized.replaceAll(/-+/g, '-');
|
|
365
|
+
};
|
|
333
366
|
const normalizeWorkerFileName = (fileName) => {
|
|
334
|
-
const baseName = fileName.
|
|
335
|
-
return baseName
|
|
336
|
-
.replaceAll(/([a-z\d])([A-Z])/g, '$1-$2')
|
|
337
|
-
.replaceAll(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1-$2')
|
|
338
|
-
.replaceAll(/[\s_]+/g, '-')
|
|
339
|
-
.replaceAll(/-+/g, '-')
|
|
340
|
-
.toLowerCase();
|
|
367
|
+
const baseName = fileName.replace(/\.[^.]+$/, '');
|
|
368
|
+
return toKebabWorkerName(baseName).toLowerCase();
|
|
341
369
|
};
|
|
342
370
|
const supportsWorkerFileDiscovery = () => {
|
|
343
371
|
return (isNodeRuntime() &&
|
|
@@ -1364,19 +1392,15 @@ const resolveRedisConfigFromEnv = (config, context) => {
|
|
|
1364
1392
|
};
|
|
1365
1393
|
const resolveRedisConfigFromDirect = (config, context) => {
|
|
1366
1394
|
const fallbackDb = Env.getInt('REDIS_QUEUE_DB', ZintrustLang.REDIS_DEFAULT_DB);
|
|
1367
|
-
const redisConfigWithDatabase = config;
|
|
1368
1395
|
let normalizedDb = fallbackDb;
|
|
1369
1396
|
if (typeof config.db === 'number') {
|
|
1370
1397
|
normalizedDb = config.db;
|
|
1371
1398
|
}
|
|
1372
|
-
else if (typeof redisConfigWithDatabase.database === 'number') {
|
|
1373
|
-
normalizedDb = redisConfigWithDatabase.database;
|
|
1374
|
-
}
|
|
1375
1399
|
return {
|
|
1376
1400
|
host: requireRedisHost(config.host, context),
|
|
1377
1401
|
port: config.port,
|
|
1378
1402
|
db: normalizedDb,
|
|
1379
|
-
password: config.password ?? Env.get('REDIS_PASSWORD'
|
|
1403
|
+
password: config.password ?? Env.get('REDIS_PASSWORD'),
|
|
1380
1404
|
};
|
|
1381
1405
|
};
|
|
1382
1406
|
const resolveRedisConfig = (config, context) => isRedisEnvConfig(config)
|
package/dist/build-manifest.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zintrust/workers",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"buildDate": "2026-03-
|
|
3
|
+
"version": "0.4.34",
|
|
4
|
+
"buildDate": "2026-03-29T19:24:26.213Z",
|
|
5
5
|
"buildEnvironment": {
|
|
6
|
-
"node": "
|
|
6
|
+
"node": "v22.22.1",
|
|
7
7
|
"platform": "darwin",
|
|
8
8
|
"arch": "arm64"
|
|
9
9
|
},
|
|
10
10
|
"git": {
|
|
11
|
-
"commit": "
|
|
11
|
+
"commit": "4abfecc6",
|
|
12
12
|
"branch": "dev"
|
|
13
13
|
},
|
|
14
14
|
"package": {
|
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
"@opentelemetry/api",
|
|
20
20
|
"hot-shots",
|
|
21
21
|
"ioredis",
|
|
22
|
-
"ml.js",
|
|
23
22
|
"prom-client",
|
|
24
23
|
"simple-statistics"
|
|
25
24
|
],
|
|
@@ -47,8 +46,8 @@
|
|
|
47
46
|
"sha256": "1a6d9ea39ba9e17fc16eb52294c10c3912024cb3009a8f9c07ffa576e754c7f4"
|
|
48
47
|
},
|
|
49
48
|
"BroadcastWorker.d.ts": {
|
|
50
|
-
"size":
|
|
51
|
-
"sha256": "
|
|
49
|
+
"size": 934,
|
|
50
|
+
"sha256": "ea5b05820fdd30d80f4483f476e400c78fa842ebbb29a442b2f1261dc0b2de8a"
|
|
52
51
|
},
|
|
53
52
|
"BroadcastWorker.js": {
|
|
54
53
|
"size": 821,
|
|
@@ -127,8 +126,8 @@
|
|
|
127
126
|
"sha256": "23837171b31c5242e4b43226cb0acae815dea0ce7b1628aa1428a86b24689230"
|
|
128
127
|
},
|
|
129
128
|
"NotificationWorker.d.ts": {
|
|
130
|
-
"size":
|
|
131
|
-
"sha256": "
|
|
129
|
+
"size": 952,
|
|
130
|
+
"sha256": "facdae5d7e82364ad9aab4398f8a3f8b5be8d8e9cb3aaa18fde76a88cd05b959"
|
|
132
131
|
},
|
|
133
132
|
"NotificationWorker.js": {
|
|
134
133
|
"size": 828,
|
|
@@ -175,20 +174,20 @@
|
|
|
175
174
|
"sha256": "555277c91f87899415cebf35eddc08d7c0b80cc55bfac7cb7fe96529cc927257"
|
|
176
175
|
},
|
|
177
176
|
"WorkerFactory.d.ts": {
|
|
178
|
-
"size":
|
|
179
|
-
"sha256": "
|
|
177
|
+
"size": 7716,
|
|
178
|
+
"sha256": "3869f960c87260588e40941ff91bffcfa0757be7a04815fd28b57dd4840c51df"
|
|
180
179
|
},
|
|
181
180
|
"WorkerFactory.js": {
|
|
182
|
-
"size":
|
|
183
|
-
"sha256": "
|
|
181
|
+
"size": 102783,
|
|
182
|
+
"sha256": "f2928a648eaedba8b8c9f6e211cd6fc5e8a5bb531dc656899b20db7ddaa702b9"
|
|
184
183
|
},
|
|
185
184
|
"WorkerInit.d.ts": {
|
|
186
|
-
"size":
|
|
187
|
-
"sha256": "
|
|
185
|
+
"size": 3284,
|
|
186
|
+
"sha256": "f902550cda7fca36f2db6297d39a4339ed6b5ff1c738da867233309cf0ca8fe1"
|
|
188
187
|
},
|
|
189
188
|
"WorkerInit.js": {
|
|
190
|
-
"size":
|
|
191
|
-
"sha256": "
|
|
189
|
+
"size": 14031,
|
|
190
|
+
"sha256": "51f44ca085a1682130aa36fed3acfd575108e974bf4c21eaa772001719c18853"
|
|
192
191
|
},
|
|
193
192
|
"WorkerMetrics.d.ts": {
|
|
194
193
|
"size": 3304,
|
|
@@ -231,8 +230,8 @@
|
|
|
231
230
|
"sha256": "8af20d462270e7044c6ea983821f5b6e6ce8a5caf39b6e8fefff07c9a0bf071e"
|
|
232
231
|
},
|
|
233
232
|
"build-manifest.json": {
|
|
234
|
-
"size":
|
|
235
|
-
"sha256": "
|
|
233
|
+
"size": 19590,
|
|
234
|
+
"sha256": "627732a0b46235bfeb923176bfc8e40265d42bc5abac5250002e431301a552e2"
|
|
236
235
|
},
|
|
237
236
|
"config/workerConfig.d.ts": {
|
|
238
237
|
"size": 132,
|
|
@@ -243,12 +242,12 @@
|
|
|
243
242
|
"sha256": "189c3b1d8a31de1c04206fcfacc1fed974a74684d7d70895cd20a03b35860ac6"
|
|
244
243
|
},
|
|
245
244
|
"createQueueWorker.d.ts": {
|
|
246
|
-
"size":
|
|
247
|
-
"sha256": "
|
|
245
|
+
"size": 1031,
|
|
246
|
+
"sha256": "dacd49f6c112eba439bdd9bb457eea90daedbf32efc381cd3189ce562fa5b0a8"
|
|
248
247
|
},
|
|
249
248
|
"createQueueWorker.js": {
|
|
250
|
-
"size":
|
|
251
|
-
"sha256": "
|
|
249
|
+
"size": 14103,
|
|
250
|
+
"sha256": "8e619da00200c0c1270674a6a2941ae050c8ade3e38925b5446916cddc2a8b65"
|
|
252
251
|
},
|
|
253
252
|
"dashboard/index.d.ts": {
|
|
254
253
|
"size": 109,
|
|
@@ -271,8 +270,8 @@
|
|
|
271
270
|
"sha256": "8e0e04329e1119d8ae835dd4458efead084293bcc2c263c09dd5a19d467e5ca4"
|
|
272
271
|
},
|
|
273
272
|
"dashboard/workers-api.js": {
|
|
274
|
-
"size":
|
|
275
|
-
"sha256": "
|
|
273
|
+
"size": 28207,
|
|
274
|
+
"sha256": "ae1ff0e962b1f64e6d200a35c3b8b1de968341d8df6283625a3efce50a23826c"
|
|
276
275
|
},
|
|
277
276
|
"helper/index.d.ts": {
|
|
278
277
|
"size": 159,
|
|
@@ -411,12 +410,12 @@
|
|
|
411
410
|
"sha256": "e90a171f2d8f6a62518099f825775b80299b934a7d48421bc1a3ebd6b065d617"
|
|
412
411
|
},
|
|
413
412
|
"index.d.ts": {
|
|
414
|
-
"size":
|
|
415
|
-
"sha256": "
|
|
413
|
+
"size": 2721,
|
|
414
|
+
"sha256": "0dcb7ca21683ab210eeb23d067e41b55ae996fa9e52c688371dc177f070ec059"
|
|
416
415
|
},
|
|
417
416
|
"index.js": {
|
|
418
|
-
"size":
|
|
419
|
-
"sha256": "
|
|
417
|
+
"size": 2337,
|
|
418
|
+
"sha256": "223686f6a65ebbea5599bdb509d8857d1cbdf57d20669a8d00eee5190ff654d3"
|
|
420
419
|
},
|
|
421
420
|
"register.d.ts": {
|
|
422
421
|
"size": 256,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as Core from '@zintrust/core';
|
|
2
2
|
import { Env, Logger, Queue } from '@zintrust/core';
|
|
3
|
+
const TypedQueue = Queue;
|
|
3
4
|
const RETRY_BASE_DELAY_MS = 1000;
|
|
4
5
|
const RETRY_MAX_DELAY_MS = 30000;
|
|
5
6
|
const getJobStateTracker = () => {
|
|
@@ -92,6 +93,12 @@ const buildBaseLogFields = (message, getLogFields) => {
|
|
|
92
93
|
...getLogFields(message.payload),
|
|
93
94
|
};
|
|
94
95
|
};
|
|
96
|
+
const toBullMQPayload = (payload) => {
|
|
97
|
+
if (typeof payload === 'object' && payload !== null) {
|
|
98
|
+
return { ...payload };
|
|
99
|
+
}
|
|
100
|
+
return { payload };
|
|
101
|
+
};
|
|
95
102
|
const getWorkerInstanceId = () => {
|
|
96
103
|
return typeof Env['WORKER_INSTANCE_ID'] === 'string'
|
|
97
104
|
? String(Env['WORKER_INSTANCE_ID'])
|
|
@@ -139,12 +146,12 @@ const checkAndRequeueIfNotDue = async (options, queueName, driverName, message,
|
|
|
139
146
|
...baseLogFields,
|
|
140
147
|
dueAt: new Date(timestamp).toISOString(),
|
|
141
148
|
});
|
|
142
|
-
await
|
|
143
|
-
await
|
|
149
|
+
await TypedQueue.enqueue(queueName, toBullMQPayload(message.payload), driverName);
|
|
150
|
+
await TypedQueue.ack(queueName, message.id, driverName);
|
|
144
151
|
return true;
|
|
145
152
|
};
|
|
146
153
|
const onProcessSuccess = async (input) => {
|
|
147
|
-
await
|
|
154
|
+
await TypedQueue.ack(input.queueName, input.message.id, input.driverName);
|
|
148
155
|
if (typeof input.trackerApi.completed === 'function') {
|
|
149
156
|
await input.trackerApi.completed({
|
|
150
157
|
queueName: input.queueName,
|
|
@@ -177,22 +184,20 @@ const onProcessFailure = async (input) => {
|
|
|
177
184
|
if (nextAttempts < input.options.maxAttempts) {
|
|
178
185
|
const retryDelayMs = getRetryDelayMs(nextAttempts);
|
|
179
186
|
retryAt = new Date(Date.now() + retryDelayMs).toISOString();
|
|
180
|
-
const currentPayload =
|
|
181
|
-
? input.message.payload
|
|
182
|
-
: { payload: input.message.payload };
|
|
187
|
+
const currentPayload = toBullMQPayload(input.message.payload);
|
|
183
188
|
const payloadForRetry = {
|
|
184
189
|
...currentPayload,
|
|
185
190
|
attempts: nextAttempts,
|
|
186
191
|
timestamp: Date.now() + retryDelayMs,
|
|
187
192
|
};
|
|
188
|
-
await
|
|
193
|
+
await TypedQueue.enqueue(input.queueName, payloadForRetry, input.driverName);
|
|
189
194
|
Logger.info(`${input.options.kindLabel} re-queued for retry`, {
|
|
190
195
|
...input.baseLogFields,
|
|
191
196
|
attempts: nextAttempts,
|
|
192
197
|
retryDelayMs,
|
|
193
198
|
});
|
|
194
199
|
}
|
|
195
|
-
await
|
|
200
|
+
await TypedQueue.ack(input.queueName, input.message.id, input.driverName);
|
|
196
201
|
await removeHeartbeatIfSupported(input.queueName, input.message.id);
|
|
197
202
|
if (typeof input.trackerApi.failed === 'function') {
|
|
198
203
|
await input.trackerApi.failed({
|
|
@@ -235,7 +240,7 @@ const startTrackingAndHeartbeat = async (input) => {
|
|
|
235
240
|
return { startedAtMs, heartbeatTimer };
|
|
236
241
|
};
|
|
237
242
|
const processQueueMessage = async (options, queueName, driverName) => {
|
|
238
|
-
const message =
|
|
243
|
+
const message = await TypedQueue.dequeue(queueName, driverName);
|
|
239
244
|
if (!message)
|
|
240
245
|
return false;
|
|
241
246
|
const baseLogFields = buildBaseLogFields(message, options.getLogFields);
|
package/dist/index.d.ts
CHANGED
|
@@ -32,11 +32,12 @@ export { BroadcastWorker } from './BroadcastWorker';
|
|
|
32
32
|
export { createQueueWorker } from './createQueueWorker';
|
|
33
33
|
export type { CreateQueueWorkerOptions } from './createQueueWorker';
|
|
34
34
|
export { NotificationWorker } from './NotificationWorker';
|
|
35
|
-
export type { RedisConfig, WorkerAutoScalingConfig, WorkerComplianceConfig, WorkerConfig, WorkerCostConfig, WorkerObservabilityConfig,
|
|
35
|
+
export type { RedisConfig, WorkerAutoScalingConfig, WorkerComplianceConfig, WorkerConfig, WorkerCostConfig, WorkerObservabilityConfig, WorkersConfigOverrides, WorkersGlobalConfig, WorkerStatus, WorkerVersioningConfig, } from '@zintrust/core';
|
|
36
36
|
export type { Job, Worker, WorkerOptions } from 'bullmq';
|
|
37
37
|
export type { IAnomaly, IAnomalyConfig, IForecast, IMetric, IPrediction, IRecommendation, IRootCauseAnalysis, } from './AnomalyDetection';
|
|
38
38
|
export type { IChaosComparison, IChaosExperiment, IChaosReport, IChaosStatus, } from './ChaosEngineering';
|
|
39
39
|
export type { ISLAConfig, ISLAReport, ISLAStatus, ISLAViolation, ITimeRange } from './SLAMonitor';
|
|
40
|
+
export type * from './config/workerConfig';
|
|
40
41
|
export type * from './type';
|
|
41
42
|
/**
|
|
42
43
|
* Package version and build metadata
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zintrust/workers",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.34",
|
|
4
4
|
"description": "Worker orchestration and background job management for ZinTrust.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"node": ">=20.0.0"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@zintrust/core": "^0.4.
|
|
43
|
+
"@zintrust/core": "^0.4.34",
|
|
44
44
|
"@zintrust/queue-monitor": "*",
|
|
45
45
|
"@zintrust/queue-redis": "*"
|
|
46
46
|
},
|
package/src/WorkerFactory.ts
CHANGED
|
@@ -141,9 +141,6 @@ const resolvePackageSpecifierUrl = (specifier: string): string | null => {
|
|
|
141
141
|
}
|
|
142
142
|
};
|
|
143
143
|
|
|
144
|
-
const escapeRegExp = (value: string): string =>
|
|
145
|
-
value.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
|
|
146
|
-
|
|
147
144
|
const rewriteProcessorImports = (code: string): string => {
|
|
148
145
|
const replacements: Array<{ from: string; to: string }> = [];
|
|
149
146
|
const coreUrl = resolvePackageSpecifierUrl('@zintrust/core');
|
|
@@ -155,8 +152,8 @@ const rewriteProcessorImports = (code: string): string => {
|
|
|
155
152
|
|
|
156
153
|
let updated = code;
|
|
157
154
|
for (const { from, to } of replacements) {
|
|
158
|
-
|
|
159
|
-
updated = updated.
|
|
155
|
+
updated = updated.replaceAll(`'${from}'`, `'${to}'`);
|
|
156
|
+
updated = updated.replaceAll(`"${from}"`, `"${to}"`);
|
|
160
157
|
}
|
|
161
158
|
|
|
162
159
|
return updated;
|
|
@@ -548,14 +545,58 @@ const getProcessorSpecConfig = (): typeof workersConfig.processorSpec =>
|
|
|
548
545
|
|
|
549
546
|
const toPosixPath = (value: string): string => value.split(path.sep).join('/');
|
|
550
547
|
|
|
548
|
+
const isUpperAlpha = (value: string): boolean => /^[A-Z]$/.test(value);
|
|
549
|
+
|
|
550
|
+
const isLowerAlphaOrDigit = (value: string): boolean => /^[a-z\d]$/.test(value);
|
|
551
|
+
|
|
552
|
+
const isAlphaNumeric = (value: string): boolean => /^[A-Za-z\d]$/.test(value);
|
|
553
|
+
|
|
554
|
+
const shouldInsertWorkerNameDash = (
|
|
555
|
+
previous: string,
|
|
556
|
+
current: string,
|
|
557
|
+
next: string | undefined
|
|
558
|
+
): boolean => {
|
|
559
|
+
if (!isAlphaNumeric(previous) || !isAlphaNumeric(current)) return false;
|
|
560
|
+
|
|
561
|
+
if (isLowerAlphaOrDigit(previous) && isUpperAlpha(current)) {
|
|
562
|
+
return true;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (isUpperAlpha(previous) && isUpperAlpha(current) && isLowerAlphaOrDigit(next ?? '')) {
|
|
566
|
+
return true;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
return false;
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
const toKebabWorkerName = (value: string): string => {
|
|
573
|
+
if (!isNonEmptyString(value)) return value;
|
|
574
|
+
|
|
575
|
+
let normalized = '';
|
|
576
|
+
|
|
577
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
578
|
+
const current = value[index] ?? '';
|
|
579
|
+
const previous = index > 0 ? (value[index - 1] ?? '') : '';
|
|
580
|
+
const next = value[index + 1];
|
|
581
|
+
|
|
582
|
+
if (current === ' ' || current === '_') {
|
|
583
|
+
if (!normalized.endsWith('-')) normalized += '-';
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
if (shouldInsertWorkerNameDash(previous, current, next) && !normalized.endsWith('-')) {
|
|
588
|
+
normalized += '-';
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
normalized += current;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
return normalized.replaceAll(/-+/g, '-');
|
|
595
|
+
};
|
|
596
|
+
|
|
551
597
|
const normalizeWorkerFileName = (fileName: string): string => {
|
|
552
|
-
const baseName = fileName.
|
|
553
|
-
return baseName
|
|
554
|
-
.replaceAll(/([a-z\d])([A-Z])/g, '$1-$2')
|
|
555
|
-
.replaceAll(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1-$2')
|
|
556
|
-
.replaceAll(/[\s_]+/g, '-')
|
|
557
|
-
.replaceAll(/-+/g, '-')
|
|
558
|
-
.toLowerCase();
|
|
598
|
+
const baseName = fileName.replace(/\.[^.]+$/, '');
|
|
599
|
+
return toKebabWorkerName(baseName).toLowerCase();
|
|
559
600
|
};
|
|
560
601
|
|
|
561
602
|
const supportsWorkerFileDiscovery = (): boolean => {
|
|
@@ -1984,20 +2025,17 @@ const resolveRedisConfigFromEnv = (config: RedisEnvConfig, context: string): Red
|
|
|
1984
2025
|
|
|
1985
2026
|
const resolveRedisConfigFromDirect = (config: RedisConfig, context: string): RedisConfig => {
|
|
1986
2027
|
const fallbackDb = Env.getInt('REDIS_QUEUE_DB', ZintrustLang.REDIS_DEFAULT_DB);
|
|
1987
|
-
const redisConfigWithDatabase = config as RedisConfig & { database?: number };
|
|
1988
2028
|
|
|
1989
2029
|
let normalizedDb = fallbackDb;
|
|
1990
2030
|
if (typeof config.db === 'number') {
|
|
1991
2031
|
normalizedDb = config.db;
|
|
1992
|
-
} else if (typeof redisConfigWithDatabase.database === 'number') {
|
|
1993
|
-
normalizedDb = redisConfigWithDatabase.database;
|
|
1994
2032
|
}
|
|
1995
2033
|
|
|
1996
2034
|
return {
|
|
1997
2035
|
host: requireRedisHost(config.host, context),
|
|
1998
2036
|
port: config.port,
|
|
1999
2037
|
db: normalizedDb,
|
|
2000
|
-
password: config.password ?? Env.get('REDIS_PASSWORD'
|
|
2038
|
+
password: config.password ?? Env.get('REDIS_PASSWORD'),
|
|
2001
2039
|
};
|
|
2002
2040
|
};
|
|
2003
2041
|
|
package/src/createQueueWorker.ts
CHANGED
|
@@ -2,6 +2,17 @@ import type { BullMQPayload, QueueMessage } from '@zintrust/core';
|
|
|
2
2
|
import * as Core from '@zintrust/core';
|
|
3
3
|
import { Env, Logger, Queue } from '@zintrust/core';
|
|
4
4
|
|
|
5
|
+
type QueueApi = Readonly<{
|
|
6
|
+
enqueue: (queue: string, payload: BullMQPayload, driverName?: string) => Promise<string>;
|
|
7
|
+
dequeue: <TPayload>(
|
|
8
|
+
queue: string,
|
|
9
|
+
driverName?: string
|
|
10
|
+
) => Promise<QueueMessage<TPayload> | undefined>;
|
|
11
|
+
ack: (queue: string, id: string, driverName?: string) => Promise<void>;
|
|
12
|
+
}>;
|
|
13
|
+
|
|
14
|
+
const TypedQueue = Queue as QueueApi;
|
|
15
|
+
|
|
5
16
|
const RETRY_BASE_DELAY_MS = 1000;
|
|
6
17
|
const RETRY_MAX_DELAY_MS = 30000;
|
|
7
18
|
|
|
@@ -97,9 +108,7 @@ const getAttemptsFromMessage = <TPayload>(message: QueueMessage<TPayload>): numb
|
|
|
97
108
|
typeof message.payload === 'object' && message.payload !== null
|
|
98
109
|
? normalizeAttempts((message.payload as Record<string, unknown>)['attempts'])
|
|
99
110
|
: 0;
|
|
100
|
-
const messageAttempts = normalizeAttempts(
|
|
101
|
-
(message as QueueMessage<TPayload> & { attempts?: number }).attempts
|
|
102
|
-
);
|
|
111
|
+
const messageAttempts = normalizeAttempts(message.attempts);
|
|
103
112
|
return Math.max(payloadAttempts, messageAttempts);
|
|
104
113
|
};
|
|
105
114
|
|
|
@@ -152,6 +161,14 @@ const buildBaseLogFields = <TPayload>(
|
|
|
152
161
|
};
|
|
153
162
|
};
|
|
154
163
|
|
|
164
|
+
const toBullMQPayload = <TPayload>(payload: TPayload): BullMQPayload => {
|
|
165
|
+
if (typeof payload === 'object' && payload !== null) {
|
|
166
|
+
return { ...(payload as Record<string, unknown>) };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return { payload };
|
|
170
|
+
};
|
|
171
|
+
|
|
155
172
|
type TrackerApi = {
|
|
156
173
|
started?: (input: {
|
|
157
174
|
queueName: string;
|
|
@@ -263,8 +280,8 @@ const checkAndRequeueIfNotDue = async <TPayload>(
|
|
|
263
280
|
...baseLogFields,
|
|
264
281
|
dueAt: new Date(timestamp).toISOString(),
|
|
265
282
|
});
|
|
266
|
-
await
|
|
267
|
-
await
|
|
283
|
+
await TypedQueue.enqueue(queueName, toBullMQPayload(message.payload), driverName);
|
|
284
|
+
await TypedQueue.ack(queueName, message.id, driverName);
|
|
268
285
|
return true;
|
|
269
286
|
};
|
|
270
287
|
|
|
@@ -277,7 +294,7 @@ const onProcessSuccess = async <TPayload>(input: {
|
|
|
277
294
|
startedAtMs: number;
|
|
278
295
|
baseLogFields: Record<string, unknown>;
|
|
279
296
|
}): Promise<boolean> => {
|
|
280
|
-
await
|
|
297
|
+
await TypedQueue.ack(input.queueName, input.message.id, input.driverName);
|
|
281
298
|
|
|
282
299
|
if (typeof input.trackerApi.completed === 'function') {
|
|
283
300
|
await input.trackerApi.completed({
|
|
@@ -324,10 +341,7 @@ const onProcessFailure = async <TPayload>(input: {
|
|
|
324
341
|
if (nextAttempts < input.options.maxAttempts) {
|
|
325
342
|
const retryDelayMs = getRetryDelayMs(nextAttempts);
|
|
326
343
|
retryAt = new Date(Date.now() + retryDelayMs).toISOString();
|
|
327
|
-
const currentPayload =
|
|
328
|
-
typeof input.message.payload === 'object' && input.message.payload !== null
|
|
329
|
-
? (input.message.payload as Record<string, unknown>)
|
|
330
|
-
: ({ payload: input.message.payload } as Record<string, unknown>);
|
|
344
|
+
const currentPayload = toBullMQPayload(input.message.payload);
|
|
331
345
|
|
|
332
346
|
const payloadForRetry: BullMQPayload = {
|
|
333
347
|
...currentPayload,
|
|
@@ -335,7 +349,7 @@ const onProcessFailure = async <TPayload>(input: {
|
|
|
335
349
|
timestamp: Date.now() + retryDelayMs,
|
|
336
350
|
};
|
|
337
351
|
|
|
338
|
-
await
|
|
352
|
+
await TypedQueue.enqueue(input.queueName, payloadForRetry, input.driverName);
|
|
339
353
|
Logger.info(`${input.options.kindLabel} re-queued for retry`, {
|
|
340
354
|
...input.baseLogFields,
|
|
341
355
|
attempts: nextAttempts,
|
|
@@ -343,7 +357,7 @@ const onProcessFailure = async <TPayload>(input: {
|
|
|
343
357
|
});
|
|
344
358
|
}
|
|
345
359
|
|
|
346
|
-
await
|
|
360
|
+
await TypedQueue.ack(input.queueName, input.message.id, input.driverName);
|
|
347
361
|
await removeHeartbeatIfSupported(input.queueName, input.message.id);
|
|
348
362
|
|
|
349
363
|
if (typeof input.trackerApi.failed === 'function') {
|
|
@@ -409,7 +423,7 @@ const processQueueMessage = async <TPayload>(
|
|
|
409
423
|
queueName: string,
|
|
410
424
|
driverName?: string
|
|
411
425
|
): Promise<boolean> => {
|
|
412
|
-
const message =
|
|
426
|
+
const message = await TypedQueue.dequeue<TPayload>(queueName, driverName);
|
|
413
427
|
if (!message) return false;
|
|
414
428
|
|
|
415
429
|
const baseLogFields = buildBaseLogFields(message, options.getLogFields);
|
package/src/index.ts
CHANGED
|
@@ -71,10 +71,10 @@ export type {
|
|
|
71
71
|
WorkerConfig,
|
|
72
72
|
WorkerCostConfig,
|
|
73
73
|
WorkerObservabilityConfig,
|
|
74
|
-
WorkerStatus,
|
|
75
|
-
WorkerVersioningConfig,
|
|
76
74
|
WorkersConfigOverrides,
|
|
77
75
|
WorkersGlobalConfig,
|
|
76
|
+
WorkerStatus,
|
|
77
|
+
WorkerVersioningConfig,
|
|
78
78
|
} from '@zintrust/core';
|
|
79
79
|
|
|
80
80
|
// Re-export bullmq types for type compatibility
|
|
@@ -97,6 +97,7 @@ export type {
|
|
|
97
97
|
} from './ChaosEngineering';
|
|
98
98
|
export type { ISLAConfig, ISLAReport, ISLAStatus, ISLAViolation, ITimeRange } from './SLAMonitor';
|
|
99
99
|
|
|
100
|
+
export type * from './config/workerConfig';
|
|
100
101
|
export type * from './type';
|
|
101
102
|
|
|
102
103
|
/**
|