Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebSocketClient's KeepAliveInterval can't be disabled. #60

Closed
Nyatra opened this issue May 22, 2016 · 9 comments
Closed

WebSocketClient's KeepAliveInterval can't be disabled. #60

Nyatra opened this issue May 22, 2016 · 9 comments

Comments

@Nyatra
Copy link

Nyatra commented May 22, 2016

In console window (OnLogMessage from DiscordBot):
[Gateway] Disconnected: Received close code 4002: Error while decoding payload.

In Visual Studio output window:

Exception thrown: 'Discord.Net.WebSocketException' in Discord.Net.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in mscorlib.ni.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in mscorlib.ni.dll
Exception thrown: 'Discord.Net.WebSocketException' in mscorlib.ni.dll

This occurs every 32.5 seconds when there is absolutely no activity in connected channels.
With activity, this does not occur.

After disconnecting, Discord.Net reconnects and, if there is still no activity, it disconnects again after 32.5 seconds.

Guessing it has something to do with the heartbeat.

Using .Net Core RC2. Latest master branch from GitHub.

project.json:

{
    "version": "1.0.0-*",
    "buildOptions": {
        "emitEntryPoint": true
    },

    "dependencies": {
        "Newtonsoft.Json": "8.0.4-beta1",
        "Discord.Net": "0.9.2"
    },

    "frameworks": {
        "netstandard1.5": {
            "imports": [
                "portable-net451+win81"
            ]
        }
    },

    "runtimes": {
        "win81-x64": { }
    }
}

Program.cs:

using System;
using System.Text;
using Discord;

namespace InactivityIssue
{
    public class Program
    {
        public static void Main(string[] args) => new Program().Start();

        private DiscordClient _client;

        public void Start()
        {
            _client = new DiscordClient(x =>
            {
                x.LogLevel = LogSeverity.Debug;
                x.LogHandler = OnLogMessage;
            });

            _client.ExecuteAndWait(async () =>
            {
                await _client.Connect("BOTTOKEN");
            });
        }

        private void OnLogMessage(object sender, LogMessageEventArgs e)
        {
            //Color
            ConsoleColor color;
            switch (e.Severity)
            {
                case LogSeverity.Error: color = ConsoleColor.Red; break;
                case LogSeverity.Warning: color = ConsoleColor.Yellow; break;
                case LogSeverity.Info: color = ConsoleColor.White; break;
                case LogSeverity.Verbose: color = ConsoleColor.Gray; break;
                case LogSeverity.Debug: default: color = ConsoleColor.DarkGray; break;
            }

            //Exception
            string exMessage;
            Exception ex = e.Exception;
            if (ex != null)
            {
                while (ex is AggregateException && ex.InnerException != null)
                    ex = ex.InnerException;
                exMessage = ex.Message;
            }
            else
                exMessage = null;

            //Source
            string sourceName = e.Source?.ToString();

            //Text
            string text;
            if (e.Message == null)
            {
                text = exMessage ?? "";
                exMessage = null;
            }
            else
                text = e.Message;

            //Build message
            StringBuilder builder = new StringBuilder(text.Length + (sourceName?.Length ?? 0) + (exMessage?.Length ?? 0) + 5);
            if (sourceName != null)
            {
                builder.Append('[');
                builder.Append(sourceName);
                builder.Append("] ");
            }
            for (int i = 0; i < text.Length; i++)
            {
                //Strip control chars
                char c = text[i];
                if (!char.IsControl(c))
                    builder.Append(c);
            }
            if (exMessage != null)
            {
                builder.Append(": ");
                builder.Append(exMessage);
            }

            text = builder.ToString();
            Console.ForegroundColor = color;
            Console.WriteLine(text);
        }
    }
}
@Auralytical
Copy link
Collaborator

Auralytical commented May 22, 2016

If this is running on a Linux/OSX box, be sure to add the Discord gateway cert:
certmgr -ssl https://gateway.discord.gg

@foxbot
Copy link
Member

foxbot commented May 22, 2016

Unable to Reproduce;

Copied your project.json, Program.cs
Using Discord.Net 0.9.2 from NuGet.
dotnet 1.0.0-preview1-002702

@Nyatra
Copy link
Author

Nyatra commented May 23, 2016

I'm using:

  • Windows 10 Pro 64bit
  • Visual Studio 2015 Community
  • 1.0.0-preview1-002702
  • Latest version of Discord.net from the master branch on GitHub

I've attached the project with the issue. InactivityIssue.zip

Folder structure:
YourProjectsFolder\Discord.Net\src\Discord.Net
YourProjectsFolder\InactivityIssue\

I get the same issue when I dotnet publish -c Release and run it on a remote Windows Server 2012.

@Auralytical
Copy link
Collaborator

Thanks, I was able to reproduce with your project, looking into it.

@Auralytical
Copy link
Collaborator

Auralytical commented May 23, 2016

This appears to be tied to WebSocketClient's built-in KeepAliveInterval, which runs every 30 seconds of no activity.

I tried disabling it on my end, but if you look at https://github.com/dotnet/corefx/blob/master/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocketOptions.cs#L131 - I don't see this option being used anywhere.

EDIT: Found an issue for this: https://github.com/dotnet/corefx/issues/5116

@Auralytical Auralytical changed the title [Gateway] Disconnected: Received close code 4002: Error while decoding payload. WebSocketClient's KeepAliveInterval can't be disabled. Jun 1, 2016
@Auralytical Auralytical added this to the 1.1 milestone Jun 1, 2016
@Xeevis
Copy link

Xeevis commented Jul 15, 2016

This can be really frustrating issue as bot on low traffic guilds is coming on/off all the time missing commands and events. I've managed to over come this by deploying to docker on Synology NAS (any Linux environment should work), where it works flawlessly.

Since stable release of WebSockets.Client doesn't support unix yet, it's necessary to download latest beta version from https://dotnet.myget.org/feed/dotnet-core/package/nuget/System.Net.WebSockets.Client

Or bump Discord.Net/projects.json dependency to

"System.Net.WebSockets.Client": "4.0.1-beta*",

(this requires adding MyGet into NuGet package sources)

https://dotnet.myget.org/F/dotnet-core/api/v3/index.json

@Nyatra
Copy link
Author

Nyatra commented Jul 17, 2016

The way I worked around the issue on Windows for now, is by setting the global Keep-alive Interval in the registry to something really large.

HKLM:\Software\Microsoft\WebSocket\KeepaliveInterval

It's should be a DWORD, if it does not exist already.

This will affect anything that uses the global setting and does not have it's own setting. (All .NET Core WebSockets currently)

I found this in an msdn page:

WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL

Sets the interval, in milliseconds, to send a keep-alive packet over the connection. The default interval is 30000 (30 seconds). The minimum interval is 15000 (15 seconds). Using WinHttpSetOption to set a value lower than 15000 will return with ERROR_INVALID_PARAMETER.

Note The default value for WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL is read from HKLM:\SOFTWARE\Microsoft\WebSocket\KeepaliveInterval. If a value is not set, the default value of 30000 will be used. It is not possible to have a lower keepalive interval than 15000 milliseconds.

@Auralytical Auralytical modified the milestones: Future, 1.1 Jul 19, 2016
@Auralytical
Copy link
Collaborator

I've talked to Discord about this, and they're going to fix this sometime on their end, adding support for keepalive packets. @jhgg

@Auralytical
Copy link
Collaborator

This fix is live.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants