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

NodeJS调用SQL Server存储过程出现Aborted错误的解决求助

NodeJS调用SQL Server存储过程出现PendingOperation.js Aborted错误排查

问题背景

此前通过NodeJS API调用SQL Server存储过程获取电话类型数据正常,但调用获取军种分支的存储过程时,触发了来自PendingOperation.js的aborted错误,请求协助解决。

获取电话类型的代码

let query;
query = env.STOREDPROCS.GET.PHONETYPES; // to add input var put @varname='' <-- VALUE
let db = {};
module.exports = db;

initializeDB();

async function initializeDB() {
  sql
    .connect(config)
    .then((dbConn) => {
      console.log("connected for phonetypes: ", query);

      dbConn.query(query, (err, data) => {
        if (err) {
          console.log("Error getting PhoneTypes from Stored Proc: ", err);
          sql.close();
        }
        if (data) {
          console.log("ALL PHONE TYPES RETRIEVED: ", data);
          phonetypesDataArray.push(data.recordset);
          console.log("RECORDSET PHONETYPES: ", phonetypesDataArray);
          db.PhoneTypesModel = phonetypesDataArray;
          console.log("Phone Types Model: ", db.PhoneTypesModel);
          sql.close();
          return db.PhoneTypesModel;
        } else {
          let errmsg =
            "NO RECORDS RETURNED for " + env.STOREDPROCS.GET.PHONETYPES;
          console.log(errmsg);
          phonetypesDataArray.push({ error: errmsg });
          sql.close();
          return phonetypesDataArray;
        }
      });
    })
    .catch((err) => {
      console.log("error", err);
      errmsg = `"Error Connecting to Database: ", ${err}`;
      phonetypesDataArray.push(errmsg);
      return phonetypesDataArray;
    });
}

获取军种分支的代码

let db = {};
module.exports = db;

initializeDB();

async function initializeDB() {
  sql
    .connect(config)
    .then((dbConn) => {
      console.log("connected inside GET BRANCHES");

      dbConn.query(query, (err, data) => {
        if (err) {
          console.log("Error getting BRANCHES OF SERVICE from Stored Proc: ", err);
          sql.close();
        }
        if (data) {
          console.log("ALL BRANCHES OF SERVICE RETRIEVED: ", data);
          branchOfSvcDataArray.push(data.recordset);
          console.log("RECORDSET BRANCHES OF SERVICE: ", branchOfSvcDataArray);
          db.branchOfSvcDataArray = phonetypesDataArray;
          console.log("Branches of Service Model: ", db.branchOfSvcDataArray);
          sql.close();
          return db.branchOfSvcDataArray;
        } else {
          let errmsg =
            "NO RECORDS RETURNED for " + env.STOREDPROCS.GET.BRANCHESOFSVC;
          console.log(errmsg);
          branchOfSvcDataArray.push({ error: errmsg });
          sql.close();
          return branchOfSvcDataArray;
        }
      });
    })
    .catch((err) => {
      console.log("error", err);
      errmsg = `"Error Connecting to Database: ", ${err}`;
      branchOfSvcDataArray.push(errmsg);
      return branchOfSvcDataArray;
    });
}

错误日志

[nodemon] restarting due to changes...
[nodemon] starting `node index.js`
[nodemon] restarting due to changes...
[nodemon] starting `node index.js`
Listening on port number: 8000
connected for phonetypes:  usp_getPhoneTypes
connected branches of service
connected column info
connected db-conn
connected for getting column info:  usp_getColumnInforForADB
connected inside GET BRANCHES
ALL PHONE TYPES RETRIEVED:  {
  recordsets: [ [ [Object], [Object], [Object] ] ],
  recordset: [
    { phone_types_id: 1, phone_type_name: 'CELL', rowCnt: 3 },
    { phone_types_id: 2, phone_type_name: 'HOME', rowCnt: 3 },
    { phone_types_id: 3, phone_type_name: 'WORK', rowCnt: 3 }
  ],
  output: {},
  rowsAffected: []
}
RECORDSET PHONETYPES:  [
  [
    { phone_types_id: 1, phone_type_name: 'CELL', rowCnt: 3 },
    { phone_types_id: 2, phone_type_name: 'HOME', rowCnt: 3 },
    { phone_types_id: 3, phone_type_name: 'WORK', rowCnt: 3 }
  ]
]
Phone Types Model:  [
  [
    { phone_types_id: 1, phone_type_name: 'CELL', rowCnt: 3 },
    { phone_types_id: 2, phone_type_name: 'HOME', rowCnt: 3 },
    { phone_types_id: 3, phone_type_name: 'WORK', rowCnt: 3 }
  ]
]

