Deno中如何检测Web Worker关闭并实现错误捕获与重启?
Deno Worker 进程关闭处理与错误重启方案
核心问题说明
Deno Worker API 完全对齐浏览器 Web Worker 规范,不存在onclose事件,原生仅提供onerror监听 Worker 内的未捕获错误。默认情况下,Worker 抛出未捕获错误会导致宿主进程崩溃(配合--watch参数时,这种崩溃会触发宿主自动重启)。
可行实现方案
1. Worker 内部主动捕获错误并通知宿主
在 Worker 全局作用域捕获所有错误,阻止默认崩溃行为,通过postMessage向宿主发送退出信号:
// Worker 侧代码 globalThis.addEventListener("error", (event) => { // 阻止错误向上冒泡引发宿主进程崩溃 event.preventDefault(); // 向宿主传递错误信息与退出指令 globalThis.postMessage({ command: "exit", error: { message: event.message, filename: event.filename, lineno: event.lineno } }); }); // 若Worker因业务逻辑需要正常退出,也可主动发送exit指令 // globalThis.postMessage({ command: "exit" });
2. 宿主侧监听消息并处理终止与重启
在宿主进程中监听 Worker 消息,收到exit指令后主动终止 Worker,根据错误状态决定是否重启:
// 宿主侧代码 function createWorker() { const worker = new Worker(new URL("./worker.ts", import.meta.url).href, { type: "module" }); worker.onmessage = (event) => { const { command, error } = event.data; if (command === "exit") { // 主动终止Worker实例 worker.terminate(); console.log("Worker已终止"); // 存在错误时延迟重启Worker if (error) { console.error("Worker错误详情:", error); setTimeout(() => { console.log("启动Worker重启..."); createWorker(); }, 5000); } } }; // 监听Worker初始化阶段的加载错误 worker.onerror = (error) => { console.error("Worker初始化失败:", error); worker.terminate(); setTimeout(() => createWorker(), 5000); }; return worker; } // 启动首个Worker createWorker();
--watch参数的特殊坑点
使用deno run --watch时,Worker 内的未捕获错误会触发宿主进程的热重启(这是--watch的默认机制),导致错误捕获逻辑无法正常测试。测试阶段建议暂时移除--watch参数,或确保 Worker 内所有错误都被捕获并发送exit指令,避免触发--watch的重启行为。
边界情况补充处理
若 Worker 因系统级原因(如内存不足、被外部进程强制终止)意外退出,宿主无法收到exit消息,会进入 Worker 失联状态。可通过心跳机制补充检测:
// Worker侧添加心跳发送逻辑 setInterval(() => { globalThis.postMessage({ command: "heartbeat" }); }, 2000); // 宿主侧处理心跳超时 function createWorker() { const worker = new Worker(/* ... */); let heartbeatTimer: number; const resetHeartbeat = () => { clearTimeout(heartbeatTimer); heartbeatTimer = setTimeout(() => { console.log("Worker心跳超时,强制重启"); worker.terminate(); createWorker(); }, 5000); }; worker.onmessage = (event) => { if (event.data.command === "heartbeat") { resetHeartbeat(); } else if (event.data.command === "exit") { clearTimeout(heartbeatTimer); // 执行原有的exit处理逻辑 // ... } }; resetHeartbeat(); // ... }
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

