@lodestar/beacon-node
Version:
A Typescript implementation of the beacon chain
90 lines • 4.03 kB
JavaScript
import { Thread } from "@chainsafe/threads";
import { sleep } from "@lodestar/utils";
const NANO_TO_SECOND_CONVERSION = 1e9;
export var EventDirection;
(function (EventDirection) {
EventDirection[EventDirection["workerToMain"] = 0] = "workerToMain";
EventDirection[EventDirection["mainToWorker"] = 1] = "mainToWorker";
/** Event not emitted through worker boundary */
EventDirection[EventDirection["none"] = 2] = "none";
})(EventDirection || (EventDirection = {}));
/**
* Bridges events from worker to main thread
* Each event can only have one direction:
* - worker to main
* - main to worker
*/
export function wireEventsOnWorkerThread(mainEventName, events, parentPort, metrics, isWorkerToMain) {
// Subscribe to events from main thread
parentPort.on("message", (data) => {
if (typeof data === "object" &&
data.type === mainEventName &&
// This check is not necessary but added for safety in case of improper implemented events
isWorkerToMain[data.event] === EventDirection.mainToWorker) {
const [sec, nanoSec] = process.hrtime(data.posted);
const networkWorkerLatency = sec + nanoSec / NANO_TO_SECOND_CONVERSION;
metrics?.networkWorkerWireEventsOnWorkerThreadLatency.observe({ eventName: data.event }, networkWorkerLatency);
events.emit(data.event, data.data);
}
});
for (const eventName of Object.keys(isWorkerToMain)) {
if (isWorkerToMain[eventName] === EventDirection.workerToMain) {
// Pick one of the events to comply with StrictEventEmitter function signature
events.on(eventName, (data) => {
const workerEvent = {
type: mainEventName,
event: eventName,
posted: process.hrtime(),
data,
};
parentPort.postMessage(workerEvent);
});
}
}
}
export function wireEventsOnMainThread(mainEventName, events, worker, metrics, isWorkerToMain) {
// Subscribe to events from main thread
worker.on("message", (data) => {
if (typeof data === "object" &&
data.type === mainEventName &&
// This check is not necessary but added for safety in case of improper implemented events
isWorkerToMain[data.event] === EventDirection.workerToMain) {
const [sec, nanoSec] = process.hrtime(data.posted);
const networkWorkerLatency = sec + nanoSec / NANO_TO_SECOND_CONVERSION;
metrics?.networkWorkerWireEventsOnMainThreadLatency.observe({ eventName: data.event }, networkWorkerLatency);
events.emit(data.event, data.data);
}
});
for (const eventName of Object.keys(isWorkerToMain)) {
if (isWorkerToMain[eventName] === EventDirection.mainToWorker) {
// Pick one of the events to comply with StrictEventEmitter function signature
events.on(eventName, (data) => {
const workerEvent = {
type: mainEventName,
event: eventName,
posted: process.hrtime(),
data,
};
worker.postMessage(workerEvent);
});
}
}
}
export async function terminateWorkerThread({ worker, retryMs, retryCount, logger, }) {
const terminated = new Promise((resolve) => {
Thread.events(worker).subscribe((event) => {
if (event.type === "termination") {
resolve(true);
}
});
});
for (let i = 0; i < retryCount; i++) {
await Thread.terminate(worker);
const result = await Promise.race([terminated, sleep(retryMs).then(() => false)]);
if (result)
return;
logger?.warn("Worker thread failed to terminate, retrying...");
}
throw new Error(`Worker thread failed to terminate in ${retryCount * retryMs}ms.`);
}
//# sourceMappingURL=workerEvents.js.map