Azure Web作业和SignalR内存泄漏

时间:2016-11-16 03:58:55

标签: iis signalr azure-webjobs azure-webjobssdk

所以我有一些偶尔连接到信号中心并播放消息的webjobs。下面只是一个示例,在这种情况下,它是一个用于开发的简单Web作业,其TimerTrigger属性设置为每20秒连续运行一次。如下面的代码所示。

    public static void Main()
    {

        JobHostConfiguration config = new JobHostConfiguration();
        config.Tracing.ConsoleLevel = TraceLevel.Verbose;
        config.UseTimers();
        if (config.IsDevelopment)
        {
            config.UseDevelopmentSettings();
        }
        var host = new JobHost(config);
        host.RunAndBlock();
    }

    public static void ProcessPush([TimerTrigger("00:00:20", RunOnStartup = true)] TimerInfo timerInfo, TextWriter log)
    {
        // Send a signalr message to the Hub
        try
        {            
            SendMessageToHub(log);
        }
        catch (Exception e)
        {
            log.WriteLine($"WebJob Push Exception: {e.Message}");
        }
    }

    private static async Task SendMessageToHub(TextWriter log)
    {
            var hub = new HubConnection(CloudConfigurationManager.GetSetting("MyWebSite"));
            var proxy = _hub.CreateHubProxy("MyHub");

            log.WriteLine("WebJob Push: Sending message to SignalR Hub.");
            if (_hub.State == Microsoft.AspNet.SignalR.Client.ConnectionState.Disconnected)
            {
                await _hub.Start();
            }
            await _proxy.Invoke("BroadcastMessage");
            log.WriteLine("WebJob Push: Sent message to SignalR Hub.");
    }

托管网站和信号中心的服务器上的内存总是有增量。在调查网站上的IIS日志时,似乎有大量/批次的POST消息在同一秒内使用长轮询进入网站。然后它会等待一段时间然后被另一批消息轰炸。顺便说一下,这也会使IIS服务器上的CPU变得疯狂。在这篇文章的底部是IIS日志条目的一个例子。

我希望能够以一致的方式通过常规脉冲消息从Web作业发送信号器消息(我们希望扩展Web作业 - 请原谅它现在在计时器上运行的事实)

亲切的问候,

的Stefan

示例IIS日志条目 - 注意它们都在同一秒内进入,而不是相隔20秒:

二○一六年十一月一十五日23点10分35秒POST / signalr /轮询clientProtocol = 1.4&安培;运输= longPolling&安培; connectionData = [%7B%22Name%22:%22MyHub%22%7D]安培; connectionToken = TBbNVDpndk0riu8UvVzbGJrWjYIo7eMLcP4lk7ABV74OBMbZRTJrCRL1bzsPxpd1Tyle2rS3tV2JJrigninhu880ml51Xers76PPDX0Hf97dTBYR4k% 2BVc2V9KAmiGt0p& messageId = d-80E0087-B%2C7D%7CEz%2C0%7CE0%2C0 443 - 104.210.116.149 SignalR.Client.NET45 / 2.2.1.0 +(Microsoft + Windows + NT + 6.2.9200.0) - 200 0 0 5343

2016-11-15 23:10:35 POST / signalr / poll clientProtocol = 1.4& transport = longPolling& connectionData = [%7B%22Name%22:%22MyHub%22%7D]& connectionToken = KYwQXpNrPIU21NXMa0So5u42EwXTcMlGyLqL3tetx4WfOtTunHLclG% 2BhPd%2BcPeZPmfe6KKvQL13XIU1W5fApuTv0XN5XFPoNUmyBjhhISoqodwcZeu3QKmkbaXcpHMtE& messageId = d-80E0087-B%2C7D%7Cav%2C0%7Caw%2C2 443 - 104.210.116.149 SignalR.Client.NET45 / 2.2.1.0 +(Microsoft + Windows + NT + 6.2.9200.0) - 200 0 0 10641

2016-11-15 23:10:35 POST / signalr / poll clientProtocol = 1.4& transport = longPolling& connectionData = [%7B%22Name%22:%22MyHub%22%7D]& connectionToken = nO% 2BPZ8M5JJOpiobpJUV5%2FZvQyEKYjp%2FOuqQ%2F0Bkq05TKRJZfeI%2FD%2BxRyPC7EsAAjXVqJr05PksorlMWrXocGkskfVsLU2Qvtx%2Fi1O8hU5lNz4KcoSc%2Bkv%2BlDpr2AZBLv&安培; MESSAGEID = d-80E0087-B%2C7D%7CFB%2C0%7CFC%2C0 443 - 104.210.116.149 SignalR.Client.NET45 / 2.2.1.0 + (Microsoft + Windows + NT + 6.2.9200.0) - 200 0 0 18282

