Nodejs奇葩的bug经历,用nodejs写了个库存监控工具,运行一段时间后总是卡死

每次都是运行 10 多个小时就卡死,不退出执行,也没有错误日志。

所以打了些断点想看看卡死在哪里了,结果在非常奇怪的位置。查看内存溢出,fd 溢出等等都比较正常。stack 追踪太复杂,没找到合适的工具。

查论坛有个解决办法就是限制循环运行的次数,在运行一段时间后主动使用 process.exit 退出然后让 pm2 拉起来。

于是准备去改代码实操了,却发现之前的代码是这样的 👇


let retryCount = 4 * 60 * 60; // 基于库存检测的模式,单次耗时 3s 左右。

(async () => { // …

// 循环检测购物车
for (let i = 0; i < retryCount; i++) {
    // ...

    await sleep(5);
}

})();

Σ(°ロ°),原来是我自己加了 retryCount ,但是我忘记了!!!原来卡死就是循环次数耗尽了。(另外这一段代码循环次数耗尽并不会退出会阻塞住)


Nodejs奇葩的bug经历,用nodejs写了个库存监控工具,运行一段时间后总是卡死

17 回复

不忍直视


炸裂

所以这不是 bug ,这是 feature

所以。。楼主打算怎么 fix ?

循环次数耗尽,为什么会阻塞住呢? for 循环不是不会执行了么

不执行了,但是程序也不会退出,需要手动写 exit 进行退出,我也不太理解这个机制。

八成还是哪里有 bug ,当你不知道他为什么会阻塞住的时候说明还是哪里有问题。你可能只是找到了一个表象的 bug

还是要 fix 一下,退出循环之后加上一个 exit(0) 让程序主动退出,然后现在也加上了 pm2 主动拉起。

好像很有道理,为啥循环结束会阻塞是一个值得深究的问题, 我再去研究一下。

好久好久没写过 nodejs 了,不过我记得 libuv 应该是 loop 里有 callback 就不会退出循环吧。对应的就是 nodejs 如果有在运行的 Promise 就不会退出?

对的,我现在测试了一下,就是有没清理的环境,所以整个 async fn 不会退出。

(async () => {
var browser = await firefox.launch();

var context = await browser.newContext();

// await context.close(); // 这里注释就不会退出执行。
// await browser.close();

console.log(“done??”);
})();


可能数据库没有关闭,就卡在那里了。

笑出声来 :D

数据库连接没关闭吧,

请用 for await ,否则循环不会等待,一次性 100 await sleep(5)

因为 node 在还持有 fd 或者连接,或者 event loop 未清空,或者监听了某些进程事件的时候,不会自动退出。
我曾经遇到过有个 sdk 存在未清理的 fd ,只能在代码里手动 exit()

在Node.js中遇到程序卡死的问题确实令人头疼,这通常是由于内存泄漏、事件循环阻塞或者资源未正确释放等原因引起的。以下是一些常见的排查和解决此类问题的步骤,以及一个简短的代码示例,帮助你定位和解决可能的问题。

  1. 内存泄漏:使用Node.js内置的内存分析工具,如process.memoryUsage(),定期检查内存使用情况。

  2. 事件循环阻塞:确保没有长时间运行的同步代码阻塞事件循环。使用异步I/O操作,如fs.promises代替fs的回调或同步方法。

  3. 资源未释放:确保所有数据库连接、文件句柄等在使用完毕后正确关闭。

以下是一个简单的示例,展示如何定期检查内存使用情况并处理潜在的阻塞操作:

const fs = require('fs').promises;
const interval = setInterval(() => {
    const memory = process.memoryUsage();
    console.log(`Memory Usage: ${JSON.stringify(memory)}`);
}, 10000); // 每10秒检查一次内存

async function fetchInventory() {
    // 模拟异步操作,如从数据库获取库存信息
    await fs.readFile('inventory.txt', 'utf8');
    console.log('Inventory fetched');
}

// 使用try-catch和async函数处理可能的错误和异常
(async () => {
    try {
        while (true) {
            await fetchInventory();
            // 添加其他监控逻辑
        }
    } catch (error) {
        console.error('Error:', error);
    }
})();

通过上述方法,你可以更有效地监控和排查Node.js应用中的卡死问题。

回到顶部