UNPKG

@lynx-js/rspeedy

Version:

A webpack/rspack-based frontend toolchain for Lynx

112 lines (111 loc) 5.49 kB
export const __webpack_ids__ = [ "src_cli_exit_ts" ]; export const __webpack_modules__ = { "./src/cli/exit.ts": function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.d(__webpack_exports__, { exit: ()=>exit_exit }); var core_ = __webpack_require__("@rsbuild/core"); var external_node_process_ = __webpack_require__("node:process"); const asyncCallbacks = new Set(); const callbacks = new Set(); let isCalled = false; let isRegistered = false; async function exit(shouldManuallyExit, isSynchronous, signal) { if (isCalled) return; isCalled = true; if (asyncCallbacks.size > 0 && isSynchronous) console.error("SYNCHRONOUS TERMINATION NOTICE: When explicitly exiting the process via process.exit or via a parent process, asynchronous tasks in your exitHooks will not run. Either remove these tasks, use gracefulExit() instead of process.exit(), or ensure your parent process sends a SIGINT to the process running this code."); const exitCode = 128 + signal; const done = (force = false)=>{ if (true === force || true === shouldManuallyExit) external_node_process_["default"].exit(exitCode); }; for (const callback of callbacks)callback(exitCode); if (isSynchronous) return void done(); const promises = []; let forceAfter = 0; for (const [callback, wait] of asyncCallbacks){ forceAfter = Math.max(forceAfter, wait); promises.push(Promise.resolve(callback(exitCode))); } const asyncTimer = setTimeout(()=>{ done(true); }, forceAfter); await Promise.all(promises); clearTimeout(asyncTimer); done(); } function addHook(options) { const { onExit, wait, isSynchronous } = options; const asyncCallbackConfig = [ onExit, wait ]; if (isSynchronous) callbacks.add(onExit); else asyncCallbacks.add(asyncCallbackConfig); if (!isRegistered) { isRegistered = true; external_node_process_["default"].once('beforeExit', exit.bind(void 0, true, false, -128)); external_node_process_["default"].once('SIGINT', exit.bind(void 0, true, false, 2)); external_node_process_["default"].once('SIGTERM', exit.bind(void 0, true, false, 15)); external_node_process_["default"].once('exit', exit.bind(void 0, false, true, 0)); external_node_process_["default"].on('message', (message)=>{ if ('shutdown' === message) exit(true, true, -128); }); } return ()=>{ if (isSynchronous) callbacks.delete(onExit); else asyncCallbacks.delete(asyncCallbackConfig); }; } function asyncExitHook(onExit, options = {}) { if ('function' != typeof onExit) throw new TypeError('onExit must be a function'); if (!('number' == typeof options.wait && options.wait > 0)) throw new TypeError('wait must be set to a positive numeric value'); return addHook({ onExit, wait: options.wait, isSynchronous: false }); } function gracefulExit(signal = 0) { exit(true, false, -128 + signal); } var picocolors = __webpack_require__("../../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js"); var picocolors_default = /*#__PURE__*/ __webpack_require__.n(picocolors); var debug = __webpack_require__("./src/debug.ts"); const start = Date.now(); const exitPromises = []; const unsubscribe = asyncExitHook(exit_onExit, { wait: 1000 }); process.on('unhandledRejection', async (reason)=>{ core_.logger.error('Unhandled Rejection with reason:', reason instanceof Error ? reason : new Error(JSON.stringify(reason))); unsubscribe(); await exit_onExit(1); process.exit(1); }); let interrupted = false; process.on('SIGINT', ()=>{ if (interrupted) { core_.logger.info("Force exiting Rspeedy."); return process.exit(130); } interrupted = true; core_.logger.info(`Gracefully shutting down. Please wait... (Press ${picocolors_default().cyan('Ctrl+C')} again to force exit)`); exit_exit(130); }); let previousSignal = null; const exit_exit = (signal = 0)=>{ if (null !== previousSignal) (0, debug.fF)(`graceful exit called multiple times, current: ${signal}, previous: ${previousSignal}`); previousSignal = signal; (0, debug.fF)(`graceful exit process with signal: ${signal}`); gracefulExit(signal); }; async function exit_onExit(signal) { const duration = Date.now() - start; (0, debug.fF)(`exit hook fired with signal: ${signal}, duration: ${duration}`); (0, debug.fF)(`awaiting exit promises(length: ${exitPromises.length})...`); await Promise.allSettled(exitPromises); } } };