我创建了一个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}`);
}
答案 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
调用就在执行之前(因为返回语句)。该超时将立即开始倒计时。但是,执行调用不能保证在使用线程池中的线程时立即启动,并且可能必须等待一个线程可用。请记住一些事情......