You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js应用随机出现NJS-040连接请求超时问题求助

Node.js Oracle连接池随机NJS-040超时错误解决方案

问题概述

运行Node.js应用时随机触发NJS-040: Request exceeded queueTimeout of 60000错误,无固定触发规律,重启应用可暂时恢复。错误发生在获取连接池连接的await oracledb.getConnection(process.env.ORACLE_POOL);代码行。

现有Oracle连接池配置

const oracledb = require("oracledb");

exports.initOracle = async function init() {
    try {
        oracledb.initOracleClient({ libDir: "C:\\instantclient_21_10"});
        await oracledb.createPool({
            user: process.env.ORACLE_USER,
            password: process.env.ORACLE_PASSWORD,
            connectString: process.env.ORACLE_STRING,
            poolAlias: process.env.ORACLE_POOL,
            poolMin: 1,
            poolMax: 30,
            poolIncrement: 1,
            poolTimeout: 10
        });
        console.log("Oracle connection pool started");
    } catch (err) {
        console.error("init() error: " + err.message);
    }
};

exports.closePool = async function () {
    try {
        const pool = await oracledb.getPool(process.env.ORACLE_POOL);
        await pool.close();
    } catch (err) {
        console.log("Error occur while closing pool: ", process.env.ORACLE_POOL);
    }
};

触发错误的查询函数

//Search for patient in oracle
exports.getPatient = async (req, res, next) => {
    let result;
    let pesel = req.body.pesel;

    let conn;
    try {
        conn  = await oracledb.getConnection(process.env.ORACLE_POOL);

        result = await conn.execute(
            "SELECT id, imie, nazw, pesl FROM pacj WHERE pesl=:pesel",
            { pesel: pesel },
            { outFormat: oracledb.OBJECT }
        );
        if (result.rows.length !== 1) {
            res.status(400).send({
                message: "Patient not found in Oracle DB",
            });
        } else {
            res.locals.patient = {
                patientId: result.rows[0]["ID"],
                firstname: result.rows[0]["IMIE"],
                lastname: result.rows[0]["NAZW"],
                pesel: result.rows[0]["PESL"],
            };
            next();
        }
    } catch (err) {
        console.error(err);
        res.status(500).send({
            message: "Something went wrong while searching for patient query",
        });
    } finally {
        if (conn) {
            try {
                await conn.close();
                console.log("getPatient finally closed connection")
            } catch (err) {
                console.error(err);
            }
        }
    }
};

排查与解决建议

1. 优化连接池参数配置

当前配置未显式设置queueTimeout,默认60秒,当poolMax(30个)连接全部被占用且无法及时释放时,新请求会排队超时。调整参数:

  • 延长queueTimeout至120秒,给连接释放留缓冲时间
  • 添加poolPingInterval定时检测空闲连接有效性,避免池中存在失效连接
  • 可选添加pingInterval,每次获取连接前自动检测连接可用性

修改后的连接池创建代码:

await oracledb.createPool({
    user: process.env.ORACLE_USER,
    password: process.env.ORACLE_PASSWORD,
    connectString: process.env.ORACLE_STRING,
    poolAlias: process.env.ORACLE_POOL,
    poolMin: 1,
    poolMax: 30,
    poolIncrement: 1,
    poolTimeout: 10,
    queueTimeout: 120000, // 延长队列超时至2分钟
    poolPingInterval: 60, // 每60秒检测空闲连接
    pingInterval: 30 // 每次获取连接前检测有效性
});

2. 排查隐性连接泄漏

虽然日志显示连接已关闭,仍需确认是否存在极端场景下的泄漏:

  • 在连接获取和释放时添加更详细日志,记录连接ID、时间戳,追踪每个连接的生命周期:
    // 获取连接时
    conn = await oracledb.getConnection(process.env.ORACLE_POOL);
    console.log(`获取连接ID: ${conn.id},时间: ${new Date().toISOString()}`);
    // 释放时
    await conn.close();
    console.log(`释放连接ID: ${conn.id},时间: ${new Date().toISOString()}`);
    
  • 检查其他使用连接池的代码,确保所有获取的连接都在finally块中关闭,避免遗漏。

3. 优化查询性能,减少连接占用时长

查询缓慢会导致连接长时间被占用,加剧池资源紧张:

  • 为pacj表的pesl字段创建索引,加速查询:
    CREATE INDEX idx_pacj_pesl ON pacj(pesl);
    
  • 确认查询语句无冗余逻辑,确保只返回必要字段(当前已实现)。

4. 添加连接池健康检查与自动恢复

定时检测连接池状态,异常时自动重建:

// 连接池健康检查函数
async function checkPoolHealth() {
    try {
        const pool = await oracledb.getPool(process.env.ORACLE_POOL);
        const conn = await pool.getConnection();
        await conn.close();
    } catch (err) {
        console.error("连接池异常,尝试重建:", err.message);
        // 关闭旧池
        try {
            const oldPool = await oracledb.getPool(process.env.ORACLE_POOL);
            await oldPool.close(0); // 强制关闭所有连接
        } catch (e) {
            console.error("关闭旧池失败:", e.message);
        }
        // 重新初始化连接池
        await exports.initOracle();
    }
}

// 每5分钟执行一次健康检查
setInterval(checkPoolHealth, 300000);

5. 升级oracledb依赖版本

旧版本可能存在连接池隐性bug,升级到最新稳定版:

npm install oracledb@latest

内容的提问来源于stack exchange,提问作者Callz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 18:15:08