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

时间:2019-02-07 15:41:06

标签: javascript node.js express

假设我们有下面的代码,它的超时设置为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循环仍在工作。

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

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:-1)

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

例如:

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