Error getting BRANCHES OF SERVICE from stored procedure.

Error: aborted

at PendingOperation.abort (C:\node-rest-api\node_modules\tarn\dist\PendingOperation.js:25:21)

at C:\node-rest-api\node_modules\tarn\dist\Pool.js:208:25

at Array.map ()

at C:\node-rest-api\node_modules\tarn\dist\Pool.js:207:53

at runNextTicks (node:internal/process/task_queues:61:5)

at processImmediate (node:internal/timers:437:9)

NO RECORDS RETURNED for usp_getBranches

C:\node-rest-api\node_modules\tarn\dist\PendingOperation.js:25

this.reject(new Error('aborted'));

Error: aborted

at PendingOperation.abort (C:\node-rest-api\node_modules\tarn\dist\PendingOperation.js:25:21)

at C:\node-rest-api\node_modules\tarn\dist\Pool.js:208:25

at Array.map ()

at C:\node-rest-api\node_modules\tarn\dist\Pool.js:207:53

at runNextTicks (node:internal/process/task_queues:61:5)

at processImmediate (node:internal/timers:437:9)

[nodemon] app crashed - waiting for file changes before starting...

问题分析与解决方案

核心问题定位

  1. 未定义query变量:军种分支代码中没有初始化query变量,直接调用dbConn.query(query)会触发错误,而电话类型代码中明确赋值了query = env.STOREDPROCS.GET.PHONETYPES。
  2. 连接池被过早关闭:两个模块都在请求完成后调用sql.close(),这会关闭整个连接池,导致后续请求无法获取连接,触发tarn池的aborted错误(等待获取连接的操作被终止)。
  3. 变量混淆:军种分支代码中错误地将phonetypesDataArray赋值给db.branchOfSvcDataArray,应该使用branchOfSvcDataArray。

修复步骤

1. 补全军种分支代码的query变量

在军种分支代码顶部添加:

let query;
query = env.STOREDPROCS.GET.BRANCHESOFSVC;

2. 避免全局关闭连接池

不要使用sql.close(),而是释放单个连接。对于mssql库,dbConn是连接实例,请求完成后应调用dbConn.close()而非全局的sql.close()。全局sql.close()会销毁整个连接池,导致后续所有请求失败。

3. 修正变量赋值错误

将军种分支代码中的:

db.branchOfSvcDataArray = phonetypesDataArray;

改为:

db.branchOfSvcDataArray = branchOfSvcDataArray;

4. 改用async/await写法(推荐)

回调嵌套容易导致错误,改用async/await让代码更清晰,同时更好地处理异步流程:

let query = env.STOREDPROCS.GET.BRANCHESOFSVC;
let db = {};
module.exports = db;

(async function initializeDB() {
  try {
    const dbConn = await sql.connect(config);
    console.log("connected inside GET BRANCHES");
    
    const data = await dbConn.query(query);
    console.log("ALL BRANCHES OF SERVICE RETRIEVED: ", data);
    
    branchOfSvcDataArray.push(data.recordset);
    console.log("RECORDSET BRANCHES OF SERVICE: ", branchOfSvcDataArray);
    db.branchOfSvcDataArray = branchOfSvcDataArray;
    console.log("Branches of Service Model: ", db.branchOfSvcDataArray);
    
    // 释放当前连接,而非关闭整个池
    await dbConn.close();
    return db.branchOfSvcDataArray;
  } catch (err) {
    console.log("Error getting BRANCHES OF SERVICE from Stored Proc: ", err);
    const errmsg = `Error Connecting to Database: ${err}`;
    branchOfSvcDataArray.push({ error: errmsg });
    return branchOfSvcDataArray;
  }
})();

额外建议

  • 建立全局连接池:在应用启动时初始化一次连接池,而非每个模块单独创建连接,避免重复创建和关闭池的开销。
  • 错误处理优化:确保在所有分支中都正确处理错误,避免未捕获异常导致应用崩溃。
  • 变量声明检查:确保所有使用的变量都已正确声明和赋值,避免隐式全局变量。

内容的提问来源于stack exchange,提问作者Peter The Angular Dude

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 00:37:19