当Promise拒绝它时,节点js停止长进程任务

时间:2017-05-19 04:07:31

标签: node.js promise oracledb oracledb-npm

我创建了一个promise函数来处理一个长时间的查询任务。有时候任务会阻塞几个小时。我想设置一个时间来停止任务。下面是代码。

它可以正确返回错误消息,但在停止之前它仍然长时间运行connection.execute()。那么如何在返回拒绝消息时立即停止它?

谢谢!

function executeQuery(connection, query) {
return new Promise((resolve, reject) => {
    "use strict";
    //long time query
    connection.execute(query, function (err, results) {
        if (err) reject('Error when fetch data');
        else resolve(results);
        clearTimeout(t);
    });

    let t = setTimeout(function () {
        reject('Time Out');
    }, 10);
})


(async () => {
"use strict";
oracle.outFormat = oracle.OBJECT;

try {
    let query = fs.readFileSync("query.sql").toString();
    let results = await executeQuery(connection, query);

    console.log(results.rows);
} catch (e) {
    console.log(`error:${e}`);

}

3 个答案:

答案 0 :(得分:1)

试试这个(使用bluebird承诺):

var execute = Promise.promisify(connection.execute);

function executeQuery(connection, query) {
   return execute.call(connection, query)
   .timeout(10000)
   .then(function (results) {
      // handle results here
   })
   .catch(Promise.TimeoutError, function (err) {
      // handle timeout error here
   });
   .catch(function (err) {
      // handle other errors here
   });
};

如果这仍然阻塞,那么您使用的数据库驱动程序可能实际上是同步的而不是异步的。在这种情况下,该驱动程序将与节点事件循环不兼容,您可能希望查看另一个。

答案 1 :(得分:1)

  

那么如何在返回拒绝消息时立即停止它?

根据文档,您可以使用connection.break

return new Promise((resolve, reject) => {
    connection.execute(query, (err, results) => {
        if (err) reject(err);
        else resolve(results);
        clearTimeout(t);
    });

    const t = setTimeout(() => {
        connection.break(reject); // is supposed to call the execute callback with an error
    }, 10);
})

确保release块中的finally连接。

答案 2 :(得分:0)

正如Bergi所提到的,您需要使用connection.break方法。

给出以下功能:

create or replace function wait_for_seconds(
  p_seconds in number
)
  return number
is
begin
  dbms_lock.sleep(p_seconds);

  return 1;
end;

以下是其使用示例:

const oracledb = require('oracledb');
const config = require('./dbConfig.js');
let conn;
let err;
let timeout;

oracledb.getConnection(config)
  .then((c) => {
    conn = c;

    timeout = setTimeout(() => {
      console.log('Timeout expired, invoking break');

      conn.break((err) => {
        console.log('Break finished', err);
      });
    }, 5000);

    return conn.execute(
     `select wait_for_seconds(10)
      from dual`,
      [],
      {
        outFormat: oracledb.OBJECT
      }
    );
  })
  .then(result => {
    console.log(result.rows);

    clearTimeout(timeout);
  })
  .catch(err => {
    console.log('Error in processing', err);

    if (/^Error: ORA-01013/.test(err)) {
      console.log('The error was related to the timeout');
    }
  })
  .then(() => {
    if (conn) { // conn assignment worked, need to close
      return conn.close();
    }
  })
  .catch(err => {
    console.log('Error during close', err)
  });

请记住,setTimeout调用就在执行之前(因为返回语句)。该超时将立即开始倒计时。但是,执行调用不能保证在使用线程池中的线程时立即启动,并且可能必须等待一个线程可用。请记住一些事情......