UNPKG

@awesome-ecs/workers

Version:

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

136 lines (135 loc) 5.17 kB
import "../worker-message-CpfPNmUD.mjs"; import "../worker-instance-D6m0tNnA.mjs"; import { assertComponent } from "@awesome-ecs/core/utils"; //#region 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(); } }; //#endregion //#region src/systems/middlewares/initializers/worker-thread-message-subscription.ts var WorkerThreadMessageSubscriptionSystem = class { shouldRun(context) { return !!context.entity.instance.worker; } action(context) { const { identity, instance } = context.entity; const proxy = identity.proxy; instance.worker.onmessage = (event) => { const data = { uid: event.data.messageType === "health" ? "message-received-health" : "message-received-data", message: event.data }; context.events.dispatchEvent(data, proxy); context.logger.debug("[WORKER-RECEIVED] Message from worker", proxy, data.message.messageType, data.message.messageUid, data.message.workerUid); }; instance.worker.onerror = (error) => { const data = { uid: "message-received-health", message: null, error }; context.events.broadcastEvent(data); instance.status = 3; }; instance.worker.onmessageerror = (error) => { const data = { uid: "message-received-health", message: null, messageError: error }; context.events.broadcastEvent(data); instance.status = 3; }; } }; //#endregion //#region src/systems/middlewares/updaters/worker-thread-data-complete.ts var WorkerThreadDataCompleteSystem = class { shouldRun(context, event) { const workerUid = context.entity.identity.model.uid.toString(); return event.origin.entityUid.toString() === workerUid || event.data.message?.workerUid === workerUid; } action(context, event) { if (event.data.message.messageType !== "data") return; context.entity.instance.status = 1; } }; //#endregion //#region src/systems/middlewares/updaters/worker-thread-health-request.ts var WorkerThreadHealthRequestSystem = class { maxHeartbeatsPending = 3; shouldRun(context) { if (!context.entity.instance.worker) return false; const { lastHealthQuery } = context.entity.instance; if (!lastHealthQuery) return true; if ((/* @__PURE__ */ new Date()).getTime() - lastHealthQuery.getTime() > context.entity.identity.model.healthCheckInterval) return true; return false; } action(context) { assertComponent(context.entity.instance, context.entity, "instance"); const { entity } = context; const { instance } = entity; if (instance.status === 2) { 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.identity.proxy); const existingModel = context.entity.identity.model; const model = { type: existingModel.type, uid: `worker-${existingModel.type}-${randomUid}`, healthCheckInterval: existingModel.healthCheckInterval }; context.repository.addEntity("worker-thread", model); } else { this.sendHeartbeatMessage(randomUid, entity); context.entity.instance.lastHealthQuery = /* @__PURE__ */ new Date(); } } sendHeartbeatMessage(uid, entity) { const message = { messageUid: `worker-heartbeat-${uid}`, request: { heartbeatValue: uid }, workerType: entity.identity.model.type, messageType: "health" }; entity.instance.worker.postMessage(message); entity.instance.heartbeats.set(uid, true); } }; //#endregion //#region src/systems/middlewares/updaters/worker-thread-health-response.ts var WorkerThreadHealthResponseSystem = class { shouldRun(context, event) { return !!context.entity.instance.worker && this.isEventForWorker(context, event); } action(context, event) { assertComponent(context.entity.instance, context.entity, "instance"); const { instance } = context.entity; 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) instance.status = 1; instance.heartbeats.delete(message.data.heartbeatValue); } isEventForWorker(context, event) { const workerUid = context.entity.identity.model.uid.toString(); return event.origin.entityUid.toString() === workerUid || event.data.message?.workerUid === workerUid; } }; //#endregion export { WorkerThreadDataCompleteSystem, WorkerThreadHealthRequestSystem, WorkerThreadHealthResponseSystem, WorkerThreadHealthScheduleSystem, WorkerThreadMessageSubscriptionSystem }; //# sourceMappingURL=index.mjs.map