NodeJS 是否在server.close()后放弃http请求?

5t7ly7z5  于 2022-12-12  发布在  Node.js
关注(0)|答案(1)|浏览(131)

我有一个普通的nodejs服务器,如下所示:

let someVar // to be set to a Promise

const getData = url => {
  return new Promise((resolve, reject) => {
    https.get(
      url,
      { headers: { ...COMMON_REQUEST_HEADERS, 'X-Request-Time': '' + Date.now() } },
      res => {
        if (res.statusCode === 401) return reject(new RequestError(INVALID_KEY, res))
        if (res.statusCode !== 200) return reject(new RequestError(BAD_REQUEST, res))

        let json = ''
        res.on('data', chunk => json += chunk)
        res.on('end', () => {
          try {
            resolve(JSON.parse(json).data)
          } catch (error) {
            return reject(new RequestError(INVALID_RESPONSE, res, json))
          }
        })
      }
    ).on('error', error => reject(new RequestError(FAILED, error)))
  })
}
const aCallback = () =>
  console.log('making api call')
  someVar = getData('someApiEndpoint')
    .then(data => { ... })
}
const main = () => {
  const server = http.createServer(handleRequest)
  anInterval = setInterval(aCallback, SOME_LENGTH_OF_TIME)

  const exit = () => {
    server.close(() => process.exit())
    log('Server is closed')
  }

  process.on('SIGINT', exit)
  process.on('SIGTERM', exit)

  process.on('uncaughtException', (err, origin) => {
    log(`Process caught unhandled exception ${err} ${origin}`, 'ERROR')
  })
}
main()

我遇到了这样一种情况:我将执行ctrl-c,并将看到Server is closed日志,然后是命令提示符,* 但随后我将看到更多的日志打印出来,表明正在进行更多的API调用
exit()内调用clearInterval(anInterval)(在server.close()之前)似乎解决了即使服务器关闭时间隔仍继续的问题,所以这很好。但是:
从这些节点文档:
关闭连接到此服务器的所有连接
*,这些连接没有发送请求或等待响应**。
也就是说,我假设server.close()不会自动终止http请求。
当我的计算机/节点不再跟踪变量someVar时,http响应信息会发生什么变化?
如果不专门终止发出http请求(并等待响应)的线程,会有什么后果?
是否有取消请求的最佳实践?
这包括什么(即,我最终会告诉API的服务器“没关系,请不要发送任何东西”,还是我只是指示节点不要接收任何新信息)?

zkure5ic

zkure5ic1#

有几件事你应该知道。首先,在软件中处理SIGINT是一件复杂的事情。其次,你永远不需要调用process.exit(),因为节点总是在它准备好的时候退出。如果你的进程没有正确退出,那意味着有“工作正在完成”,你需要停止。一旦没有更多的工作要做,节点将安全地自行退出。通过示例可以很好地解释这一点。让我们从这个简单的程序开始:

const interval = setInterval(() => console.log('Hello'), 5000);

如果运行这个程序,然后按Ctrl + C(发送SIGINT信号),节点会自动清除间隔并退出(嗯......这更像是“致命”退出,但这超出了这个答案的范围)。

const interval = setInterval(() => console.log('Hello'), 5000);

process.on('SIGINT', () => {
  console.log('SIGINT received');
});

现在,如果你运行这个程序并按下Ctrl + C,你会看到 “SIGINT received” 消息,但进程永远不会退出。当你听到SIGINT时,你是在告诉节点“嘿,我有一些事情需要在你退出之前清理”。节点会等待任何“正在进行的工作”完成后才退出。如果节点最终没有自己退出,它会告诉你“嘿,我可以看到有一些东西仍在运行-你需要停止他们之前,我将退出”。
让我们看看清除间隔后会发生什么:

const interval = setInterval(() => console.log('Hello'), 5000);

process.on('SIGINT', () => {
  console.log('SIGINT received');
  clearInterval(interval);
});

现在,如果你运行这个程序并按下Ctrl + C,你会看到 “SIGINT received” 消息,进程将顺利退出。一旦我们清除了间隔,节点就足够聪明地看到没有发生任何事情,它将退出。这里重要的一课是,如果你监听SIGINT,你将等待任何任务完成。您应该永远不需要调用process.exit()
至于这与您的代码有何关系,您需要做三件事:

  • http服务器监听请求
  • 间隔
  • 传出https.get请求

当程序退出时,您需要清理上述各项。在最简单的情况下,您应该执行以下操作:

  • 关闭服务器:server.close();
  • 清除间隔:clearInterval(anInterval);
  • 销毁任何传出请求:request.destroy()

您可能决定在关闭服务器之前等待任何传入的请求完成,或者您可能希望侦听传出请求的“close”事件以检测任何丢失的连接。这取决于您。您应该阅读node http docs中可用的方法和事件。希望现在您已经开始了解SIGINT在软件中是如何复杂的。祝您好运。

相关问题