在Express.js中请求超时后停止运行任务



让我们假设我们有下面的代码,它的超时设置为5秒。

router.get('/timeout', async (req, res, next) => {
req.setTimeout(5000, () => {
res.status(503)
res.send()
})
while (true) {
console.log("I'm alive")
}
res.status(200)
res.send({msg: 'success'})
})

我知道最后两行永远不会达到,但这不是重点。我想解决的问题是,尽管发送了响应,while循环仍在工作。

有没有什么方法可以杀死这种仍在工作的任务?

有两种类型的长期运行任务,两者的取消都不同:

1) 异步任务:

它们可能需要一段时间,但它们没有使用JavaScript引擎,而是引擎处于空闲状态,等待一些外部数据(数据库/文件/计时器)。在某些情况下(例如计时器),您可以很容易地放弃该外部操作,也可以将其作为事件触发,因为引擎没有被阻止,并且可以处理取消。如果异步操作不能直接取消(例如数据库读取),您可以等待它完成并取消它,然后:

class Cancelable {
constructor() { 
this.cancelled = false;
this.handlers = [];
}
onCancel(handler) { this.handlers.push(handler); }
cancel() {
this.cancelled = true;
this.handlers.forEach(handler => handler());
}
}

// inside of the request handler:
const canceller = new Cancelable;
req.setTimeout(5000, () => {
res.status(503);
res.send();
canceller.cancel(); // propagate cancellation
});
// Some long running, async cancellable task
const timer = setTimeout(function() {
res.send("done");
}, 10000 * Math.random())
// on cancellation just remove the timer
canceller.onCancel(() => clearTimeout(timer));
unCancellableAction(function callback() {
if(canceller.canceled) return; // exit early if it was cancelled
res.send("done");
});

2) 同步任务:您不能直接取消同步任务,因为引擎正忙于执行任务,并且无法处理取消。为了使它们可以取消,您必须使用轮询,任务必须暂停其作业,检查是否应该取消,然后继续或中止。在JS中,可以用生成器函数来完成(因为它们可以产生执行):

function runMax(time, action) {
const gen = action(), start = Date.now();
let done, value;
do {
({ done, value } = gen.next());
} while(!done && Date.now() < start + time)
return value;
}
// inside the request handler:
runMax(5000, function* () {
while(true) {
// ... some jobs
// yield at a safe position to allow abortion:
yield;
}
});

我认为您需要在while循环中添加新的if语句来打破循环。

例如:

while (!req.timeout) {
if (!req.timeout) {
break;
}
}

最新更新