UNPKG

@storm-stack/core

Version:

A build toolkit and runtime used by Storm Software in TypeScript applications

169 lines (167 loc) 5.42 kB
import { createLog } from './chunk-RDCOIWVB.js'; import { __name } from './chunk-43IZMM3W.js'; import { LogLevelLabel } from '@storm-software/config-tools/types'; import { findFileName } from '@stryke/path/file-path-fns'; import { defu } from 'defu'; import { Worker as Worker$1 } from 'jest-worker'; import { Transform } from 'node:stream'; var RESTARTED = Symbol("restarted"); var cleanupWorkers = /* @__PURE__ */ __name((worker) => { for (const curWorker of worker._workerPool?._workers || []) { curWorker._child?.kill("SIGINT"); } }, "cleanupWorkers"); var Worker = class { static { __name(this, "Worker"); } workerPath; options; #worker; #log; constructor(workerPath, options) { this.workerPath = workerPath; this.options = options; const { timeout, onRestart, name, context, ...farmOptions } = this.options; this.#log = createLog(name || workerPath); let restartPromise; let resolveRestartPromise; let activeTasks = 0; this.#worker = void 0; process.on("exit", () => { this.close(); }); const createWorker2 = /* @__PURE__ */ __name(() => { this.#worker = new Worker$1(workerPath, { ...farmOptions, forkOptions: { ...farmOptions.forkOptions, env: { ...farmOptions.forkOptions?.env ?? {}, ...process.env, STORM_STACK_LOCAL: process.env.STORM_STACK_LOCAL || "0" } }, maxRetries: 0 }); restartPromise = new Promise((resolve) => { resolveRestartPromise = resolve; }); if (!farmOptions.enableWorkerThreads) { for (const worker of this.#worker._workerPool?._workers || []) { worker._child?.on("exit", (code, signal) => { if ((code || signal && signal !== "SIGINT") && this.#worker) { this.#log(LogLevelLabel.ERROR, `${this.options.name} worker exited with code: ${code} and signal: ${signal}`); process.exit(code ?? 1); } }); worker._child?.on("message", ([, data]) => { if (data && typeof data === "object" && "type" in data && data.type === "activity") { onActivity(); } }); } } let aborted = false; const onActivityAbort = /* @__PURE__ */ __name(() => { if (!aborted) { this.options.onActivityAbort?.(); aborted = true; } }, "onActivityAbort"); const abortActivityStreamOnLog = new Transform({ transform(_chunk, _encoding, callback) { onActivityAbort(); callback(); } }); this.#worker.getStdout().pipe(abortActivityStreamOnLog); this.#worker.getStderr().pipe(abortActivityStreamOnLog); this.#worker.getStdout().pipe(process.stdout); this.#worker.getStderr().pipe(process.stderr); }, "createWorker"); createWorker2(); const onHanging = /* @__PURE__ */ __name(() => { const worker = this.#worker; if (!worker) { return; } const resolve = resolveRestartPromise; createWorker2(); this.#log(LogLevelLabel.WARN, `Sending SIGTERM signal to static worker due to timeout${timeout ? ` of ${timeout / 1e3} seconds` : ""}. Subsequent errors may be a result of the worker exiting.`); void worker.end().then(() => { resolve(RESTARTED); }); }, "onHanging"); let hangingTimer = false; const onActivity = /* @__PURE__ */ __name(() => { if (hangingTimer) { clearTimeout(hangingTimer); } if (this.options.onActivity) { this.options.onActivity(); } hangingTimer = activeTasks > 0 && setTimeout(onHanging, timeout); }, "onActivity"); for (const method of farmOptions.exposedMethods) { if (method.startsWith("_")) { continue; } this[method] = timeout ? async (...args) => { activeTasks++; try { let attempts = 0; for (; ; ) { onActivity(); const params = defu(args.length > 0 && args[0] ? args[0] : {}, context ?? {}); const result = await Promise.race([ // eslint-disable-next-line ts/no-unsafe-call this.#worker[method](...params), restartPromise ]); if (result !== RESTARTED) { return result; } if (onRestart) { onRestart(method, args, ++attempts); } } } finally { activeTasks--; onActivity(); } } : this.#worker[method].bind(this.#worker); } } async end() { const worker = this.#worker; if (!worker) { throw new Error("Farm is ended, no more calls can be done to it"); } cleanupWorkers(worker); this.#worker = void 0; return worker.end(); } /** * Quietly end the worker if it exists */ close() { if (this.#worker) { cleanupWorkers(this.#worker); void this.#worker.end(); } } }; function createWorker(workerPath, exposedMethods, numWorkers = 1) { return new Worker(workerPath, { name: findFileName(workerPath, { withExtension: false }), exposedMethods, numWorkers }); } __name(createWorker, "createWorker"); export { Worker, createWorker }; //# sourceMappingURL=chunk-O2R2KDOD.js.map //# sourceMappingURL=chunk-O2R2KDOD.js.map