digitaltwin-core 0.14.2 → 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 +20 -20
- package/README.md +494 -359
- package/dist/auth/apisix_parser.d.ts +141 -0
- package/dist/auth/apisix_parser.d.ts.map +1 -0
- package/dist/auth/apisix_parser.js +161 -0
- package/dist/auth/apisix_parser.js.map +1 -0
- package/dist/auth/auth_config.d.ts +126 -0
- package/dist/auth/auth_config.d.ts.map +1 -0
- package/dist/auth/auth_config.js +169 -0
- package/dist/auth/auth_config.js.map +1 -0
- package/dist/auth/auth_provider.d.ts +118 -0
- package/dist/auth/auth_provider.d.ts.map +1 -0
- package/dist/auth/auth_provider.js +8 -0
- package/dist/auth/auth_provider.js.map +1 -0
- package/dist/auth/auth_provider_factory.d.ts +91 -0
- package/dist/auth/auth_provider_factory.d.ts.map +1 -0
- package/dist/auth/auth_provider_factory.js +146 -0
- package/dist/auth/auth_provider_factory.js.map +1 -0
- package/dist/auth/index.d.ts +8 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +7 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/providers/gateway_auth_provider.d.ts +78 -0
- package/dist/auth/providers/gateway_auth_provider.d.ts.map +1 -0
- package/dist/auth/providers/gateway_auth_provider.js +109 -0
- package/dist/auth/providers/gateway_auth_provider.js.map +1 -0
- package/dist/auth/providers/index.d.ts +4 -0
- package/dist/auth/providers/index.d.ts.map +1 -0
- package/dist/auth/providers/index.js +4 -0
- package/dist/auth/providers/index.js.map +1 -0
- package/dist/auth/providers/jwt_auth_provider.d.ts +91 -0
- package/dist/auth/providers/jwt_auth_provider.d.ts.map +1 -0
- package/dist/auth/providers/jwt_auth_provider.js +204 -0
- package/dist/auth/providers/jwt_auth_provider.js.map +1 -0
- package/dist/auth/providers/no_auth_provider.d.ts +61 -0
- package/dist/auth/providers/no_auth_provider.d.ts.map +1 -0
- package/dist/auth/providers/no_auth_provider.js +76 -0
- package/dist/auth/providers/no_auth_provider.js.map +1 -0
- package/dist/auth/types.d.ts +100 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +2 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/auth/user_service.d.ts +86 -0
- package/dist/auth/user_service.d.ts.map +1 -0
- package/dist/auth/user_service.js +237 -0
- package/dist/auth/user_service.js.map +1 -0
- package/dist/components/assets_manager.d.ts +662 -0
- package/dist/components/assets_manager.d.ts.map +1 -0
- package/dist/components/assets_manager.js +1537 -0
- package/dist/components/assets_manager.js.map +1 -0
- package/dist/components/async_upload.d.ts +20 -0
- package/dist/components/async_upload.d.ts.map +1 -0
- package/dist/components/async_upload.js +10 -0
- package/dist/components/async_upload.js.map +1 -0
- package/dist/components/collector.d.ts +203 -0
- package/dist/components/collector.d.ts.map +1 -0
- package/dist/components/collector.js +214 -0
- package/dist/components/collector.js.map +1 -0
- package/dist/components/custom_table_manager.d.ts +503 -0
- package/dist/components/custom_table_manager.d.ts.map +1 -0
- package/dist/components/custom_table_manager.js +1023 -0
- package/dist/components/custom_table_manager.js.map +1 -0
- package/dist/components/global_assets_handler.d.ts +63 -0
- package/dist/components/global_assets_handler.d.ts.map +1 -0
- package/dist/components/global_assets_handler.js +127 -0
- package/dist/components/global_assets_handler.js.map +1 -0
- package/dist/components/handler.d.ts +104 -0
- package/dist/components/handler.d.ts.map +1 -0
- package/dist/components/handler.js +110 -0
- package/dist/components/handler.js.map +1 -0
- package/dist/components/harvester.d.ts +182 -0
- package/dist/components/harvester.d.ts.map +1 -0
- package/dist/components/harvester.js +406 -0
- package/dist/components/harvester.js.map +1 -0
- package/dist/components/index.d.ts +11 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +9 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/interfaces.d.ts +126 -0
- package/dist/components/interfaces.d.ts.map +1 -0
- package/dist/components/interfaces.js +8 -0
- package/dist/components/interfaces.js.map +1 -0
- package/dist/components/map_manager.d.ts +61 -0
- package/dist/components/map_manager.d.ts.map +1 -0
- package/dist/components/map_manager.js +242 -0
- package/dist/components/map_manager.js.map +1 -0
- package/dist/components/tileset_manager.d.ts +125 -0
- package/dist/components/tileset_manager.d.ts.map +1 -0
- package/dist/components/tileset_manager.js +623 -0
- package/dist/components/tileset_manager.js.map +1 -0
- package/dist/components/types.d.ts +226 -0
- package/dist/components/types.d.ts.map +1 -0
- package/dist/components/types.js +8 -0
- package/dist/components/types.js.map +1 -0
- package/dist/database/adapters/knex_database_adapter.d.ts +97 -0
- package/dist/database/adapters/knex_database_adapter.d.ts.map +1 -0
- package/dist/database/adapters/knex_database_adapter.js +729 -0
- package/dist/database/adapters/knex_database_adapter.js.map +1 -0
- package/dist/database/database_adapter.d.ts +262 -0
- package/dist/database/database_adapter.d.ts.map +1 -0
- package/dist/database/database_adapter.js +46 -0
- package/dist/database/database_adapter.js.map +1 -0
- package/dist/engine/digital_twin_engine.d.ts +295 -0
- package/dist/engine/digital_twin_engine.d.ts.map +1 -0
- package/dist/engine/digital_twin_engine.js +907 -0
- package/dist/engine/digital_twin_engine.js.map +1 -0
- package/dist/engine/endpoints.d.ts +47 -0
- package/dist/engine/endpoints.d.ts.map +1 -0
- package/dist/engine/endpoints.js +88 -0
- package/dist/engine/endpoints.js.map +1 -0
- package/dist/engine/error_handler.d.ts +20 -0
- package/dist/engine/error_handler.d.ts.map +1 -0
- package/dist/engine/error_handler.js +69 -0
- package/dist/engine/error_handler.js.map +1 -0
- package/dist/engine/events.d.ts +93 -0
- package/dist/engine/events.d.ts.map +1 -0
- package/dist/engine/events.js +71 -0
- package/dist/engine/events.js.map +1 -0
- package/dist/engine/health.d.ts +112 -0
- package/dist/engine/health.d.ts.map +1 -0
- package/dist/engine/health.js +190 -0
- package/dist/engine/health.js.map +1 -0
- package/dist/engine/initializer.d.ts +62 -0
- package/dist/engine/initializer.d.ts.map +1 -0
- package/dist/engine/initializer.js +108 -0
- package/dist/engine/initializer.js.map +1 -0
- package/dist/engine/queue_manager.d.ts +87 -0
- package/dist/engine/queue_manager.d.ts.map +1 -0
- package/dist/engine/queue_manager.js +196 -0
- package/dist/engine/queue_manager.js.map +1 -0
- package/dist/engine/scheduler.d.ts +30 -0
- package/dist/engine/scheduler.d.ts.map +1 -0
- package/dist/engine/scheduler.js +378 -0
- package/dist/engine/scheduler.js.map +1 -0
- package/dist/engine/upload_processor.d.ts +36 -0
- package/dist/engine/upload_processor.d.ts.map +1 -0
- package/dist/engine/upload_processor.js +113 -0
- package/dist/engine/upload_processor.js.map +1 -0
- package/dist/env/env.d.ts +134 -0
- package/dist/env/env.d.ts.map +1 -0
- package/dist/env/env.js +177 -0
- package/dist/env/env.js.map +1 -0
- package/dist/errors/index.d.ts +94 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +149 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +65 -0
- package/dist/index.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/openapi/index.d.ts +9 -0
- package/dist/openapi/index.d.ts.map +1 -0
- package/dist/openapi/index.js +9 -0
- package/dist/openapi/index.js.map +1 -0
- package/dist/openapi/types.d.ts +182 -0
- package/dist/openapi/types.d.ts.map +1 -0
- package/dist/openapi/types.js +16 -0
- package/dist/openapi/types.js.map +1 -0
- package/dist/storage/adapters/local_storage_service.d.ts +57 -0
- package/dist/storage/adapters/local_storage_service.d.ts.map +1 -0
- package/dist/storage/adapters/local_storage_service.js +132 -0
- package/dist/storage/adapters/local_storage_service.js.map +1 -0
- package/dist/storage/adapters/ovh_storage_service.d.ts +72 -0
- package/dist/storage/adapters/ovh_storage_service.d.ts.map +1 -0
- package/dist/storage/adapters/ovh_storage_service.js +205 -0
- package/dist/storage/adapters/ovh_storage_service.js.map +1 -0
- package/dist/storage/storage_factory.d.ts +14 -0
- package/dist/storage/storage_factory.d.ts.map +1 -0
- package/dist/storage/storage_factory.js +43 -0
- package/dist/storage/storage_factory.js.map +1 -0
- package/dist/storage/storage_service.d.ts +163 -0
- package/dist/storage/storage_service.d.ts.map +1 -0
- package/dist/storage/storage_service.js +58 -0
- package/dist/storage/storage_service.js.map +1 -0
- package/dist/types/data_record.d.ts +123 -0
- package/dist/types/data_record.d.ts.map +1 -0
- package/dist/types/data_record.js +8 -0
- package/dist/types/data_record.js.map +1 -0
- package/dist/utils/graceful_shutdown.d.ts +44 -0
- package/dist/utils/graceful_shutdown.d.ts.map +1 -0
- package/dist/utils/graceful_shutdown.js +79 -0
- package/dist/utils/graceful_shutdown.js.map +1 -0
- package/dist/utils/http_responses.d.ts +175 -0
- package/dist/utils/http_responses.d.ts.map +1 -0
- package/dist/utils/http_responses.js +216 -0
- package/dist/utils/http_responses.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +74 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +92 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/map_to_data_record.d.ts +10 -0
- package/dist/utils/map_to_data_record.d.ts.map +1 -0
- package/dist/utils/map_to_data_record.js +36 -0
- package/dist/utils/map_to_data_record.js.map +1 -0
- package/dist/utils/safe_async.d.ts +50 -0
- package/dist/utils/safe_async.d.ts.map +1 -0
- package/dist/utils/safe_async.js +90 -0
- package/dist/utils/safe_async.js.map +1 -0
- package/dist/utils/servable_endpoint.d.ts +63 -0
- package/dist/utils/servable_endpoint.d.ts.map +1 -0
- package/dist/utils/servable_endpoint.js +67 -0
- package/dist/utils/servable_endpoint.js.map +1 -0
- package/dist/utils/zip_utils.d.ts +66 -0
- package/dist/utils/zip_utils.d.ts.map +1 -0
- package/dist/utils/zip_utils.js +169 -0
- package/dist/utils/zip_utils.js.map +1 -0
- package/dist/validation/index.d.ts +3 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +7 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/schemas.d.ts +273 -0
- package/dist/validation/schemas.d.ts.map +1 -0
- package/dist/validation/schemas.js +82 -0
- package/dist/validation/schemas.js.map +1 -0
- package/dist/validation/validate.d.ts +49 -0
- package/dist/validation/validate.d.ts.map +1 -0
- package/dist/validation/validate.js +110 -0
- package/dist/validation/validate.js.map +1 -0
- package/package.json +23 -13
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Collector } from '../components/collector.js';
|
|
2
|
+
import { Harvester } from '../components/harvester.js';
|
|
3
|
+
import { Worker } from 'bullmq';
|
|
4
|
+
import type { QueueManager } from './queue_manager.js';
|
|
5
|
+
import { LogLevel } from '../utils/logger.js';
|
|
6
|
+
/**
|
|
7
|
+
* Schedules components for execution using the queue manager
|
|
8
|
+
*
|
|
9
|
+
* This function creates a scheduler instance and sets up:
|
|
10
|
+
* - Job scheduling based on component schedules
|
|
11
|
+
* - Event-driven harvester triggers
|
|
12
|
+
* - Workers for processing jobs
|
|
13
|
+
*
|
|
14
|
+
* @param components - Array of components to schedule
|
|
15
|
+
* @param queueManager - Queue manager instance
|
|
16
|
+
* @param multiQueue - Whether to use multi-queue mode (default: true)
|
|
17
|
+
* @param logLevel - Log level for the scheduler (optional)
|
|
18
|
+
* @returns Promise that resolves to array of created workers
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* const workers = await scheduleComponents(
|
|
23
|
+
* [collector1, harvester1],
|
|
24
|
+
* queueManager,
|
|
25
|
+
* true
|
|
26
|
+
* )
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function scheduleComponents(components: Array<Collector | Harvester>, queueManager: QueueManager, multiQueue?: boolean, logLevel?: LogLevel): Promise<Worker[]>;
|
|
30
|
+
//# sourceMappingURL=scheduler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/engine/scheduler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,EAAU,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAqarD;;;;;;;;;;;;;;;;;;;;;;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"}
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
// src/engine/scheduler.ts
|
|
2
|
+
import { Collector } from '../components/collector.js';
|
|
3
|
+
import { Harvester } from '../components/harvester.js';
|
|
4
|
+
import { Worker } from 'bullmq';
|
|
5
|
+
import { Logger, LogLevel } from '../utils/logger.js';
|
|
6
|
+
import { engineEventBus } from './events.js';
|
|
7
|
+
import debounce from 'lodash/debounce.js';
|
|
8
|
+
/**
|
|
9
|
+
* Worker configuration constants
|
|
10
|
+
*/
|
|
11
|
+
const WORKER_CONFIG = {
|
|
12
|
+
COLLECTOR: {
|
|
13
|
+
concurrency: 5,
|
|
14
|
+
limiter: { max: 10, duration: 60000 }
|
|
15
|
+
},
|
|
16
|
+
HARVESTER: {
|
|
17
|
+
concurrency: 3,
|
|
18
|
+
limiter: { max: 20, duration: 60000 }
|
|
19
|
+
},
|
|
20
|
+
PRIORITY: {
|
|
21
|
+
concurrency: 1 // One priority task at a time
|
|
22
|
+
},
|
|
23
|
+
SINGLE_QUEUE: {
|
|
24
|
+
concurrency: (componentCount) => Math.max(componentCount, 1)
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Default job options for event-triggered harvesters
|
|
29
|
+
*/
|
|
30
|
+
const EVENT_JOB_OPTIONS = {
|
|
31
|
+
removeOnComplete: true,
|
|
32
|
+
attempts: 3,
|
|
33
|
+
backoff: { type: 'exponential', delay: 1000 }
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Component Scheduler - Manages scheduling and execution of collectors and harvesters
|
|
37
|
+
*
|
|
38
|
+
* The scheduler supports two modes:
|
|
39
|
+
* - Multi-queue mode: Separate queues for collectors, harvesters, and priority jobs
|
|
40
|
+
* - Single-queue mode: All components share one queue (legacy mode)
|
|
41
|
+
*
|
|
42
|
+
* @class ComponentScheduler
|
|
43
|
+
*/
|
|
44
|
+
class ComponentScheduler {
|
|
45
|
+
/**
|
|
46
|
+
* Creates a new Component Scheduler instance
|
|
47
|
+
* @param components - Array of components to schedule
|
|
48
|
+
* @param queueManager - Queue manager instance
|
|
49
|
+
* @param multiQueue - Whether to use multi-queue mode
|
|
50
|
+
* @param logLevel - Log level for the scheduler (optional)
|
|
51
|
+
*/
|
|
52
|
+
constructor(components, queueManager, multiQueue = true, logLevel) {
|
|
53
|
+
this.componentMap = {};
|
|
54
|
+
this.debouncedTriggers = {};
|
|
55
|
+
this.components = components;
|
|
56
|
+
this.queueManager = queueManager;
|
|
57
|
+
this.multiQueue = multiQueue;
|
|
58
|
+
this.logger = new Logger('DigitalTwin', logLevel ?? (process.env.NODE_ENV === 'test' ? LogLevel.SILENT : LogLevel.INFO));
|
|
59
|
+
this.#buildComponentMap();
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Schedules all components and creates workers
|
|
63
|
+
* @returns Array of created workers
|
|
64
|
+
*/
|
|
65
|
+
async schedule() {
|
|
66
|
+
this.#setupEventListeners();
|
|
67
|
+
if (this.multiQueue) {
|
|
68
|
+
return this.#scheduleMultiQueue();
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
return this.#scheduleSingleQueue();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Builds a map of component names to component instances
|
|
76
|
+
* @private
|
|
77
|
+
*/
|
|
78
|
+
#buildComponentMap() {
|
|
79
|
+
for (const comp of this.components) {
|
|
80
|
+
const config = comp.getConfiguration();
|
|
81
|
+
this.componentMap[config.name] = comp;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Sets up event listeners for harvesters with on-source trigger
|
|
86
|
+
* @private
|
|
87
|
+
*/
|
|
88
|
+
#setupEventListeners() {
|
|
89
|
+
this.#setupHarvesterTriggers();
|
|
90
|
+
this.#setupCollectorEventListener();
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Creates debounced trigger functions for event-driven harvesters
|
|
94
|
+
* @private
|
|
95
|
+
*/
|
|
96
|
+
#setupHarvesterTriggers() {
|
|
97
|
+
for (const comp of this.components) {
|
|
98
|
+
if (!(comp instanceof Harvester))
|
|
99
|
+
continue;
|
|
100
|
+
const config = comp.getConfiguration();
|
|
101
|
+
if (!this.#shouldSetupEventTrigger(config))
|
|
102
|
+
continue;
|
|
103
|
+
const triggerFunction = this.#createTriggerFunction(config);
|
|
104
|
+
const debounceMs = config.debounceMs || 1000;
|
|
105
|
+
this.debouncedTriggers[config.name] = debounce(triggerFunction, debounceMs);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Checks if a harvester should have event trigger setup
|
|
110
|
+
* @private
|
|
111
|
+
*/
|
|
112
|
+
#shouldSetupEventTrigger(config) {
|
|
113
|
+
return config.triggerMode === 'on-source' || config.triggerMode === 'both';
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Creates a trigger function for a harvester
|
|
117
|
+
* @private
|
|
118
|
+
*/
|
|
119
|
+
#createTriggerFunction(config) {
|
|
120
|
+
return async () => {
|
|
121
|
+
const queue = this.multiQueue ? this.queueManager.harvesterQueue : this.queueManager.collectorQueue;
|
|
122
|
+
await queue.add(config.name, {
|
|
123
|
+
type: 'harvester',
|
|
124
|
+
triggeredBy: 'source-event',
|
|
125
|
+
source: config.source
|
|
126
|
+
}, EVENT_JOB_OPTIONS);
|
|
127
|
+
this.logger.debug(`Triggered harvester ${config.name} from source event`);
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Sets up listener for collector completion events
|
|
132
|
+
* @private
|
|
133
|
+
*/
|
|
134
|
+
#setupCollectorEventListener() {
|
|
135
|
+
engineEventBus.on('component:event', async (event) => {
|
|
136
|
+
if (event.type !== 'collector:completed')
|
|
137
|
+
return;
|
|
138
|
+
this.logger.debug(`Received collector:completed event from ${event.componentName}`);
|
|
139
|
+
try {
|
|
140
|
+
await this.#triggerDependentHarvesters(event.componentName);
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
this.logger.error(`Failed to trigger harvesters for ${event.componentName}: ${error instanceof Error ? error.message : String(error)}`, {
|
|
144
|
+
componentName: event.componentName,
|
|
145
|
+
stack: error instanceof Error ? error.stack : undefined
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Triggers harvesters that depend on a completed collector
|
|
152
|
+
* @private
|
|
153
|
+
*/
|
|
154
|
+
async #triggerDependentHarvesters(collectorName) {
|
|
155
|
+
for (const comp of this.components) {
|
|
156
|
+
if (!(comp instanceof Harvester))
|
|
157
|
+
continue;
|
|
158
|
+
const config = comp.getConfiguration();
|
|
159
|
+
if (config.source === collectorName && this.debouncedTriggers[config.name]) {
|
|
160
|
+
this.logger.debug(`Triggering harvester "${config.name}" from "${collectorName}"`);
|
|
161
|
+
this.debouncedTriggers[config.name]();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Schedules components in multi-queue mode
|
|
167
|
+
* @private
|
|
168
|
+
*/
|
|
169
|
+
async #scheduleMultiQueue() {
|
|
170
|
+
await this.#scheduleCollectors();
|
|
171
|
+
await this.#scheduleHarvesters();
|
|
172
|
+
return [this.#createCollectorWorker(), this.#createHarvesterWorker(), this.#createPriorityWorker()];
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Schedules all collectors in multi-queue mode
|
|
176
|
+
* @private
|
|
177
|
+
*/
|
|
178
|
+
async #scheduleCollectors() {
|
|
179
|
+
const collectors = this.components.filter((comp) => comp instanceof Collector);
|
|
180
|
+
for (const collector of collectors) {
|
|
181
|
+
const config = collector.getConfiguration();
|
|
182
|
+
const schedule = collector.getSchedule();
|
|
183
|
+
await this.queueManager.collectorQueue.upsertJobScheduler(config.name, { pattern: schedule }, {
|
|
184
|
+
name: config.name,
|
|
185
|
+
data: { type: 'collector', triggeredBy: 'schedule' }
|
|
186
|
+
});
|
|
187
|
+
this.logger.info(`Collector "${config.name}" scheduled: ${schedule}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Schedules harvesters (only those not exclusively on-source) in multi-queue mode
|
|
192
|
+
* @private
|
|
193
|
+
*/
|
|
194
|
+
async #scheduleHarvesters() {
|
|
195
|
+
const harvesters = this.components.filter((comp) => comp instanceof Harvester);
|
|
196
|
+
for (const harvester of harvesters) {
|
|
197
|
+
const config = harvester.getConfiguration();
|
|
198
|
+
const schedule = harvester.getSchedule();
|
|
199
|
+
if (schedule && config.triggerMode !== 'on-source') {
|
|
200
|
+
await this.queueManager.harvesterQueue.upsertJobScheduler(config.name, { pattern: schedule }, {
|
|
201
|
+
name: config.name,
|
|
202
|
+
data: { type: 'harvester', triggeredBy: 'schedule' }
|
|
203
|
+
});
|
|
204
|
+
this.logger.info(`Harvester "${config.name}" scheduled: ${schedule}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Creates collector worker for multi-queue mode
|
|
210
|
+
* @private
|
|
211
|
+
*/
|
|
212
|
+
#createCollectorWorker() {
|
|
213
|
+
return new Worker('dt-collectors', async (job) => this.#processCollectorJob(job), {
|
|
214
|
+
connection: this.queueManager.collectorQueue.opts.connection,
|
|
215
|
+
concurrency: WORKER_CONFIG.COLLECTOR.concurrency,
|
|
216
|
+
limiter: WORKER_CONFIG.COLLECTOR.limiter
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Creates harvester worker for multi-queue mode
|
|
221
|
+
* @private
|
|
222
|
+
*/
|
|
223
|
+
#createHarvesterWorker() {
|
|
224
|
+
return new Worker('dt-harvesters', async (job) => this.#processHarvesterJob(job), {
|
|
225
|
+
connection: this.queueManager.harvesterQueue.opts.connection,
|
|
226
|
+
concurrency: WORKER_CONFIG.HARVESTER.concurrency,
|
|
227
|
+
limiter: WORKER_CONFIG.HARVESTER.limiter
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Creates priority worker for multi-queue mode
|
|
232
|
+
* @private
|
|
233
|
+
*/
|
|
234
|
+
#createPriorityWorker() {
|
|
235
|
+
return new Worker('dt-priority', async (job) => this.#processPriorityJob(job), {
|
|
236
|
+
connection: this.queueManager.priorityQueue.opts.connection,
|
|
237
|
+
concurrency: WORKER_CONFIG.PRIORITY.concurrency
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Processes a collector job
|
|
242
|
+
* @private
|
|
243
|
+
*/
|
|
244
|
+
async #processCollectorJob(job) {
|
|
245
|
+
const comp = this.componentMap[job.name];
|
|
246
|
+
if (!comp)
|
|
247
|
+
return;
|
|
248
|
+
this.logger.debug(`Running collector: ${job.name}`);
|
|
249
|
+
try {
|
|
250
|
+
const result = await comp.run();
|
|
251
|
+
return {
|
|
252
|
+
success: true,
|
|
253
|
+
bytes: result?.length || 0,
|
|
254
|
+
timestamp: new Date().toISOString()
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
this.logger.error(`Collector ${job.name} failed:`, error);
|
|
259
|
+
throw error;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Processes a harvester job
|
|
264
|
+
* @private
|
|
265
|
+
*/
|
|
266
|
+
async #processHarvesterJob(job) {
|
|
267
|
+
const comp = this.componentMap[job.name];
|
|
268
|
+
if (!comp)
|
|
269
|
+
return;
|
|
270
|
+
this.logger.debug(`Running harvester: ${job.name} (${job.data.triggeredBy})`);
|
|
271
|
+
try {
|
|
272
|
+
const result = await comp.run();
|
|
273
|
+
// Emit harvester completion event
|
|
274
|
+
engineEventBus.emit('component:event', {
|
|
275
|
+
type: 'harvester:completed',
|
|
276
|
+
componentName: comp.getConfiguration().name,
|
|
277
|
+
timestamp: new Date(),
|
|
278
|
+
data: { success: result }
|
|
279
|
+
});
|
|
280
|
+
return {
|
|
281
|
+
success: result,
|
|
282
|
+
timestamp: new Date().toISOString()
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
this.logger.error(`Harvester ${job.name} failed:`, error);
|
|
287
|
+
throw error;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Processes a priority job
|
|
292
|
+
* @private
|
|
293
|
+
*/
|
|
294
|
+
async #processPriorityJob(job) {
|
|
295
|
+
const comp = this.componentMap[job.name];
|
|
296
|
+
if (!comp)
|
|
297
|
+
return;
|
|
298
|
+
this.logger.debug(`Running priority job: ${job.name}`);
|
|
299
|
+
const result = await comp.run();
|
|
300
|
+
return { success: true, result };
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Schedules components in single-queue mode (legacy)
|
|
304
|
+
* @private
|
|
305
|
+
*/
|
|
306
|
+
async #scheduleSingleQueue() {
|
|
307
|
+
this.logger.warn('Single-queue mode (not recommended for production)');
|
|
308
|
+
const singleQueue = this.queueManager.collectorQueue;
|
|
309
|
+
await this.#scheduleAllComponentsInSingleQueue(singleQueue);
|
|
310
|
+
const worker = new Worker(singleQueue.name, async (job) => this.#processSingleQueueJob(job), {
|
|
311
|
+
connection: singleQueue.opts.connection,
|
|
312
|
+
concurrency: WORKER_CONFIG.SINGLE_QUEUE.concurrency(this.components.length)
|
|
313
|
+
});
|
|
314
|
+
return [worker];
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Schedules all components in single queue
|
|
318
|
+
* @private
|
|
319
|
+
*/
|
|
320
|
+
async #scheduleAllComponentsInSingleQueue(singleQueue) {
|
|
321
|
+
for (const comp of this.components) {
|
|
322
|
+
const config = comp.getConfiguration();
|
|
323
|
+
const schedule = comp.getSchedule();
|
|
324
|
+
const shouldSchedule = comp instanceof Harvester
|
|
325
|
+
? schedule && comp.getConfiguration().triggerMode !== 'on-source'
|
|
326
|
+
: schedule !== null;
|
|
327
|
+
if (shouldSchedule) {
|
|
328
|
+
await singleQueue.upsertJobScheduler(config.name, { pattern: schedule }, {
|
|
329
|
+
name: config.name,
|
|
330
|
+
data: {
|
|
331
|
+
type: comp instanceof Collector ? 'collector' : 'harvester',
|
|
332
|
+
triggeredBy: 'schedule'
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Processes a job in single-queue mode
|
|
340
|
+
* @private
|
|
341
|
+
*/
|
|
342
|
+
async #processSingleQueueJob(job) {
|
|
343
|
+
const comp = this.componentMap[job.name];
|
|
344
|
+
if (!comp)
|
|
345
|
+
return;
|
|
346
|
+
this.logger.debug(`Running ${job.data.type}: ${job.name}`);
|
|
347
|
+
const result = await comp.run();
|
|
348
|
+
return { success: true, result };
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Schedules components for execution using the queue manager
|
|
353
|
+
*
|
|
354
|
+
* This function creates a scheduler instance and sets up:
|
|
355
|
+
* - Job scheduling based on component schedules
|
|
356
|
+
* - Event-driven harvester triggers
|
|
357
|
+
* - Workers for processing jobs
|
|
358
|
+
*
|
|
359
|
+
* @param components - Array of components to schedule
|
|
360
|
+
* @param queueManager - Queue manager instance
|
|
361
|
+
* @param multiQueue - Whether to use multi-queue mode (default: true)
|
|
362
|
+
* @param logLevel - Log level for the scheduler (optional)
|
|
363
|
+
* @returns Promise that resolves to array of created workers
|
|
364
|
+
*
|
|
365
|
+
* @example
|
|
366
|
+
* ```typescript
|
|
367
|
+
* const workers = await scheduleComponents(
|
|
368
|
+
* [collector1, harvester1],
|
|
369
|
+
* queueManager,
|
|
370
|
+
* true
|
|
371
|
+
* )
|
|
372
|
+
* ```
|
|
373
|
+
*/
|
|
374
|
+
export async function scheduleComponents(components, queueManager, multiQueue = true, logLevel) {
|
|
375
|
+
const scheduler = new ComponentScheduler(components, queueManager, multiQueue, logLevel);
|
|
376
|
+
return scheduler.schedule();
|
|
377
|
+
}
|
|
378
|
+
//# sourceMappingURL=scheduler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/engine/scheduler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ConnectionOptions } from 'bullmq';
|
|
2
|
+
import type { StorageService } from '../storage/storage_service.js';
|
|
3
|
+
import type { DatabaseAdapter } from '../database/database_adapter.js';
|
|
4
|
+
export interface TilesetUploadJobData {
|
|
5
|
+
type: 'tileset';
|
|
6
|
+
recordId: number;
|
|
7
|
+
tempFilePath: string;
|
|
8
|
+
componentName: string;
|
|
9
|
+
userId: number;
|
|
10
|
+
filename: string;
|
|
11
|
+
description: string;
|
|
12
|
+
}
|
|
13
|
+
export type UploadJobData = TilesetUploadJobData;
|
|
14
|
+
export type UploadStatus = 'pending' | 'processing' | 'completed' | 'failed';
|
|
15
|
+
/**
|
|
16
|
+
* Background worker for processing large file uploads (tileset extraction).
|
|
17
|
+
* Prevents HTTP timeout by queuing jobs and processing asynchronously.
|
|
18
|
+
*
|
|
19
|
+
* Flow:
|
|
20
|
+
* 1. Read ZIP from temp file
|
|
21
|
+
* 2. Extract and upload all files to storage (OVH S3)
|
|
22
|
+
* 3. Update database with tileset_url and base_path
|
|
23
|
+
* 4. Clean up temp file
|
|
24
|
+
*/
|
|
25
|
+
export declare class UploadProcessor {
|
|
26
|
+
private worker;
|
|
27
|
+
private storage;
|
|
28
|
+
private db;
|
|
29
|
+
constructor(storage: StorageService, db: DatabaseAdapter);
|
|
30
|
+
start(connection: ConnectionOptions): void;
|
|
31
|
+
stop(): Promise<void>;
|
|
32
|
+
private processJob;
|
|
33
|
+
private processTilesetUpload;
|
|
34
|
+
private updateRecordStatus;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=upload_processor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload_processor.d.ts","sourceRoot":"","sources":["../../src/engine/upload_processor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AAQtE,MAAM,WAAW,oBAAoB;IACjC,IAAI,EAAE,SAAS,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,MAAM,aAAa,GAAG,oBAAoB,CAAA;AAChD,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAA;AAE5E;;;;;;;;;GASG;AACH,qBAAa,eAAe;IACxB,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,EAAE,CAAiB;gBAEf,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,eAAe;IAKxD,KAAK,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI;IAWpC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAOb,UAAU;YAQV,oBAAoB;YAsFpB,kBAAkB;CAGnC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { Worker } from 'bullmq';
|
|
2
|
+
import { extractAndStoreArchive } from '../utils/zip_utils.js';
|
|
3
|
+
import { safeAsync, safeCleanup } from '../utils/safe_async.js';
|
|
4
|
+
import { Logger } from '../utils/logger.js';
|
|
5
|
+
import fs from 'fs/promises';
|
|
6
|
+
const logger = new Logger('UploadProcessor');
|
|
7
|
+
/**
|
|
8
|
+
* Background worker for processing large file uploads (tileset extraction).
|
|
9
|
+
* Prevents HTTP timeout by queuing jobs and processing asynchronously.
|
|
10
|
+
*
|
|
11
|
+
* Flow:
|
|
12
|
+
* 1. Read ZIP from temp file
|
|
13
|
+
* 2. Extract and upload all files to storage (OVH S3)
|
|
14
|
+
* 3. Update database with tileset_url and base_path
|
|
15
|
+
* 4. Clean up temp file
|
|
16
|
+
*/
|
|
17
|
+
export class UploadProcessor {
|
|
18
|
+
constructor(storage, db) {
|
|
19
|
+
this.worker = null;
|
|
20
|
+
this.storage = storage;
|
|
21
|
+
this.db = db;
|
|
22
|
+
}
|
|
23
|
+
start(connection) {
|
|
24
|
+
this.worker = new Worker('dt-uploads', async (job) => this.processJob(job), {
|
|
25
|
+
connection,
|
|
26
|
+
concurrency: 2,
|
|
27
|
+
limiter: { max: 5, duration: 60000 }
|
|
28
|
+
});
|
|
29
|
+
this.worker.on('completed', job => console.log(`[UploadProcessor] Job ${job.id} completed`));
|
|
30
|
+
this.worker.on('failed', (job, err) => console.error(`[UploadProcessor] Job ${job?.id} failed:`, err.message));
|
|
31
|
+
}
|
|
32
|
+
async stop() {
|
|
33
|
+
if (this.worker) {
|
|
34
|
+
await this.worker.close();
|
|
35
|
+
this.worker = null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async processJob(job) {
|
|
39
|
+
if (job.data.type === 'tileset') {
|
|
40
|
+
await this.processTilesetUpload(job);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
throw new Error(`Unknown upload job type: ${job.data.type}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async processTilesetUpload(job) {
|
|
47
|
+
const { recordId, tempFilePath, componentName } = job.data;
|
|
48
|
+
let basePath = null;
|
|
49
|
+
try {
|
|
50
|
+
await this.updateRecordStatus(recordId, componentName, 'processing');
|
|
51
|
+
await job.updateProgress(10);
|
|
52
|
+
// Read ZIP file
|
|
53
|
+
const zipBuffer = await fs.readFile(tempFilePath).catch(err => {
|
|
54
|
+
throw new Error(`Failed to read temp file: ${err.message}`);
|
|
55
|
+
});
|
|
56
|
+
await job.updateProgress(20);
|
|
57
|
+
// Generate unique base path
|
|
58
|
+
basePath = `${componentName}/${Date.now()}`;
|
|
59
|
+
// Extract and upload all files to storage
|
|
60
|
+
const extractResult = await extractAndStoreArchive(zipBuffer, this.storage, basePath);
|
|
61
|
+
await job.updateProgress(80);
|
|
62
|
+
// Validate tileset.json exists
|
|
63
|
+
if (!extractResult.root_file) {
|
|
64
|
+
// Clean up uploaded files (basePath is always set at this point)
|
|
65
|
+
if (basePath) {
|
|
66
|
+
const pathToDelete = basePath;
|
|
67
|
+
await safeAsync(() => this.storage.deleteByPrefix(pathToDelete), 'cleanup storage on invalid tileset', logger);
|
|
68
|
+
}
|
|
69
|
+
throw new Error('Invalid tileset: no tileset.json found in the ZIP archive');
|
|
70
|
+
}
|
|
71
|
+
// Build the public URL for tileset.json
|
|
72
|
+
const tilesetPath = `${basePath}/${extractResult.root_file}`;
|
|
73
|
+
const tilesetUrl = this.storage.getPublicUrl(tilesetPath);
|
|
74
|
+
// Update database record (url = basePath for deletion)
|
|
75
|
+
await this.db.updateById(componentName, recordId, {
|
|
76
|
+
url: basePath,
|
|
77
|
+
tileset_url: tilesetUrl,
|
|
78
|
+
upload_status: 'completed'
|
|
79
|
+
});
|
|
80
|
+
await job.updateProgress(90);
|
|
81
|
+
// Clean up temp file
|
|
82
|
+
await safeAsync(() => fs.unlink(tempFilePath), 'cleanup temp file after upload', logger);
|
|
83
|
+
await job.updateProgress(100);
|
|
84
|
+
logger.info(`Tileset ${recordId} uploaded: ${extractResult.file_count} files`);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
// Update record as failed (don't delete - keep for debugging)
|
|
88
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
89
|
+
await safeAsync(() => this.db.updateById(componentName, recordId, {
|
|
90
|
+
upload_status: 'failed',
|
|
91
|
+
upload_error: errorMessage
|
|
92
|
+
}), 'update record status to failed', logger);
|
|
93
|
+
// Clean up: uploaded files and temp file
|
|
94
|
+
const pathToClean = basePath; // Capture for closure
|
|
95
|
+
await safeCleanup([
|
|
96
|
+
...(pathToClean
|
|
97
|
+
? [
|
|
98
|
+
{
|
|
99
|
+
operation: () => this.storage.deleteByPrefix(pathToClean),
|
|
100
|
+
context: 'cleanup storage on upload error'
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
: []),
|
|
104
|
+
{ operation: () => fs.unlink(tempFilePath), context: 'cleanup temp file on upload error' }
|
|
105
|
+
], logger);
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async updateRecordStatus(id, tableName, status) {
|
|
110
|
+
await this.db.updateById(tableName, id, { upload_status: status });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=upload_processor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload_processor.js","sourceRoot":"","sources":["../../src/engine/upload_processor.ts"],"names":[],"mappings":"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"}
|