UNPKG

@awesome-ecs/workers

Version:

The Workers package for Awesome ECS. Provides basic implementation for the Worker communication using ECS.

174 lines (169 loc) 6.03 kB
import "../chunk-MEIXQAHY.js"; import "../chunk-A5ALYPYH.js"; import "../chunk-TVAABFYA.js"; import "../chunk-HGXB5X2K.js"; // src/systems/middlewares/initializers/worker-thread-health-schedule.ts var WorkerThreadHealthScheduleSystem = class { action(context) { const { identity } = context.entity; context.scheduler.scheduleUpdate( { entityType: identity.entityType, entityUid: identity.model.uid }, identity.model.healthCheckInterval || 5e3 ); } cleanup(context) { context.scheduler.removeSchedule(); context.entity.instance.worker.terminate(); } }; // src/systems/middlewares/initializers/worker-thread-message-subscription.ts var WorkerThreadMessageSubscriptionSystem = class { shouldRun(context) { return !!context.entity.instance.worker; } action(context) { const { worker } = context.entity.instance; worker.onmessage = (event) => { const data = { uid: event.data.messageType === "health" /* health */ ? "message-received-health" /* messageReceivedHealth */ : "message-received-data" /* messageReceivedData */, message: event.data }; context.events.dispatchEvent(data, context.entity.myProxy); if (event.data.messageType === "data" /* data */) { context.entity.instance.status = 1 /* available */; } context.logger.debug( "[WORKER-RECEIVED] Message from worker", context.entity.myProxy, data.message.messageType, data.message.messageUid, data.message.workerUid ); }; worker.onerror = (error) => { const data = { uid: "message-received-health" /* messageReceivedHealth */, message: null, error }; context.events.dispatchEvent(data); context.entity.instance.status = 3 /* error */; }; worker.onmessageerror = (error) => { const data = { uid: "message-received-health" /* messageReceivedHealth */, message: null, messageError: error }; context.events.dispatchEvent(data); context.entity.instance.status = 3 /* error */; }; } cleanup(context) { context.events.clearSubscriptions(); } }; // src/systems/middlewares/initializers/worker-thread-health-subscription.ts var WorkerThreadHealthSubscriptionSystem = class { action(context) { context.events.subscribeTo("message-received-health" /* messageReceivedHealth */); } cleanup(context) { context.events.unsubscribeFrom("message-received-health" /* messageReceivedHealth */); } }; // src/systems/middlewares/updaters/worker-thread-health-request.ts import { assertComponent } from "@awesome-ecs/core/utils"; var WorkerThreadHealthRequestSystem = class { maxHeartbeatsPending = 0; shouldRun(context) { const { lastHealthQuery } = context.entity.instance; if (!lastHealthQuery) { return true; } const passedMs = (/* @__PURE__ */ new Date()).getTime() - lastHealthQuery.getTime(); if (passedMs > context.entity.identity.model.healthCheckInterval) { return true; } return false; } action(context) { assertComponent("worker-instance" /* workerInstance */, context.entity); const { entity } = context; const { instance } = entity; if (instance.status === 2 /* busy */) { context.logger.debug( "Worker is still busy, won't send heartbeat.", entity.identity.model.uid ); return; } const randomUid = Math.random().toFixed(3); if (instance.heartbeats.size > this.maxHeartbeatsPending) { context.logger.warn( `Worker ${entity.identity.model.uid} has ${instance.heartbeats.size} pending heartbeat. Will deactivate!` ); context.repository.removeEntity(context.entity.myProxy); const existingModel = context.entity.identity.model; const model = { type: existingModel.type, uid: `worker-${existingModel.type}-${randomUid}`, healthCheckInterval: existingModel.healthCheckInterval }; context.repository.addEntity("worker-thread" /* workerThread */, model); } else { this.sendHeartbeatMessage(randomUid, entity); context.entity.instance.lastHealthQuery = /* @__PURE__ */ new Date(); } } cleanup(context) { context.events.unsubscribeFrom("message-received-health" /* messageReceivedHealth */); } sendHeartbeatMessage(uid, entity) { const message = { messageUid: `worker-heartbeat-${uid}`, request: { heartbeatValue: uid }, workerType: entity.identity.model.type, messageType: "health" /* health */ }; entity.instance.worker.postMessage(message); entity.instance.heartbeats.set(uid, true); } }; // src/systems/middlewares/updaters/worker-thread-health-response.ts import { assertComponent as assertComponent2 } from "@awesome-ecs/core/utils"; var WorkerThreadHealthResponseSystem = class { shouldRun(context) { return context.events.hasEvent("message-received-health" /* messageReceivedHealth */); } action(context) { assertComponent2("worker-instance" /* workerInstance */, context.entity); const { instance } = context.entity; const event = context.events.getEvent("message-received-health" /* messageReceivedHealth */); if (event.data.error) { throw new Error(`[WORKER-REPLY] ${event.data.error.message}`); } const { message } = event.data; context.logger.debug("[WORKER-HEALTH-REPLY]", context.entity.identity.model.uid, message); if (instance.status === 0 /* starting */) { instance.status = 1 /* available */; } instance.heartbeats.delete(message.data.heartbeatValue); } cleanup(context) { context.events.unsubscribeFrom("message-received-health" /* messageReceivedHealth */); } }; export { WorkerThreadHealthRequestSystem, WorkerThreadHealthResponseSystem, WorkerThreadHealthScheduleSystem, WorkerThreadHealthSubscriptionSystem, WorkerThreadMessageSubscriptionSystem }; //# sourceMappingURL=index.js.map