@cepseudo/engine 1.0.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/LICENSE +21 -0
- package/README.md +209 -0
- package/dist/component_types.d.ts +92 -0
- package/dist/component_types.d.ts.map +1 -0
- package/dist/component_types.js +93 -0
- package/dist/component_types.js.map +1 -0
- package/dist/digital_twin_engine.d.ts +390 -0
- package/dist/digital_twin_engine.d.ts.map +1 -0
- package/dist/digital_twin_engine.js +1200 -0
- package/dist/digital_twin_engine.js.map +1 -0
- package/dist/endpoints.d.ts +45 -0
- package/dist/endpoints.d.ts.map +1 -0
- package/dist/endpoints.js +87 -0
- package/dist/endpoints.js.map +1 -0
- package/dist/error_handler.d.ts +20 -0
- package/dist/error_handler.d.ts.map +1 -0
- package/dist/error_handler.js +68 -0
- package/dist/error_handler.js.map +1 -0
- package/dist/global_assets_handler.d.ts +63 -0
- package/dist/global_assets_handler.d.ts.map +1 -0
- package/dist/global_assets_handler.js +127 -0
- package/dist/global_assets_handler.js.map +1 -0
- package/dist/graceful_shutdown.d.ts +44 -0
- package/dist/graceful_shutdown.d.ts.map +1 -0
- package/dist/graceful_shutdown.js +79 -0
- package/dist/graceful_shutdown.js.map +1 -0
- package/dist/health.d.ts +112 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +190 -0
- package/dist/health.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/initializer.d.ts +62 -0
- package/dist/initializer.d.ts.map +1 -0
- package/dist/initializer.js +110 -0
- package/dist/initializer.js.map +1 -0
- package/dist/loader/component_loader.d.ts +133 -0
- package/dist/loader/component_loader.d.ts.map +1 -0
- package/dist/loader/component_loader.js +340 -0
- package/dist/loader/component_loader.js.map +1 -0
- package/dist/openapi/generator.d.ts +93 -0
- package/dist/openapi/generator.d.ts.map +1 -0
- package/dist/openapi/generator.js +293 -0
- package/dist/openapi/generator.js.map +1 -0
- package/dist/queue_manager.d.ts +87 -0
- package/dist/queue_manager.d.ts.map +1 -0
- package/dist/queue_manager.js +196 -0
- package/dist/queue_manager.js.map +1 -0
- package/dist/scheduler.d.ts +29 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +375 -0
- package/dist/scheduler.js.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview OpenAPI specification generator for Digital Twin components
|
|
3
|
+
*
|
|
4
|
+
* This module provides utilities to automatically generate OpenAPI 3.0
|
|
5
|
+
* documentation from Digital Twin components that implement OpenAPIDocumentable.
|
|
6
|
+
*/
|
|
7
|
+
import { isOpenAPIDocumentable } from '@cepseudo/shared';
|
|
8
|
+
/**
|
|
9
|
+
* Generates OpenAPI 3.0 specifications from Digital Twin components.
|
|
10
|
+
*
|
|
11
|
+
* The generator aggregates OpenAPI specs from all components that implement
|
|
12
|
+
* the OpenAPIDocumentable interface and produces a complete OpenAPI document.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import { OpenAPIGenerator } from 'digitaltwin-core'
|
|
17
|
+
* import * as components from './src/components'
|
|
18
|
+
*
|
|
19
|
+
* const spec = OpenAPIGenerator.generate({
|
|
20
|
+
* info: {
|
|
21
|
+
* title: 'My Digital Twin API',
|
|
22
|
+
* version: '1.0.0',
|
|
23
|
+
* description: 'API documentation'
|
|
24
|
+
* },
|
|
25
|
+
* components: Object.values(components),
|
|
26
|
+
* servers: [{ url: 'http://localhost:3000' }]
|
|
27
|
+
* })
|
|
28
|
+
*
|
|
29
|
+
* // Write to file
|
|
30
|
+
* OpenAPIGenerator.writeYAML(spec, './openapi.yaml')
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export class OpenAPIGenerator {
|
|
34
|
+
/**
|
|
35
|
+
* Generates an OpenAPI document from the provided components.
|
|
36
|
+
*
|
|
37
|
+
* @param options - Generation options including components and metadata
|
|
38
|
+
* @returns Complete OpenAPI document
|
|
39
|
+
*/
|
|
40
|
+
static generate(options) {
|
|
41
|
+
const { info, servers, components, additionalSchemas, additionalTags, includeAuth = true } = options;
|
|
42
|
+
// Filter components that implement OpenAPIDocumentable
|
|
43
|
+
const documentableComponents = components.filter(isOpenAPIDocumentable);
|
|
44
|
+
// Aggregate paths, tags, and schemas from all components
|
|
45
|
+
const allPaths = {};
|
|
46
|
+
const allTags = additionalTags ? [...additionalTags] : [];
|
|
47
|
+
const allSchemas = additionalSchemas ? { ...additionalSchemas } : {};
|
|
48
|
+
const tagNames = new Set(additionalTags?.map(t => t.name) || []);
|
|
49
|
+
for (const component of documentableComponents) {
|
|
50
|
+
try {
|
|
51
|
+
const spec = component.getOpenAPISpec();
|
|
52
|
+
// Merge paths
|
|
53
|
+
for (const [path, pathItem] of Object.entries(spec.paths)) {
|
|
54
|
+
if (allPaths[path]) {
|
|
55
|
+
// Merge operations into existing path
|
|
56
|
+
allPaths[path] = { ...allPaths[path], ...pathItem };
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
allPaths[path] = pathItem;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Merge tags (avoid duplicates)
|
|
63
|
+
if (spec.tags) {
|
|
64
|
+
for (const tag of spec.tags) {
|
|
65
|
+
if (!tagNames.has(tag.name)) {
|
|
66
|
+
allTags.push(tag);
|
|
67
|
+
tagNames.add(tag.name);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Merge schemas
|
|
72
|
+
if (spec.schemas) {
|
|
73
|
+
Object.assign(allSchemas, spec.schemas);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
const componentName = 'getConfiguration' in component
|
|
78
|
+
? component.getConfiguration().name
|
|
79
|
+
: 'unknown';
|
|
80
|
+
console.warn(`Warning: Failed to get OpenAPI spec from component "${componentName}":`, error);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Sort tags alphabetically
|
|
84
|
+
allTags.sort((a, b) => a.name.localeCompare(b.name));
|
|
85
|
+
// Build components section
|
|
86
|
+
const componentsSection = {};
|
|
87
|
+
if (Object.keys(allSchemas).length > 0) {
|
|
88
|
+
componentsSection.schemas = allSchemas;
|
|
89
|
+
}
|
|
90
|
+
if (includeAuth) {
|
|
91
|
+
componentsSection.securitySchemes = this.getDefaultSecuritySchemes();
|
|
92
|
+
}
|
|
93
|
+
// Build final document
|
|
94
|
+
const document = {
|
|
95
|
+
openapi: '3.0.3',
|
|
96
|
+
info,
|
|
97
|
+
paths: allPaths
|
|
98
|
+
};
|
|
99
|
+
if (servers && servers.length > 0) {
|
|
100
|
+
document.servers = servers;
|
|
101
|
+
}
|
|
102
|
+
if (allTags.length > 0) {
|
|
103
|
+
document.tags = allTags;
|
|
104
|
+
}
|
|
105
|
+
if (Object.keys(componentsSection).length > 0) {
|
|
106
|
+
document.components = componentsSection;
|
|
107
|
+
}
|
|
108
|
+
return document;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Returns default security schemes for APISIX/Keycloak authentication.
|
|
112
|
+
*/
|
|
113
|
+
static getDefaultSecuritySchemes() {
|
|
114
|
+
return {
|
|
115
|
+
ApiKeyAuth: {
|
|
116
|
+
type: 'apiKey',
|
|
117
|
+
in: 'header',
|
|
118
|
+
name: 'x-user-id',
|
|
119
|
+
description: 'Keycloak user ID (forwarded by APISIX)'
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Converts an OpenAPI document to YAML string.
|
|
125
|
+
*
|
|
126
|
+
* @param document - OpenAPI document to convert
|
|
127
|
+
* @returns YAML string representation
|
|
128
|
+
*/
|
|
129
|
+
static toYAML(document) {
|
|
130
|
+
return this.objectToYAML(document, 0);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Converts an OpenAPI document to JSON string.
|
|
134
|
+
*
|
|
135
|
+
* @param document - OpenAPI document to convert
|
|
136
|
+
* @param pretty - Whether to format with indentation (default: true)
|
|
137
|
+
* @returns JSON string representation
|
|
138
|
+
*/
|
|
139
|
+
static toJSON(document, pretty = true) {
|
|
140
|
+
return JSON.stringify(document, null, pretty ? 2 : undefined);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Recursively converts an object to YAML format.
|
|
144
|
+
* Simple implementation without external dependencies.
|
|
145
|
+
*/
|
|
146
|
+
static objectToYAML(obj, indent) {
|
|
147
|
+
const spaces = ' '.repeat(indent);
|
|
148
|
+
if (obj === null || obj === undefined) {
|
|
149
|
+
return 'null';
|
|
150
|
+
}
|
|
151
|
+
if (typeof obj === 'string') {
|
|
152
|
+
// Check if string needs quoting
|
|
153
|
+
if (obj === '' ||
|
|
154
|
+
obj.includes(':') ||
|
|
155
|
+
obj.includes('#') ||
|
|
156
|
+
obj.includes('\n') ||
|
|
157
|
+
obj.includes('"') ||
|
|
158
|
+
obj.includes("'") ||
|
|
159
|
+
obj.startsWith(' ') ||
|
|
160
|
+
obj.endsWith(' ') ||
|
|
161
|
+
obj === 'true' ||
|
|
162
|
+
obj === 'false' ||
|
|
163
|
+
obj === 'null' ||
|
|
164
|
+
/^[\d.]+$/.test(obj)) {
|
|
165
|
+
// Use double quotes and escape
|
|
166
|
+
return `"${obj.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n')}"`;
|
|
167
|
+
}
|
|
168
|
+
return obj;
|
|
169
|
+
}
|
|
170
|
+
if (typeof obj === 'number' || typeof obj === 'boolean') {
|
|
171
|
+
return String(obj);
|
|
172
|
+
}
|
|
173
|
+
if (Array.isArray(obj)) {
|
|
174
|
+
if (obj.length === 0) {
|
|
175
|
+
return '[]';
|
|
176
|
+
}
|
|
177
|
+
const items = obj.map(item => {
|
|
178
|
+
const value = this.objectToYAML(item, indent + 1);
|
|
179
|
+
if (typeof item === 'object' && item !== null && !Array.isArray(item)) {
|
|
180
|
+
// Object in array - put first property on same line as dash
|
|
181
|
+
const lines = value.split('\n');
|
|
182
|
+
if (lines.length > 0) {
|
|
183
|
+
return `${spaces}- ${lines[0].trimStart()}\n${lines.slice(1).join('\n')}`;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return `${spaces}- ${value}`;
|
|
187
|
+
});
|
|
188
|
+
return items.join('\n').replace(/\n+$/, '');
|
|
189
|
+
}
|
|
190
|
+
if (typeof obj === 'object') {
|
|
191
|
+
const entries = Object.entries(obj);
|
|
192
|
+
if (entries.length === 0) {
|
|
193
|
+
return '{}';
|
|
194
|
+
}
|
|
195
|
+
const lines = entries.map(([key, value]) => {
|
|
196
|
+
// Handle special keys that need quoting
|
|
197
|
+
const quotedKey = /[:\s#[\]{}]/.test(key) ? `"${key}"` : key;
|
|
198
|
+
if (value === null || value === undefined) {
|
|
199
|
+
return `${spaces}${quotedKey}: null`;
|
|
200
|
+
}
|
|
201
|
+
if (typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length > 0) {
|
|
202
|
+
return `${spaces}${quotedKey}:\n${this.objectToYAML(value, indent + 1)}`;
|
|
203
|
+
}
|
|
204
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
205
|
+
return `${spaces}${quotedKey}:\n${this.objectToYAML(value, indent + 1)}`;
|
|
206
|
+
}
|
|
207
|
+
return `${spaces}${quotedKey}: ${this.objectToYAML(value, indent + 1)}`;
|
|
208
|
+
});
|
|
209
|
+
return lines.join('\n');
|
|
210
|
+
}
|
|
211
|
+
return String(obj);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Helper to create a simple schema reference.
|
|
215
|
+
*/
|
|
216
|
+
static schemaRef(name) {
|
|
217
|
+
return { $ref: `#/components/schemas/${name}` };
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Helper to create a common response for 200 OK with content.
|
|
221
|
+
*/
|
|
222
|
+
static successResponse(contentType, schema, description = 'Successful response') {
|
|
223
|
+
return {
|
|
224
|
+
'200': {
|
|
225
|
+
description,
|
|
226
|
+
content: {
|
|
227
|
+
[contentType]: { schema }
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Helper to create common error responses.
|
|
234
|
+
*/
|
|
235
|
+
static errorResponses(codes = [400, 401, 404, 500]) {
|
|
236
|
+
const responses = {};
|
|
237
|
+
const descriptions = {
|
|
238
|
+
400: 'Bad request',
|
|
239
|
+
401: 'Unauthorized',
|
|
240
|
+
403: 'Forbidden',
|
|
241
|
+
404: 'Not found',
|
|
242
|
+
500: 'Internal server error'
|
|
243
|
+
};
|
|
244
|
+
for (const code of codes) {
|
|
245
|
+
responses[String(code)] = { description: descriptions[code] };
|
|
246
|
+
}
|
|
247
|
+
return responses;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Common schemas used across components.
|
|
251
|
+
*/
|
|
252
|
+
static { this.commonSchemas = {
|
|
253
|
+
Error: {
|
|
254
|
+
type: 'object',
|
|
255
|
+
properties: {
|
|
256
|
+
error: { type: 'string' },
|
|
257
|
+
message: { type: 'string' }
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
Point: {
|
|
261
|
+
type: 'object',
|
|
262
|
+
required: ['type', 'coordinates'],
|
|
263
|
+
properties: {
|
|
264
|
+
type: { type: 'string', enum: ['Point'] },
|
|
265
|
+
coordinates: {
|
|
266
|
+
type: 'array',
|
|
267
|
+
items: { type: 'number' }
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
Feature: {
|
|
272
|
+
type: 'object',
|
|
273
|
+
required: ['type', 'geometry', 'properties'],
|
|
274
|
+
properties: {
|
|
275
|
+
type: { type: 'string', enum: ['Feature'] },
|
|
276
|
+
geometry: { type: 'object' },
|
|
277
|
+
properties: { type: 'object' }
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
FeatureCollection: {
|
|
281
|
+
type: 'object',
|
|
282
|
+
required: ['type', 'features'],
|
|
283
|
+
properties: {
|
|
284
|
+
type: { type: 'string', enum: ['FeatureCollection'] },
|
|
285
|
+
features: {
|
|
286
|
+
type: 'array',
|
|
287
|
+
items: { $ref: '#/components/schemas/Feature' }
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}; }
|
|
292
|
+
}
|
|
293
|
+
//# sourceMappingURL=generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/openapi/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { QueueOptions, ConnectionOptions } from 'bullmq';
|
|
2
|
+
import { Queue } from 'bullmq';
|
|
3
|
+
/**
|
|
4
|
+
* Configuration options for the Queue Manager
|
|
5
|
+
*/
|
|
6
|
+
export interface QueueConfig {
|
|
7
|
+
/** Number of workers for collectors (data collection) */
|
|
8
|
+
collectorWorkers?: number;
|
|
9
|
+
/** Number of workers for harvesters (data processing) */
|
|
10
|
+
harvesterWorkers?: number;
|
|
11
|
+
/** Redis connection configuration */
|
|
12
|
+
redis?: ConnectionOptions;
|
|
13
|
+
/** Advanced options for each queue type */
|
|
14
|
+
queueOptions?: {
|
|
15
|
+
collectors?: Partial<QueueOptions>;
|
|
16
|
+
harvesters?: Partial<QueueOptions>;
|
|
17
|
+
priority?: Partial<QueueOptions>;
|
|
18
|
+
uploads?: Partial<QueueOptions>;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Queue Manager - Manages BullMQ queues for different component types
|
|
23
|
+
*
|
|
24
|
+
* Handles three types of queues:
|
|
25
|
+
* - Collector queue: High priority, fast execution for data collection
|
|
26
|
+
* - Harvester queue: Medium priority, slower processing for data transformation
|
|
27
|
+
* - Priority queue: Urgent/manual jobs with highest priority
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const queueManager = new QueueManager({
|
|
32
|
+
* redis: { host: 'localhost', port: 6379 },
|
|
33
|
+
* collectorWorkers: 3,
|
|
34
|
+
* harvesterWorkers: 2
|
|
35
|
+
* })
|
|
36
|
+
*
|
|
37
|
+
* await queueManager.close()
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare class QueueManager {
|
|
41
|
+
#private;
|
|
42
|
+
readonly collectorQueue: Queue;
|
|
43
|
+
readonly harvesterQueue: Queue;
|
|
44
|
+
readonly priorityQueue: Queue;
|
|
45
|
+
readonly uploadQueue: Queue;
|
|
46
|
+
/**
|
|
47
|
+
* Creates a new Queue Manager instance
|
|
48
|
+
* @param config - Queue configuration options
|
|
49
|
+
*/
|
|
50
|
+
constructor(config?: QueueConfig);
|
|
51
|
+
/**
|
|
52
|
+
* Closes all queues gracefully
|
|
53
|
+
* @returns Promise that resolves when all queues are closed
|
|
54
|
+
*/
|
|
55
|
+
close(): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Gets statistics for all queues
|
|
58
|
+
* @returns Object containing stats for each queue type
|
|
59
|
+
*/
|
|
60
|
+
getQueueStats(): Promise<{
|
|
61
|
+
collectors: {
|
|
62
|
+
waiting: number;
|
|
63
|
+
active: number;
|
|
64
|
+
completed: number;
|
|
65
|
+
failed: number;
|
|
66
|
+
};
|
|
67
|
+
harvesters: {
|
|
68
|
+
waiting: number;
|
|
69
|
+
active: number;
|
|
70
|
+
completed: number;
|
|
71
|
+
failed: number;
|
|
72
|
+
};
|
|
73
|
+
priority: {
|
|
74
|
+
waiting: number;
|
|
75
|
+
active: number;
|
|
76
|
+
completed: number;
|
|
77
|
+
failed: number;
|
|
78
|
+
};
|
|
79
|
+
uploads: {
|
|
80
|
+
waiting: number;
|
|
81
|
+
active: number;
|
|
82
|
+
completed: number;
|
|
83
|
+
failed: number;
|
|
84
|
+
};
|
|
85
|
+
}>;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=queue_manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue_manager.d.ts","sourceRoot":"","sources":["../src/queue_manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAA;AAC7D,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAE9B;;GAEG;AACH,MAAM,WAAW,WAAW;IACxB,yDAAyD;IACzD,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,yDAAyD;IACzD,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,qCAAqC;IACrC,KAAK,CAAC,EAAE,iBAAiB,CAAA;IACzB,2CAA2C;IAC3C,YAAY,CAAC,EAAE;QACX,UAAU,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;QAClC,UAAU,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;QAClC,QAAQ,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;QAChC,OAAO,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;KAClC,CAAA;CACJ;AAyCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,YAAY;;IACrB,QAAQ,CAAC,cAAc,EAAE,KAAK,CAAA;IAC9B,QAAQ,CAAC,cAAc,EAAE,KAAK,CAAA;IAC9B,QAAQ,CAAC,aAAa,EAAE,KAAK,CAAA;IAC7B,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAA;IAE3B;;;OAGG;gBACS,MAAM,GAAE,WAAgB;IA6EpC;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA+B5B;;;OAGG;IACG,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BtB"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { Queue } from 'bullmq';
|
|
2
|
+
/**
|
|
3
|
+
* Queue configuration constants
|
|
4
|
+
*/
|
|
5
|
+
const QUEUE_DEFAULTS = {
|
|
6
|
+
REDIS: {
|
|
7
|
+
host: 'localhost',
|
|
8
|
+
port: 6379,
|
|
9
|
+
maxRetriesPerRequest: null,
|
|
10
|
+
enableReadyCheck: true,
|
|
11
|
+
retryStrategy: (times) => Math.min(times * 50, 2000)
|
|
12
|
+
},
|
|
13
|
+
COLLECTORS: {
|
|
14
|
+
name: 'dt-collectors',
|
|
15
|
+
attempts: 3,
|
|
16
|
+
backoffDelay: 2000,
|
|
17
|
+
keepCompleted: 100,
|
|
18
|
+
keepFailed: 50
|
|
19
|
+
},
|
|
20
|
+
HARVESTERS: {
|
|
21
|
+
name: 'dt-harvesters',
|
|
22
|
+
attempts: 5,
|
|
23
|
+
backoffDelay: 5000,
|
|
24
|
+
keepCompleted: 50,
|
|
25
|
+
keepFailed: 100
|
|
26
|
+
},
|
|
27
|
+
PRIORITY: {
|
|
28
|
+
name: 'dt-priority',
|
|
29
|
+
attempts: 2,
|
|
30
|
+
priority: 1
|
|
31
|
+
},
|
|
32
|
+
UPLOADS: {
|
|
33
|
+
name: 'dt-uploads',
|
|
34
|
+
attempts: 1, // No retries - temp file is deleted after first attempt
|
|
35
|
+
backoffDelay: 10000,
|
|
36
|
+
keepCompleted: 50,
|
|
37
|
+
keepFailed: 100
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Queue Manager - Manages BullMQ queues for different component types
|
|
42
|
+
*
|
|
43
|
+
* Handles three types of queues:
|
|
44
|
+
* - Collector queue: High priority, fast execution for data collection
|
|
45
|
+
* - Harvester queue: Medium priority, slower processing for data transformation
|
|
46
|
+
* - Priority queue: Urgent/manual jobs with highest priority
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const queueManager = new QueueManager({
|
|
51
|
+
* redis: { host: 'localhost', port: 6379 },
|
|
52
|
+
* collectorWorkers: 3,
|
|
53
|
+
* harvesterWorkers: 2
|
|
54
|
+
* })
|
|
55
|
+
*
|
|
56
|
+
* await queueManager.close()
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export class QueueManager {
|
|
60
|
+
/**
|
|
61
|
+
* Creates a new Queue Manager instance
|
|
62
|
+
* @param config - Queue configuration options
|
|
63
|
+
*/
|
|
64
|
+
constructor(config = {}) {
|
|
65
|
+
const baseConnection = config.redis || QUEUE_DEFAULTS.REDIS;
|
|
66
|
+
this.collectorQueue = this.#createCollectorQueue(baseConnection, config.queueOptions?.collectors);
|
|
67
|
+
this.harvesterQueue = this.#createHarvesterQueue(baseConnection, config.queueOptions?.harvesters);
|
|
68
|
+
this.priorityQueue = this.#createPriorityQueue(baseConnection, config.queueOptions?.priority);
|
|
69
|
+
this.uploadQueue = this.#createUploadQueue(baseConnection, config.queueOptions?.uploads);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Creates collector queue with optimized settings for data collection
|
|
73
|
+
* @private
|
|
74
|
+
*/
|
|
75
|
+
#createCollectorQueue(connection, options) {
|
|
76
|
+
return new Queue(QUEUE_DEFAULTS.COLLECTORS.name, {
|
|
77
|
+
connection,
|
|
78
|
+
defaultJobOptions: {
|
|
79
|
+
attempts: QUEUE_DEFAULTS.COLLECTORS.attempts,
|
|
80
|
+
backoff: { type: 'exponential', delay: QUEUE_DEFAULTS.COLLECTORS.backoffDelay },
|
|
81
|
+
removeOnComplete: { count: QUEUE_DEFAULTS.COLLECTORS.keepCompleted },
|
|
82
|
+
removeOnFail: { count: QUEUE_DEFAULTS.COLLECTORS.keepFailed }
|
|
83
|
+
},
|
|
84
|
+
...options
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Creates harvester queue with settings optimized for data processing
|
|
89
|
+
* @private
|
|
90
|
+
*/
|
|
91
|
+
#createHarvesterQueue(connection, options) {
|
|
92
|
+
return new Queue(QUEUE_DEFAULTS.HARVESTERS.name, {
|
|
93
|
+
connection,
|
|
94
|
+
defaultJobOptions: {
|
|
95
|
+
attempts: QUEUE_DEFAULTS.HARVESTERS.attempts,
|
|
96
|
+
backoff: { type: 'exponential', delay: QUEUE_DEFAULTS.HARVESTERS.backoffDelay },
|
|
97
|
+
removeOnComplete: { count: QUEUE_DEFAULTS.HARVESTERS.keepCompleted },
|
|
98
|
+
removeOnFail: { count: QUEUE_DEFAULTS.HARVESTERS.keepFailed }
|
|
99
|
+
},
|
|
100
|
+
...options
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Creates priority queue for urgent/manual jobs
|
|
105
|
+
* @private
|
|
106
|
+
*/
|
|
107
|
+
#createPriorityQueue(connection, options) {
|
|
108
|
+
return new Queue(QUEUE_DEFAULTS.PRIORITY.name, {
|
|
109
|
+
connection,
|
|
110
|
+
defaultJobOptions: {
|
|
111
|
+
priority: QUEUE_DEFAULTS.PRIORITY.priority,
|
|
112
|
+
attempts: QUEUE_DEFAULTS.PRIORITY.attempts,
|
|
113
|
+
removeOnComplete: true,
|
|
114
|
+
removeOnFail: false
|
|
115
|
+
},
|
|
116
|
+
...options
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Creates upload queue for async file processing (tileset extraction, large uploads)
|
|
121
|
+
* @private
|
|
122
|
+
*/
|
|
123
|
+
#createUploadQueue(connection, options) {
|
|
124
|
+
return new Queue(QUEUE_DEFAULTS.UPLOADS.name, {
|
|
125
|
+
connection,
|
|
126
|
+
defaultJobOptions: {
|
|
127
|
+
attempts: QUEUE_DEFAULTS.UPLOADS.attempts,
|
|
128
|
+
backoff: { type: 'exponential', delay: QUEUE_DEFAULTS.UPLOADS.backoffDelay },
|
|
129
|
+
removeOnComplete: { count: QUEUE_DEFAULTS.UPLOADS.keepCompleted },
|
|
130
|
+
removeOnFail: { count: QUEUE_DEFAULTS.UPLOADS.keepFailed }
|
|
131
|
+
},
|
|
132
|
+
...options
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Closes all queues gracefully
|
|
137
|
+
* @returns Promise that resolves when all queues are closed
|
|
138
|
+
*/
|
|
139
|
+
async close() {
|
|
140
|
+
const closePromises = [];
|
|
141
|
+
// Close all queues with timeout protection
|
|
142
|
+
const queues = [this.collectorQueue, this.harvesterQueue, this.priorityQueue, this.uploadQueue];
|
|
143
|
+
for (const queue of queues) {
|
|
144
|
+
closePromises.push(Promise.race([
|
|
145
|
+
queue.close(),
|
|
146
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('Queue close timeout')), 3000))
|
|
147
|
+
]).catch(async () => {
|
|
148
|
+
// Force close if timeout - try to access Redis connection directly
|
|
149
|
+
try {
|
|
150
|
+
const redisConnection = queue.redisConnection;
|
|
151
|
+
if (redisConnection && typeof redisConnection.disconnect === 'function') {
|
|
152
|
+
await redisConnection.disconnect();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// Ignore forced cleanup errors
|
|
157
|
+
}
|
|
158
|
+
}));
|
|
159
|
+
}
|
|
160
|
+
await Promise.all(closePromises);
|
|
161
|
+
// Wait for connections to fully close
|
|
162
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Gets statistics for all queues
|
|
166
|
+
* @returns Object containing stats for each queue type
|
|
167
|
+
*/
|
|
168
|
+
async getQueueStats() {
|
|
169
|
+
const [collectorStats, harvesterStats, priorityStats, uploadStats] = await Promise.all([
|
|
170
|
+
this.#getStats(this.collectorQueue),
|
|
171
|
+
this.#getStats(this.harvesterQueue),
|
|
172
|
+
this.#getStats(this.priorityQueue),
|
|
173
|
+
this.#getStats(this.uploadQueue)
|
|
174
|
+
]);
|
|
175
|
+
return {
|
|
176
|
+
collectors: collectorStats,
|
|
177
|
+
harvesters: harvesterStats,
|
|
178
|
+
priority: priorityStats,
|
|
179
|
+
uploads: uploadStats
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Gets statistics for a specific queue
|
|
184
|
+
* @private
|
|
185
|
+
*/
|
|
186
|
+
async #getStats(queue) {
|
|
187
|
+
const [waiting, active, completed, failed] = await Promise.all([
|
|
188
|
+
queue.getWaitingCount(),
|
|
189
|
+
queue.getActiveCount(),
|
|
190
|
+
queue.getCompletedCount(),
|
|
191
|
+
queue.getFailedCount()
|
|
192
|
+
]);
|
|
193
|
+
return { waiting, active, completed, failed };
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=queue_manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue_manager.js","sourceRoot":"","sources":["../src/queue_manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Collector, Harvester } from '@cepseudo/components';
|
|
2
|
+
import { Worker } from 'bullmq';
|
|
3
|
+
import type { QueueManager } from './queue_manager.js';
|
|
4
|
+
import { LogLevel } from '@cepseudo/shared';
|
|
5
|
+
/**
|
|
6
|
+
* Schedules components for execution using the queue manager
|
|
7
|
+
*
|
|
8
|
+
* This function creates a scheduler instance and sets up:
|
|
9
|
+
* - Job scheduling based on component schedules
|
|
10
|
+
* - Event-driven harvester triggers
|
|
11
|
+
* - Workers for processing jobs
|
|
12
|
+
*
|
|
13
|
+
* @param components - Array of components to schedule
|
|
14
|
+
* @param queueManager - Queue manager instance
|
|
15
|
+
* @param multiQueue - Whether to use multi-queue mode (default: true)
|
|
16
|
+
* @param logLevel - Log level for the scheduler (optional)
|
|
17
|
+
* @returns Promise that resolves to array of created workers
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* const workers = await scheduleComponents(
|
|
22
|
+
* [collector1, harvester1],
|
|
23
|
+
* queueManager,
|
|
24
|
+
* true
|
|
25
|
+
* )
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function scheduleComponents(components: Array<Collector | Harvester>, queueManager: QueueManager, multiQueue?: boolean, logLevel?: LogLevel): Promise<Worker[]>;
|
|
29
|
+
//# sourceMappingURL=scheduler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD,OAAO,EAAU,QAAQ,EAAkB,MAAM,kBAAkB,CAAA;AAsbnE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,kBAAkB,CACpC,UAAU,EAAE,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC,EACxC,YAAY,EAAE,YAAY,EAC1B,UAAU,GAAE,OAAc,EAC1B,QAAQ,CAAC,EAAE,QAAQ,GACpB,OAAO,CAAC,MAAM,EAAE,CAAC,CAGnB"}
|