UNPKG

@lodestar/beacon-node

Version:

A Typescript implementation of the beacon chain

90 lines 4.03 kB
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