簡體   English   中英

在 server.close() 之后放棄了 http 個請求?

[英]Abandoned http requests after server.close()?

我有一個像這樣的普通 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 的服務器“沒關系,請不要發送任何東西”,或者我會指示節點不接收任何新信息)?

您應該注意幾件事。 首先,處理 SIGINT 在軟件中是一件復雜的事情。 接下來,您永遠不需要調用process.exit() ,因為節點總是會在准備就緒時退出。 如果您的流程沒有正確退出,則意味着您需要停止“正在完成的工作”。 一旦沒有更多工作要做,節點將自行安全退出。 這最好用例子來解釋。 讓我們從這個簡單的程序開始:

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

如果你運行這個程序然后按Ctrl + C (它發送 SIGINT 信號),node 會自動為你清除間隔並退出(好吧......它更像是一個“致命”退出,但這超出了這個的 scope回答)。 一旦您偵聽SIGINT事件,此自動退出行為就會發生變化:

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

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

現在,如果您運行該程序並按Ctrl + C ,您將看到“SIGINT received”消息,但該進程永遠不會退出。 當您監聽 SIGINT 時,您是在告訴節點“嘿,在您退出之前我需要清理一些東西”。 然后 Node 將等待任何“正在進行的工作”在退出之前完成。 如果節點最終沒有自行退出,它會告訴你“嘿,我可以看到有些東西還在運行 - 你需要在我退出之前停止它們”。

讓我們看看如果我們清除間隔會發生什么:

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

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

現在,如果您運行此程序並按Ctrl + C ,您將看到“SIGINT received”消息,並且該過程將正常退出。 一旦我們清除間隔,node 就足夠聰明,可以看到沒有任何事情發生,它就會退出。 這里的重要教訓是,如果您監聽SIGINT ,您就需要等待任何任務完成,並且您永遠不需要調用process.exit()

就這與您的代碼的關系而言,您正在進行三件事:

  • http 服務器監聽請求
  • 一個間隔
  • 傳出 https.get 請求

當您的程序退出時,您需要清理上述項目。 在最簡單的情況下,您應該執行以下操作:

  • 關閉服務器: server.close();
  • 清除間隔: clearInterval(anInterval);
  • 銷毀任何傳出請求: request.destroy()

您可能決定在關閉服務器之前等待所有傳入請求完成,或者您可能希望監聽傳出請求的“關閉”事件以檢測任何丟失的連接。 那是你的事。 您應該閱讀節點http文檔中提供的方法和事件。 希望現在您已經開始了解 SIGINT 在軟件中是一個多么復雜的問題。 祝你好運。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM