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

Node.js中Oracle连接池触发NJS-040超时错误求助

解决Node.js应用中node-oracledb连接池NJS-040超时错误

问题背景

使用Oracle客户端19.20.0.0.0与node-oracledb 6.1.0开发Node.js应用,采用连接池结合中间件的方式获取数据库连接,应用随机抛出如下错误:

Error: NJS-040: connection request timeout. Request exceeded "queueTimeout" of 60000

相关代码实现及错误日志如下:

连接池初始化及中间件代码

const oracledb = require('oracledb');
const logger = require('../logger');

const { PASSWORD, USERNAME, CONN_STRING } = require('../constant');
oracledb.initOracleClient();
oracledb.outFormat = oracledb.OUT_FORMAT_OBJECT;

async function initializeOraclePool() {
    try {
        await oracledb.createPool({
            user: USERNAME,
            password: PASSWORD,
            connectionString: CONN_STRING,
            poolMax: 8,
            poolMin: 1,
            poolTimeout: 2000000,
        });

        logger.info(`Oracle client version is ${oracledb.oracleClientVersionString}`)

    } catch (error) {
        logger.error(error)
        console.error('Error creating Oracle connection pool:', error);
    }
}

// Middleware to acquire a database connection from the pool
async function getOracleConnection(req, res, next) {
    try {
        req.connection = await oracledb.getConnection();
        next();
    } catch (error) {
        console.error('Error acquiring Oracle connection:', error);
        logger.error(error)
        res.status(500).json({ error: 'Database connection error' });
    }
}

module.exports = { initializeOraclePool, getOracleConnection };

业务代码示例

const fetchSupplierRecommendation = async (req, res) => {
    try {
        const { connection = {}, body = {}, query = {}, params = {} } = req;
        let { planId, srInstanceId, categorySetId, from, to } = query

        const result = await connection.execute(SQLQuery.SupplierRecommendation(planId, srInstanceId, categorySetId, from, to))
        successHandler(res, result.rows)

    } catch (error) {
        errorHandler(res, error)
    }
}

错误日志

0|index  | Error acquiring Oracle connection: Error: NJS-040: connection request timeout. Request exceeded "queueTimeout" of 60000
0|index  |     at Object.throwErr (/var/node/node_modules/oracledb/lib/errors.js:588:10)
0|index  |     at Timeout._onTimeout (/var/node/node_modules/oracledb/lib/pool.js:443:22)
0|index  |     at listOnTimeout (node:internal/timers:569:17)
0|index  |     at process.processTimers (node:internal/timers:512:7) {
0|index  |   code: 'NJS-040'
0|index  | }

原因分析

  1. 连接未正确释放:当前代码中,从连接池获取的连接在请求处理完成后没有被释放回池,导致连接被长期占用。当所有poolMax(当前设置为8)个连接都被占用时,新的连接请求会进入队列等待,超过默认的queueTimeout(60秒)后就会抛出NJS-040错误。
  2. 连接池配置不合理:poolMax设置可能无法满足应用并发需求;未显式设置queueTimeout,使用默认值60秒,若并发请求较多,排队时间容易超过阈值。
  3. 慢查询占用连接:如果业务SQL执行时间过长,会导致连接长时间被占用,加剧连接池耗尽的问题。

解决方案

1. 确保连接在请求结束后释放

修改中间件,在请求处理完成(无论成功或失败)后,将连接释放回池:

async function getOracleConnection(req, res, next) {
    try {
        req.connection = await oracledb.getConnection();
        // 请求结束后释放连接
        res.on('finish', async () => {
            if (req.connection) {
                try {
                    await req.connection.close();
                } catch (closeErr) {
                    logger.error('Error closing Oracle connection:', closeErr);
                }
            }
        });
        next();
    } catch (error) {
        console.error('Error acquiring Oracle connection:', error);
        logger.error(error);
        res.status(500).json({ error: 'Database connection error' });
    }
}

或者在业务代码的finally块中释放连接:

const fetchSupplierRecommendation = async (req, res) => {
    let connection;
    try {
        connection = req.connection;
        const { body = {}, query = {}, params = {} } = req;
        let { planId, srInstanceId, categorySetId, from, to } = query

        const result = await connection.execute(SQLQuery.SupplierRecommendation(planId, srInstanceId, categorySetId, from, to))
        successHandler(res, result.rows)

    } catch (error) {
        errorHandler(res, error)
    } finally {
        if (connection) {
            try {
                await connection.close();
            } catch (closeErr) {
                logger.error('Error closing connection:', closeErr);
            }
        }
    }
}

2. 优化连接池配置

根据应用并发量调整poolMax,同时显式设置queueTimeout(根据业务容忍度调整,比如延长至120秒):

await oracledb.createPool({
    user: USERNAME,
    password: PASSWORD,
    connectionString: CONN_STRING,
    poolMax: 16, // 根据并发量调整,比如翻倍
    poolMin: 1,
    poolTimeout: 2000000,
    queueTimeout: 120000 // 显式设置排队超时时间,单位毫秒
});

3. 排查慢查询

检查SQLQuery.SupplierRecommendation生成的SQL是否存在性能问题,比如缺少索引、查询逻辑冗余等。可以通过Oracle的执行计划分析慢查询,优化SQL性能,减少连接占用时间。

4. 监控连接池状态

添加日志监控连接池的使用情况,比如获取连接、释放连接的时间,以及池的当前连接数:

// 在初始化后添加监控
const pool = await oracledb.createPool(...);
setInterval(() => {
    const stats = pool.getStatistics();
    logger.info(`Connection Pool Stats: ${JSON.stringify(stats)}`);
}, 60000); // 每分钟打印一次状态

内容的提问来源于stack exchange,提问作者Abhinay Narayan Singh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 23:05:18