0

我创建了一个 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}`);

}
4

3 回答 3

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
   });
};

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

于 2017-05-19T04:56:56.153 回答
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块中连接。

于 2017-05-20T20:12:07.180 回答
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调用就在执行之前(因为 return 语句)。该超时将立即开始倒计时。但是,执行调用不能保证立即启动,因为它使用线程池中的一个线程,并且可能必须等到一个线程可用。只是要记住一点...

于 2017-05-19T18:31:18.900 回答