关于 Angular SSR 应用在渲染中止时如何避免内存泄漏问题的一些尝试
当某些异步任务永远挂起时,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 元素,例如 标记。然后要在 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