UNPKG

@awesome-ecs/workers

Version:

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

199 lines (193 loc) 7.3 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/systems/index.ts var systems_exports = {}; __export(systems_exports, { WorkerThreadHealthRequestSystem: () => WorkerThreadHealthRequestSystem, WorkerThreadHealthResponseSystem: () => WorkerThreadHealthResponseSystem, WorkerThreadHealthScheduleSystem: () => WorkerThreadHealthScheduleSystem, WorkerThreadHealthSubscriptionSystem: () => WorkerThreadHealthSubscriptionSystem, WorkerThreadMessageSubscriptionSystem: () => WorkerThreadMessageSubscriptionSystem }); module.exports = __toCommonJS(systems_exports); // 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 var import_utils = require("@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) { (0, import_utils.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 var import_utils2 = require("@awesome-ecs/core/utils"); var WorkerThreadHealthResponseSystem = class { shouldRun(context) { return context.events.hasEvent("message-received-health" /* messageReceivedHealth */); } action(context) { (0, import_utils2.assertComponent)("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 */); } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { WorkerThreadHealthRequestSystem, WorkerThreadHealthResponseSystem, WorkerThreadHealthScheduleSystem, WorkerThreadHealthSubscriptionSystem, WorkerThreadMessageSubscriptionSystem }); //# sourceMappingURL=index.cjs.map