[英]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()
。
就這與您的代碼的關系而言,您正在進行三件事:
當您的程序退出時,您需要清理上述項目。 在最簡單的情況下,您應該執行以下操作:
server.close();
clearInterval(anInterval);
request.destroy()
您可能決定在關閉服務器之前等待所有傳入請求完成,或者您可能希望監聽傳出請求的“關閉”事件以檢測任何丟失的連接。 那是你的事。 您應該閱讀節點http
文檔中提供的方法和事件。 希望現在您已經開始了解 SIGINT 在軟件中是一個多么復雜的問題。 祝你好運。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.