@awesome-ecs/workers
Version:
The Workers package for Awesome ECS. Provides basic implementation for the Worker communication using ECS.
135 lines (134 loc) • 4.83 kB
JavaScript
import "../worker-message-CpfPNmUD.mjs";
import "../worker-execution-mode-7gqqovFY.mjs";
import "../worker-instance-D6m0tNnA.mjs";
import { SYSTEM_CONTEXT_KEY } from "@awesome-ecs/abstract/entities";
//#region src/runtime/strategies/local-execution-strategy.ts
var LocalExecutionStrategy = class {
handlerRegistry;
logger;
mode = "local";
constructor(handlerRegistry, logger) {
this.handlerRegistry = handlerRegistry;
this.logger = logger;
}
dispatch(message, entity, onResponse) {
entity.instance.status = 2;
try {
const handler = this.handlerRegistry.resolve(message.request.type);
if (!handler) {
this.logger.warn(`[LOCAL-WORKER] No handler registered for request type: ${message.request.type}`);
entity.instance.status = 1;
return;
}
this.logger.debug("[LOCAL-WORKER] Executing handler locally", message.request.type, message.messageUid);
const startTime = performance.now();
const result = handler.handle(message.request);
const duration = performance.now() - startTime;
const metric = {
name: message.request.type,
startedAt: startTime,
endedAt: startTime + duration,
msPassed: duration
};
onResponse(entity, {
data: result.data,
transfer: result.transfer,
metrics: result.metrics ? [...result.metrics, metric] : [metric],
messageType: message.messageType,
messageUid: message.messageUid,
workerType: message.workerType
});
} catch (error) {
this.logger.warn(`[LOCAL-WORKER] Handler error: ${error?.message}`, message.request.type, error);
entity.instance.status = 3;
}
}
};
//#endregion
//#region src/runtime/strategies/web-worker-strategy.ts
var WebWorkerExecutionStrategy = class {
logger;
mode = "worker";
constructor(logger) {
this.logger = logger;
}
dispatch(message, entity) {
this.logger.debug("Sending message to Worker", entity.identity.model.uid, message);
entity.instance.worker.postMessage(message);
entity.instance.status = 2;
}
};
//#endregion
//#region src/runtime/worker-runtime.ts
var WorkerSystemRuntime = class {
workerMessageQueue;
entityRepository;
logger;
strategy;
contextRepository;
performanceTracker;
onResponse;
constructor(workerMessageQueue, entityRepository, logger, strategy, contextRepository, performanceTracker) {
this.workerMessageQueue = workerMessageQueue;
this.entityRepository = entityRepository;
this.logger = logger;
this.strategy = strategy;
this.contextRepository = contextRepository;
this.performanceTracker = performanceTracker;
this.onResponse = (entity, response) => {
if (!this.contextRepository) {
this.logger.warn("[WORKER-RUNTIME] No context repository configured for local response handling");
return;
}
const systemContext = this.contextRepository.get(entity.identity.proxy, SYSTEM_CONTEXT_KEY);
if (!systemContext) {
this.logger.warn("[WORKER-RUNTIME] No context found for entity", entity.identity.model.uid);
return;
}
const eventData = {
uid: response.messageType === "health" ? "message-received-health" : "message-received-data",
message: response
};
systemContext.events.dispatchEvent(eventData, entity.identity.proxy);
this.logger.debug("[WORKER-LOCAL-RESPONSE] Dispatched response event", response.messageType, response.messageUid);
};
}
runTick() {
while (this.workerMessageQueue.size > 0) {
const message = this.workerMessageQueue.peek();
if (!message) return;
const workers = this.entityRepository.getEntities("worker-thread");
if (!workers) {
this.logger.warn("No WorkerThreadEntity was registered for type: ", message.workerType);
return;
}
const availableWorker = this.findAvailableWorker(workers.filter((worker) => !!worker));
if (!availableWorker) {
this.logger.debug("No available worker found. Skipping remaining messages.", message.workerType, message.messageUid);
if (this.performanceTracker) {
const queue = this.workerMessageQueue;
if (typeof queue.markAllAsStalled === "function") queue.markAllAsStalled();
this.performanceTracker.recordStalledCount(this.workerMessageQueue.size);
}
return;
}
this.strategy.dispatch(message, availableWorker, this.onResponse);
this.workerMessageQueue.dequeue();
}
this.flushQueueWaitTimes();
}
flushQueueWaitTimes() {
if (!this.performanceTracker) return;
const queue = this.workerMessageQueue;
if (typeof queue.flushWaitTimes === "function") {
const waitTimes = queue.flushWaitTimes();
if (waitTimes.length) this.performanceTracker.recordWaitTimes(waitTimes);
}
}
findAvailableWorker(workers) {
for (const worker of workers) if (worker.instance.status === 1) return worker;
}
};
//#endregion
export { LocalExecutionStrategy, WebWorkerExecutionStrategy, WorkerSystemRuntime };
//# sourceMappingURL=index.mjs.map