關於 Angular SSR 應用在渲染中止時如何避免記憶體洩漏問題的一些嘗試

注销發表於2022-05-19

當某些非同步任務永遠掛起時,SSR 渲染可能永遠不會完成,例如http 呼叫後端 API。在 Angular Universal 中,預設情況下無法中止掛起的渲染。那麼渲染的資源沒有釋放,會導致記憶體洩漏。當記憶體洩漏重複時,這可能最終導致伺服器由於記憶體不足而重新啟動。

我們已經採取了一些措施來改善渲染掛起時的監控體驗 - 我們新增了配置 SsrOptimizationOptions.maxRenderTime。在 maxRenderTime 之後,我們將這種情況新增到日誌裡,渲染需要很長時間,它可能會掛起,但我們除了記錄日誌外,對這種請求沒有其他的干預方式。

理想情況下,我們應該儘可能避免懸掛渲染。從理論上講,最好調查一下 SSR 中處於掛起狀態的非同步操作的最常見原因。然後嘗試避免這種情況發生。

是否存在與 Angular Universal 不同的 SSR 的替代方法,能夠允許以程式設計方式中止掛起的渲染程序,並釋放分配的資源?

我們也可以使用這個攔截器來記錄超時請求。但我們需要小心,僅將其用於除錯目的,以找到問題的證據。激進的日誌記錄(尤其是在透過 console.log/error 與輸出流同步完成時)可能會降低 Node Express 應用程式的效能。

如果我們還想透過使用 rxjs 運算子 timeout() 來終止攔截器中長期掛起的 API 呼叫,那麼 rxjs 流將發出錯誤,此時需要在 Angular 應用中進行相應的錯誤處理。

此外,我們希望避免在 SSR 響應中返回格式錯誤的 HTML. 可能有多種方法可以將渲染標記為格式錯誤。不管標記技術如何,在 SSR 層(ExpressJS 應用程式)中,我們需要識別格式錯誤的渲染標記,然後傳送一個 CSR index.html(所謂的 CSR 回退,帶有無快取 http 標頭)而不是傳送呈現的 HTML.

以下是一些可能的方法來將渲染結果標記為格式錯誤:

(1) 呼叫一些 Angular API 來終止應用程式的掛起渲染並返回一個可能被平臺伺服器和 ngExpressEngine 捕獲的錯誤。

理想情況下,這種型別的 Angular API 還應該安全地拆除待處理的渲染(銷燬允許釋放資源的元件、服務和模組)。需要從 Angular Universal 的文件及其原始碼裡確認是否真的有這種型別的 API 存在。

(2) 讓渲染完成,在 Angular 應用程式中將渲染結果標記為格式錯誤,因此我們稍後可以在 SSR(Express js 應用程式)的層中決定忽略此 html 並回退到 CSR。

Angular 應用程式可以透過 2 種方式在 SSR 層留下標記以供以後識別:

a. 在頁面的 head 中新增一些特殊的標記 html 元素,例如 <meta> 標記。然後要在 SSR 層識別它,我們需要對原始呈現的 html 字串執行正規表示式。

b. 在 RESPONSE 物件中設定一些特殊的標記屬性(可以在 Angular APP 中注入,最好使用裝飾器 @Optional() 以避免 CSR 中的錯​​誤。

可以從 @nguniversal/express-engine/tokens' 匯入 RESPONSE。

然後,可能在 2 個潛在的地方,我們可以擷取渲染結果,識別標記並在響應中傳送 CSR 回退:

a. 在 OptimizedSsrEngine 內部,在我們獲得原始 html 之後,但在將其傳遞給響應回撥 (callback(err, html)) 之前。或者

b. 編寫一個自定義的、獨立的 Express.js 中介軟體並透過 app.use(myMiddleware) 將其插入 server.ts

相關文章