【问题标题】:Send response and continue to perform tasks Express | Node.js发送响应并继续执行任务快递 |节点.js
【发布时间】:2017-03-22 08:00:40
【问题描述】:

在 Node.js(我是新手)中,我在收到响应后尝试执行一系列任务。但是,我想让响应时间尽可能快。我不需要将这些任务的结果返回给客户端,所以我正在尝试立即返回响应。

我目前的实现大致是:

var requestTime = Date.now; 

app.post('/messages', function (req, res) {
  console.log("received request");

  // handle the response
  var body = res.body;
  res.send('Success');
  res.end();
  console.log("sent response");

  performComplexTasks(body)
})

function performComplexTasks(body){
   // perform data with body data here;
   console.log("finished tasks:", Date.now()-requestTime, "ms");
}

// -------LOG-----------
//    received request
//    POST /api/messages 200 3.685 ms - 59
//    sent response
//    finished tasks: 2500ms

发出请求的客户端似乎挂起,直到 performComplexTasks() 完成。 (POST 在 3.685 毫秒内完成,但响应需要 2500 毫秒才能完成。)

有没有办法在不让客户端等待/挂起的情况下立即发送响应并完成其他任务? (在我的例子中,客户端不能进行多个 API 调用。)

【问题讨论】:

  • 你所拥有的应该可以正常工作吗?只要响应在服务器上结束,之后发生的事情不应该影响浏览器。
  • @adeneo 我已经在本地使用 CURL 进行了测试,响应在 200- 15000ms 之间。当我注释掉performComplexTasks(body) 时,响应大约是10ms。所有其他 API 端点(没有长任务)似乎更快。这可能是因为一个独立的问题(即我的服务器 CPU 使用率而不是正确处理 reqres)?如果是这样,您对我应该从哪里开始调查有什么建议吗?
  • @adeneo 另外,如果重要的话,这个端点将被另一个服务器(不是浏览器)调用。
  • 尝试res.status(200).send('Success') 并删除res.end,然后尝试在超时或nextTick 中包装performComplexTasks()?我不知道这是否会有所作为,但这是我要开始的。

标签: javascript node.js express asynchronous


【解决方案1】:

如果您的工作不是超 CPU 密集型的,并且您可以容忍主服务器线程上的一些工作,那么只需使用 await 来中断执行,以便可以正确发送请求。您可以使用setTimeoutawait

// This line is wrong too - ask a separate question if needed
var requestTime = Date.now; 

app.post('/messages', async function (req, res) {
  console.log("received request");

  // handle the response
  var body = res.body;
  res.status(200).send({ success: true });
  console.log("sent response");

  // Method 1:
  await performComplexTasks(body)

  // Method 2:
  setTimeout(() => performComplexTasks(body), 0);
})

async function performComplexTasks(body){
   // The line below is required if using the `await` method -
   // it breaks execution and allows your previous function to
   // continue, otherwise we will only resume the other function after
   // this function is completed.
   await new Promise(resolve => setTimeout(resolve, 1));

   // perform data with body data here;
   console.log("finished tasks:", Date.now()-requestTime, "ms");
}

这并不是一个很好的解决方案,您需要使用工作线程进行长时间操作。

【讨论】:

  • 如果这种方法有效(将很快测试),那么即使您的任务是 cpu 密集型的,您也可以将 cpu 密集型工作移动到不同的端点(可能在不同的服务器上,或无服务器上) ,并在此处理程序结束时向该端点发送网络请求,这将减轻您的主线程的 cpu 密集型工作——它将把它变成一个易于并行化的异步调用。您当然希望使单独的 performComplexTasks 处理程序具有幂等性,这样如果其他人到达该端点,它就不会破坏任何东西。
【解决方案2】:

您尝试在 performComplexTasks 中执行 CPU 密集型作业,我说得对吗?如果是这样,则事件循环被该任务锁定,并且新请求正在等待,直到作业完成。

在 node.js 中,在与 http 服务器相同的进程中执行此类“复杂”任务是一种不好的做法。考虑使用后台工作者、队列或类似的东西。

详见本主题:Node.js and CPU intensive requests

【讨论】:

  • 这是真的,但是 OP 的代码应该结束响应,然后做阻塞工作,所以新的请求必须等待等等。它不应该阻止已经收到它的当前请求回应。
  • @No Danger 当您刚启动 express 应用程序时,第一个 POST /messages 请求怎么样?它工作得很快吗?
  • @No Danger 确定其他端点不受影响吗?您是否尝试在调用 POST /messages 之前和之后调用它们?还要确保 performComplexTasks 函数没有任何“全局”变量/锁(在请求之间共享)
猜你喜欢
  • 2021-02-20
  • 2018-03-24
  • 2011-04-19
  • 1970-01-01
  • 2018-09-19
  • 1970-01-01
相关资源
最近更新 更多