自 Chrome 88 以来的 SignalR 和/或计时器问题

Ken*_*enD 13 javascript google-chrome timer signalr

我们有一个 ASP.Net WebForms 应用程序,它使用 SignalR (v2.4.1) 在服务器和客户端之间进行一些双向通信。多年来一直运行良好:连接稳定,数百名用户使用它,等等。

但是,我们已经开始从我们的客户群中收到有关连接问题的零星报告,所有报告都报告相同的事情:如果浏览器 (Chrome) 会话闲置超过 5 分钟,则连接在后台断开。页面中的所有计时器都停止定期运行,这(除其他外)停止发送“keepalive”,最终连接失败并出现客户端错误:

The client has been inactive since <date> and it has exceeded the inactivity timeout of 50000 ms. Stopping the connection.
Run Code Online (Sandbox Code Playgroud)

此后的标准程序是自动重新启动连接,但这不会做任何事情。如果/当用户重新激活页面(例如通过切换到选项卡),一切都开始恢复活力,尽管 SignalR 连接已关闭。

经过大量调查,我们似乎受到了Chrome v88 中引入的这一更改的影响,其中计时器 ( setTimeouts) 受到严格限制,如果

  • 该页面已隐藏超过 5 分钟
  • 计时器已经“链接”了 5 次或更多次 - 我假设这类似于递归,计时器调用自身。
  • 页面已经“沉默”了 30 秒

5 分钟/30 秒的条件与我们得到的报告相符。然而,我们在我们的页面上运行非常基本的 Javascript:setTimeout在我们自己的代码中只有两种用法,它们都不能“链接”(递归)到自己身上。我们也不能复制的问题:这是发生在我们的测试,但我们不能这发生可靠。通过禁用此功能chrome://flags/#intensive-wake-up-throttling似乎可以缓解该问题 - 但当然,我们不能将其作为使用我们网站的要求。

该站点上唯一运行的其他 Javascript 是jquery.signalR-2.4.1.js,并且从 SignalR 源代码中可以看出,其中有很多setTimeouts。SignalR 是否会受到 Chrome 中这一变化的影响;也许是在临时网络问题或其他一些不可预测的事件后尝试以静默方式重新连接时?

如果没有,是否有任何方法可以在任何浏览器或 IDE 中跟踪哪些计时器已启动(更重要的是,“链接”),以便我们了解可能触发此限制的原因?

Cor*_*ina 8

我们也面临着我们的 signalR(WebSockets 作为传输)的问题。我们无法在实验室中重现它。我们客户的 HAR 文件和扩展日志仅向我们提供了以下信息:客户端“仅在关注感兴趣的组后才消费”在保持连接所需的默认 30 秒内未发送 ping。因此服务器关闭连接。我们在 signalR 客户端库中添加了日志,只看到 ping 计时器没有按时命中。没有错误,没有什么。(客户端是 JavaScript,问题发生在 chrome 87 的客户站点上(已经为一半的 chrome 用户实施了节流 - https://support.google.com/chrome/a/answer/7679408#87))

世界正在慢慢意识到“一个问题”:https : //github.com/SignalR/SignalR/issues/4536

我们为客户提供的快速帮助是从服务器站点创建一个具有手动广播乒乓机制的 ET,每个客户都必须回答。在提供“更好”的解决方案或修复程序之前,避免依赖于 signalR 库中的 JavaScript ping。

  • 经过两天在客户现场的测试,我们的额外心跳机制解决方案似乎解决了该问题。我们已经实现了一个BackgroundService并注入了我们的signalR hub,我们在其中调用“await hub.Clients.All.SendAsync("Heartbeat",stoppingToken);” insde ExecuteAsync 方法 - 参考backgroundServices:https://docs.microsoft.com/en-us/aspnet/core/signalr/background-services?view=aspnetcore-3.1 在前端,我们简单地通过连接实现了该方法和响应.invoke("AckHeartbeat") 转到服务器中心中的一个空方法以保持活动状态。 (2认同)
  • 服务器每 20 秒通过 Hub 发送一次心跳。客户端从服务器接收心跳作为消息,立即触发客户端方法,通过 connection.invoke("Ackheartbeat") 将消息返回到服务器。这使得服务器站点负责间隔,而客户端只需对其定期接收的事件做出反应。由于间隔逻辑在服务器站点,因此chrome的限制不会生效。 (2认同)