@zintrust/workers 0.1.30 → 0.1.43
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/ClusterLock.js +3 -2
- package/dist/DeadLetterQueue.js +3 -2
- package/dist/HealthMonitor.js +24 -13
- package/dist/Observability.js +8 -0
- package/dist/WorkerFactory.d.ts +4 -0
- package/dist/WorkerFactory.js +384 -42
- package/dist/WorkerInit.js +122 -43
- package/dist/WorkerMetrics.js +5 -1
- package/dist/WorkerRegistry.js +8 -0
- package/dist/WorkerShutdown.d.ts +0 -13
- package/dist/WorkerShutdown.js +1 -44
- package/dist/build-manifest.json +99 -83
- package/dist/config/workerConfig.d.ts +1 -0
- package/dist/config/workerConfig.js +7 -1
- package/dist/createQueueWorker.js +281 -42
- package/dist/dashboard/workers-api.js +8 -1
- package/dist/http/WorkerController.js +90 -35
- package/dist/http/WorkerMonitoringService.js +29 -2
- package/dist/index.d.ts +1 -2
- package/dist/index.js +0 -1
- package/dist/routes/workers.js +10 -7
- package/dist/storage/WorkerStore.d.ts +6 -3
- package/dist/storage/WorkerStore.js +16 -0
- package/dist/telemetry/api/TelemetryMonitoringService.js +29 -2
- package/dist/ui/router/ui.js +58 -29
- package/dist/ui/workers/index.html +202 -0
- package/dist/ui/workers/main.js +1952 -0
- package/dist/ui/workers/styles.css +1350 -0
- package/dist/ui/workers/zintrust.svg +30 -0
- package/package.json +5 -5
- package/src/ClusterLock.ts +13 -7
- package/src/ComplianceManager.ts +3 -2
- package/src/DeadLetterQueue.ts +6 -4
- package/src/HealthMonitor.ts +33 -17
- package/src/Observability.ts +11 -0
- package/src/WorkerFactory.ts +446 -43
- package/src/WorkerInit.ts +167 -48
- package/src/WorkerMetrics.ts +14 -8
- package/src/WorkerRegistry.ts +11 -0
- package/src/WorkerShutdown.ts +1 -69
- package/src/config/workerConfig.ts +9 -1
- package/src/createQueueWorker.ts +428 -43
- package/src/dashboard/workers-api.ts +8 -1
- package/src/http/WorkerController.ts +111 -36
- package/src/http/WorkerMonitoringService.ts +35 -2
- package/src/index.ts +2 -3
- package/src/routes/workers.ts +10 -8
- package/src/storage/WorkerStore.ts +21 -3
- package/src/telemetry/api/TelemetryMonitoringService.ts +35 -2
- package/src/types/queue-monitor.d.ts +2 -1
- package/src/ui/router/EmbeddedAssets.ts +3 -0
- package/src/ui/router/ui.ts +57 -39
- package/src/WorkerShutdownDurableObject.ts +0 -64
package/dist/ClusterLock.js
CHANGED
|
@@ -131,8 +131,9 @@ export const ClusterLock = Object.freeze({
|
|
|
131
131
|
Logger.warn('ClusterLock already initialized');
|
|
132
132
|
return;
|
|
133
133
|
}
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
const client = createRedisConnection(config);
|
|
135
|
+
redisClient = client;
|
|
136
|
+
startHeartbeat(client);
|
|
136
137
|
Logger.info('ClusterLock initialized', { instanceId: getInstanceId() });
|
|
137
138
|
},
|
|
138
139
|
/**
|
package/dist/DeadLetterQueue.js
CHANGED
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
* Sealed namespace for immutability
|
|
5
5
|
*/
|
|
6
6
|
import { ErrorFactory, Logger, createRedisConnection } from '@zintrust/core';
|
|
7
|
+
import { keyPrefix } from './config/workerConfig';
|
|
7
8
|
// Redis key prefixes - using workers package prefix system
|
|
8
9
|
const getDLQPrefix = () => {
|
|
9
|
-
return '
|
|
10
|
+
return keyPrefix() + ':dlq:';
|
|
10
11
|
};
|
|
11
12
|
const getAuditPrefix = () => {
|
|
12
|
-
return '
|
|
13
|
+
return keyPrefix() + ':dlq:audit:';
|
|
13
14
|
};
|
|
14
15
|
// Internal state
|
|
15
16
|
let redisClient = null;
|
package/dist/HealthMonitor.js
CHANGED
|
@@ -24,7 +24,7 @@ const persistStatusChange = async (name, status, lastError) => {
|
|
|
24
24
|
Logger.error(`Failed to persist status change for ${name}`, err);
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
|
-
const verifyWorkerHealth = async (worker
|
|
27
|
+
const verifyWorkerHealth = async (worker) => {
|
|
28
28
|
// Check if isClosing exists (isClosing check safe for mocks)
|
|
29
29
|
const workerAny = worker;
|
|
30
30
|
const isClosingFn = workerAny['isClosing'];
|
|
@@ -40,9 +40,30 @@ const verifyWorkerHealth = async (worker, _name, _queueName) => {
|
|
|
40
40
|
if (pingResult !== 'PONG') {
|
|
41
41
|
throw ErrorFactory.createWorkerError(`Redis ping failed: ${pingResult}`);
|
|
42
42
|
}
|
|
43
|
-
Logger.debug(`Worker health verification passed for ${_name} ${_queueName}`);
|
|
44
43
|
return true;
|
|
45
44
|
};
|
|
45
|
+
const withTimeout = async (promise, timeoutMs, onTimeout) => {
|
|
46
|
+
let timeoutId = null;
|
|
47
|
+
return await new Promise((resolve, reject) => {
|
|
48
|
+
timeoutId = globalThis.setTimeout(() => {
|
|
49
|
+
if (timeoutId) {
|
|
50
|
+
clearTimeout(timeoutId);
|
|
51
|
+
timeoutId = null;
|
|
52
|
+
}
|
|
53
|
+
reject(onTimeout());
|
|
54
|
+
}, timeoutMs);
|
|
55
|
+
timeoutId.unref();
|
|
56
|
+
promise
|
|
57
|
+
.then(resolve)
|
|
58
|
+
.catch(reject)
|
|
59
|
+
.finally(() => {
|
|
60
|
+
if (timeoutId) {
|
|
61
|
+
clearTimeout(timeoutId);
|
|
62
|
+
timeoutId = null;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
};
|
|
46
67
|
const updateState = (state, isHealthy, errorMsg, latency) => {
|
|
47
68
|
const now = new Date();
|
|
48
69
|
state.lastCheck = now;
|
|
@@ -108,17 +129,7 @@ const performCheck = async (state) => {
|
|
|
108
129
|
if (!state.worker) {
|
|
109
130
|
throw ErrorFactory.createWorkerError('Worker instance not available');
|
|
110
131
|
}
|
|
111
|
-
isHealthy = await
|
|
112
|
-
verifyWorkerHealth(state.worker, state.name, state.queueName || 'unknown'),
|
|
113
|
-
new Promise((_, reject) => {
|
|
114
|
-
// eslint-disable-next-line
|
|
115
|
-
const id = setTimeout(() => {
|
|
116
|
-
reject(ErrorFactory.createWorkerError('Health check timeout'));
|
|
117
|
-
}, config.checkTimeoutMs);
|
|
118
|
-
// Unref to prevent holding event loop if everything else finishes
|
|
119
|
-
id.unref();
|
|
120
|
-
}),
|
|
121
|
-
]);
|
|
132
|
+
isHealthy = await withTimeout(verifyWorkerHealth(state.worker), config.checkTimeoutMs, () => ErrorFactory.createWorkerError('Health check timeout'));
|
|
122
133
|
}
|
|
123
134
|
catch (err) {
|
|
124
135
|
isHealthy = false;
|
package/dist/Observability.js
CHANGED
|
@@ -16,6 +16,11 @@ const activeSpans = new Map();
|
|
|
16
16
|
let spanSweepInterval = null;
|
|
17
17
|
const MAX_ACTIVE_SPANS = 1000;
|
|
18
18
|
const SPAN_TTL_MS = 5 * 60 * 1000;
|
|
19
|
+
const isUnrefableTimer = (value) => {
|
|
20
|
+
if (typeof value !== 'object' || value === null)
|
|
21
|
+
return false;
|
|
22
|
+
return 'unref' in value && typeof value.unref === 'function';
|
|
23
|
+
};
|
|
19
24
|
const cleanupStaleSpans = () => {
|
|
20
25
|
const now = Date.now();
|
|
21
26
|
for (const [spanId, entry] of activeSpans.entries()) {
|
|
@@ -155,6 +160,9 @@ export const Observability = Object.freeze({
|
|
|
155
160
|
spanSweepInterval = setInterval(() => {
|
|
156
161
|
cleanupStaleSpans();
|
|
157
162
|
}, SPAN_TTL_MS);
|
|
163
|
+
if (isUnrefableTimer(spanSweepInterval)) {
|
|
164
|
+
spanSweepInterval.unref();
|
|
165
|
+
}
|
|
158
166
|
}
|
|
159
167
|
Logger.info('Observability initialized', {
|
|
160
168
|
prometheus: config.prometheus.enabled,
|
package/dist/WorkerFactory.d.ts
CHANGED
|
@@ -111,6 +111,10 @@ export declare const WorkerFactory: Readonly<{
|
|
|
111
111
|
registerProcessorSpec: (spec: string, processor: WorkerFactoryConfig["processor"]) => void;
|
|
112
112
|
resolveProcessorPath: (modulePath: string) => Promise<WorkerFactoryConfig["processor"] | undefined>;
|
|
113
113
|
resolveProcessorSpec: (spec: string) => Promise<WorkerFactoryConfig["processor"] | undefined>;
|
|
114
|
+
/**
|
|
115
|
+
* Register a new worker configuration without starting it.
|
|
116
|
+
*/
|
|
117
|
+
register(config: WorkerFactoryConfig): Promise<void>;
|
|
114
118
|
/**
|
|
115
119
|
* Create new worker with full setup
|
|
116
120
|
*/
|