從我所知道的情況來看,由於Node.js中事件循環的性質,無法輕鬆阻止請求在已被切換到回調後處理功能。由於每個事件回調都不與任何其他特定的流程或事件綁定,因此一旦將回調添加到事件循環的隊列中或正在處理中,即使request.on('超時「)處理程序被觸發。請求超時時停止處理請求
如果超時請求有什麼方法停止處理請求?我能想到部分解決這個問題的唯一方法是在請求期間執行的每個異步回調的頂部添加一個檢查,以查看請求是否超時,如果有,則立即返回並停止連續的回調。
但是,如果已經有一個由超時請求處理的未完成的異步呼叫正在處理,則這並不能解決問題。在這種情況下,除非您銷燬與異步處理(例如執行MySQL查詢)的任何連接,否則它將繼續並最終調用與其關聯的異步回調。
這在PHP + Apache等其他編程模式中不存在問題,因爲apache會爲每個傳入請求創建一個新的PHP進程,所以如果請求超時,進程最終會終止並且整個執行流程停止。
有沒有人遇到這個問題,並找到一個現有的庫或自定義的方式來輕鬆解決這個問題?
編輯:要添加一個具體的例子:
現在,我們有內置用於處理傳入的請求來跟蹤分析節點的API,該請求數據發佈到兔隊列,然後返回一個響應。如果請求進入,並且由於某種原因,請求需要超過30秒的時間才能處理,它將超時並向客戶端發送錯誤響應。此時,客戶將嘗試再次進行相同的呼叫(因此我們不會丟失分析數據)。
但是,由於請求本身和發佈給rabbit的調用之間沒有任何聯繫(除了它是發起發佈請求的事實),因此無法停止發佈該數據。因此,如果兔子服務器最終完成處理髮布請求,現在將會有重複數據,因爲客戶端現在已經發出了2個(或更多)請求。
停止完成發佈的初始請求的唯一方法是在請求超時時銷燬兔子連接。這樣,初始發佈將停止,客戶端的重試請求將不會重複。但是,對於在整個請求中進行的任何異步調用,都需要執行相同類型的手動銷燬連接。如果在超時發生時我有5個優秀的異步調用,我將需要銷燬所有5個異步連接(無論它們是否連接到rabbit,mysql,mongo等)。
然而,問題超出了請求超時時已經建立的連接。即使請求在發佈到rabbit之前超時,被調用來處理該請求的函數已經被執行,並且不會停止,除非在各個位置檢查了是否超時並返回請求立即。
您可以將兔子連接存儲在帶有id的全局對象(可以是客戶端ip或cookie值或任何其他),並且可以在下一個請求中檢索此連接。此外,您可以將兔子連接存儲在插槽本身上,並聽取「關閉」,並在發生這種情況時殺死兔子連接。殺死意味着調用'關閉'或設置一個標誌,以便在你自己的代碼中保存。第一種選擇是,您可以通過某個id將多個套接字/ http連接匯聚到單個服務器的「連接」。 – DDS
@DDS現在我將兔子連接附加到請求上,然後在超時時關閉連接。但是,我希望有一個更通用的解決方案,它包含停止處理整個請求流的能力。現在我想不出一種好的方法,除非我向節點中引入與節點完全相反的東西(爲每個傳入請求創建一個新進程)或冗餘/冗長(在每次異步調用之前添加一個檢查以查看請求已超時)。這兩種方法都不太直觀。 – Sarah
如果您使用節點0.11.x,則可以使用基於生成器的函數([gen-run](https:// github。com/creationix/gen-run),[suspend](https://github.com/jmar777/suspend)),並且您可以修改它以在您要中止函數時將異常拋入生成器函數,並結合忽略原來的下一個回調。然後你有權力在一個'運行函數'上進行真正的「中止」調用(當然這實際上是暫停的)。實質上,這將在每次回調調用後進行檢查,並將「釋放」一直推到函數出口(除非您捕獲並忽略錯誤)。 – DDS