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