2016-11-15 23:10:35 POST / signalr / poll clientProtocol = 1.4& transport = longPolling& connectionData = [%7B%22Name%22:%22MyHub%22%7D]& connectionToken = wiGSRiNHdd7crhkcAMd% %2FWy%2F3qGRZ5WdBm%2BdbR3b7aTbtpB8aaBGDil%2FqAWha6Si5eEohsUmCxAU4Pkefy及2BNoxoG9fgYC4R66ErXIShyBUcsNLWo1AyH5zGDk7bFvme3E放大器; MESSAGEID = d-80E0087-B%%2C7D%7CE9%2C0%7CE_ 443 2C0 - 104.210.116.149 SignalR.Client.NET45 / 2.2.1.0 +(微软的Windows + NT + + 6.2 .9200.0) - 200 0 0 11360

2016-11-15 23:10:35 POST / signalr / poll clientProtocol = 1.4& transport = longPolling& connectionData = [%7B%22Name%22:%22MyHub%22%7D]& connectionToken = hEJ1b0% 2Bz2eeyC8IvYmOV3ffZ%2FAFQiQpEnJLUmCZTEVDLwcgOqhyQbQnu0R29sazp6BxcK4WsDhSbEdg2Sh4wMBSZjQtKMzASr2Fa2eY2HGgoVJcfDOMixQX2FCqfa%2BmP&安培; MESSAGEID = d-80E0087-B%2C7D%7CFD%2C0%7CFE%2C0 443 - 104.210.116.149 SignalR.Client.NET45 / 2.2.1.0 +(微软的Windows + + NT + 6.2.9200.0) - 200 0 0 15798

2016-11-15 23:10:35 POST / signalr / poll clientProtocol = 1.4& transport = longPolling& connectionData = [%7B%22Name%22:%22MyHub%22%7D]& connectionToken = 2UsU63IHgaNO% 2BBYmoamsKxFq7Vv3uaGigvR1NrGnntVnAbTg2C0%2BVXZnA9aT8siqpkBv%2Fo8avvvNTSBfQD77IspaO6jOnSU8rXMXDU2Vr6ojkWr%2Fwt1LFsdNy3%2BHpDGC&安培; MESSAGEID = d-80E0087-B%2C7D%7CEv%2C0%7CEw%2C0 443 - 104.210.116.149 SignalR.Client.NET45 / 2.2.1.0 +(微软的Windows + + NT + 6.2 .9200.0) - 200 0 0 11844

等等

更新 - 显式停止集线器连接似乎已经处理了孤立客户端(或同一个Web作业客户端的多余客户端)。特别是,添加_hub.Stop();在调用代理之后。

1 个答案:

答案 0 :(得分:2)

对于某些人来说,这听起来很明显,但答案是确保我们在向其发送消息后停止集线器连接。下面是注释包含附加行的代码。

似乎与浏览器客户端不同,客户端在一段时间不活动后会断开连接。 webjob客户端坚持不懈,并继续浏览网站。因此,每次触发webjob时(通过计时器或通过读取天蓝色队列或主题的消息),它都会不断产生新客户端并保留该连接。

在webjob中,你必须明确地停止连接,否则内存和CPU将逐渐变成坚果袋。

private static async Task SendMessageToHub(TextWriter log)
{
        var hub = new HubConnection(CloudConfigurationManager.GetSetting("MyWebSite"));
        var proxy = _hub.CreateHubProxy("MyHub");

        log.WriteLine("WebJob Push: Sending message to SignalR Hub.");
        if (_hub.State == Microsoft.AspNet.SignalR.Client.ConnectionState.Disconnected)
        {
            await _hub.Start();
        }
        await _proxy.Invoke("BroadcastMessage");
        /////////////////////////////////////////////////////////////
        // Stopping the hub connection is necesssary in a web job  //
        _hub.Stop();   
        /////////////////////////////////////////////////////////////
        log.WriteLine("WebJob Push: Sent message to SignalR Hub.");
}