@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
JavaScript
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