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