【问题标题】:SignalR disconnects and does not reconnectSignalR 断开连接且不重新连接
【发布时间】:2017-01-12 19:42:28
【问题描述】:

每当我的应用程序重置时,signalR 就会断开连接但不会重新连接。

我有一个长时间运行的服务器任务,它会在每个任务完成时向客户端发送更新。

// inside action executed on every completion of a task
var h = new ForceHub();
h.MessageSent(email);

当应用程序被重置时,上面的代码停止发送更新(我可以通过触摸 web.config 来模拟这个问题)。

我想要一种重新连接到客户端的方法。目前,用户必须重新加载页面才能再次获得更新。

这是我的集线器定义

public class ForceHub : Hub
{
    public void MessageSent(string text)
    {
        GetContext().Clients.All.sent(text);
    }

    public void UpdateStatus(string msg)
    {
        GetContext().Clients.All.status(msg);
    }

    IHubContext GetContext()
    {
        return GlobalHost.ConnectionManager.GetHubContext<ForceHub>();
    }
    public override Task OnConnected()
    {
        try {
            IoC.Resolve<ILogger>().Info("SignalR Connected -----------");
        }catch (Exception){}

        return base.OnConnected();
    }

    public override Task OnDisconnected()
    {
        try {
            IoC.Resolve<ILogger>().Info("SignalR Disconnected -----------");
        }
        catch (Exception) { }
        return base.OnDisconnected();
    }

    public override Task OnReconnected()
    {
        try {
            IoC.Resolve<ILogger>().Info("SignalR Re-Connected -----------");
        }
        catch (Exception) { }
        return base.OnReconnected();
    }
}

我可以看到启动后触发了 ConnectedRe-Connected 事件,但是在触摸 web.config 之后,我没有看到任何这些事件被触发。

我尝试在客户端捕获此事件,但未触发此事件:

$.connection.hub.disconnected(function () {
    console.error('signalR disconnected, retrying connection');
    logError('Signal lost.');
    setTimeout(function () { connection.start(); }, 1000);
});

更新

我还挂钩了 State Changed 事件,该事件确实被触发,但下面的重新连接尝试不起作用。

        $.connection.hub.stateChanged(function (state) {
            console.debug('signalR state changed', state);
            if (state.newState == 1) {
                console.debug('restarting');
                setTimeout(function () { $.connection.hub.start(); }, 1000);
            }
        });

这个事件被触发两次:newState 是 2,然后是 1。

【问题讨论】:

  • 这看起来是一个有趣的案例,我试图重现它,但我无法做到。我没有尝试长时间运行的任务,而是使用一个简单的附加页面,其背后的代码在 GET 命中时向所有客户端发送消息。这模拟了“带外”工作,即使在应用程序重置后它也能正常工作,客户端会正常收到通知。我会说 SignalR 不会失去连接(这就是为什么你看不到事件)......也许问题出在其他地方?
  • @Wasp 你试过修改 web.config 吗?
  • 当然,我在对“工作”页面的请求之间这样做
  • 好的,感谢您的尝试。我现在将发布更多调试代码。也许这对你更有意义
  • 仅供参考,我添加了您的进一步事件处理程序之后所有连接的客户端。这与 SignalR 应该做的一致(处于“重新连接”状态并不意味着发生“断开连接”)。

标签: signalr signalr-hub


【解决方案1】:

我可能有一个线索...触摸 Web.config 会产生一个 appPool Recycle,这意味着将为新请求创建一个新的工作进程,而现有进程将持续一段时间,直到剩余的请求结束或超时到达了。未在超时期限内结束的请求将被终止。

当长时间运行的任务在旧进程中运行时,Signalr 客户端重新连接到新进程,所以当你在长时间运行的任务上时这样做

GlobalHost.ConnectionManager.GetHubContext<ForceHub>(); 

当客户端连接到“新”集线器时,您实际上会获得“旧”集线器的引用。 这就是为什么由 Wasp 执行的测试有效的原因:他正在发出一个新请求以在新创建的工作进程中处理的信号器集线器上发布。

您可以尝试配置一个单一的背板 (https://www.asp.net/signalr/overview/performance/scaleout-in-signalr),使用 Sql Server (https://www.asp.net/signalr/overview/performance/scaleout-with-sql-server) 配置它真的很容易。背板应该能够连接两个工作进程,希望您能在客户端收到通知。

如果这是问题所在,即使没有背板,新请求生成的通知也会起作用。请注意,背板的真正目的是横向扩展信号器,即在它们之间连接一组 WebServer。

另外请记住,在 IIS 中运行长时间运行的任务很难实现,因为 IIS 会定期执行 appPool 回收,并且对执行请求有超时限制。我建议您阅读以下帖子:http://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx “如果你认为你可以自己编写一个后台任务,那么你很可能会弄错。我不是在指责你的技能,我只是说它很微妙。另外,你为什么必须这样做?”

希望对你有帮助

【讨论】:

  • 这听起来很对 :) 好几年没碰过那个代码了。我同意 IIS 中长时间运行的任务并不理想。我能够将执行时间缩短到 1-30 分钟,这仍然很长,但在过去几年中一直在可控范围内。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-12
  • 1970-01-01
  • 1970-01-01
  • 2017-07-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多