High cpu usage when admin.shutDown

Mar 21, 2014 at 7:28 PM
Edited Mar 21, 2014 at 8:11 PM
I don't know if it's my application or the library, but when I submit a admin.shutDown command, the cpu usage goes up by a lot.

I already went through a lot of code in my app and everything seems fine. Any clues?

It only does this when the submited command is admin.shutDown. Restarting, changing map, etc, they all work fine and the cpu usage is normal.
Mar 21, 2014 at 9:58 PM
Fixed it.

It just came to my mind to use cliend.Disconnect() after the shutdown command. The high cpu usage is gone.

However I'm having trouble logging in again after a shutdown. I need to investigate this with more time.
Coordinator
Mar 21, 2014 at 11:43 PM
I'm glad you found a workaround! Since disconnecting right after works, I guess it's a connection problem, which narrows things down. Since I don't have a server to shutdown randomly (or any at all :D), it might be hard to reproduce, debug, and fix, but I'll mess around with it to try to find the source.

As for logging in, are you using IRconClient.LogOn with the latest source? If you are, then I assume the fix for an old bug worked! As for the problem at hand, does it perhaps hang on the call to LogOn? Or does it return false or throw an exception?

If it does hang, I would guess it's another connection-related problem. The method uses synchronous calls that block indefinitely, which can be problematic. Are you able to send any requests yourself, like for a normal listPlayers?

Again, if it is indeed blocking, then I've got a temp workaround. You'll need to create a new connection, client, or both each time you want to connect.

In the mean time, I'll get to work on debugging :D
Mar 22, 2014 at 12:44 AM
About the logging problem, it was from my code :) I was having some issues with threads and I was sending a request without connecting first.

Yes I noticed that some time ago. I create a new connection and client each time the user or the app wants to connect.

Off-topic: do you have twitter? If you have and if your username is Timiz0r, it was me who said "Hello" :)
Mar 22, 2014 at 2:11 AM
Edited Mar 23, 2014 at 2:09 AM
Nevermind, I'm still having issues, but after the log in part.
Sometimes it works, sometimes it doesn't. I don't know why. It seems random.

So basically I'm running a timer (System.Threading.Timer) that checks for a server connection every 10 seconds. If the connection is lost, he keeps searching for a connection untill there is one. Finally when he finds one:
  • a new connection and client are created;
  • log in process is executed (I'm not using LogOn at the moment, I'm sending requests);
  • some requests are sent to the server to retrieve info (all with async/await);
  • the method that listens to server events is fired (it's the same as the one in the documentation)
The problem with this is that sometimes it works, sometimes it just hangs. No exceptions at all. I don't know where to look :/

Edit: I tried to comment some lines of code, mainly the ones after the login process, the requests and the listener. It looks like this now:
  • a new connection and client are created;
  • log in process is executed (I'm not using LogOn at the moment, I'm sending requests);
The success rate is much higher. So far it's 100%. So the problem is after this, when I make requests to retrieve info and when the listener is called. Any clue about what could be the problem?

Edit2: after all the application doesn't stop. It's the gui who stops responding. I still can't find the source of the problem.

Edit3: I believe it's my code. I noticed the gui stops responding when I call a method using Dispatcher.Invoke. The funny thing is that this works from time to time.

Edit4: Found it. My timer and Dispatcher.Invoke don't like each other sometimes. I'm going to use a different timer.
Coordinator
Mar 23, 2014 at 10:04 PM
Sorry for the late reply. I was having trouble finding a random server to test with since the remote admin interface ports aren't public. Using a sort of server emulator, I wasn't able to find anything, though I guess you found a problem in your program anyway. Just wanted to make sure! I'll also keep doing a little more investigating to make sure nothing is up.

If you're using async/await in the timer, than that can sometimes be a problem. In my case, anyway, I had to do some fancy tricks in the library to get async/await on a different thread to stop deadlocking.

If appropriate, I would recommend using a DispatcherTimer. You'll be able to eliminate all use of the Dispatcher, which will make your code more maintainable.

If you do indeed need a separate thread, you might consider not using async/await. Since you're presumably offloading some work on the timer's thread, you don't really have much to gain from awaiting there anyway.

Also of note is that much of the library supports timeout values and CancellationTokens. You might find it more desirable to use these features just to be safe.

Oh and the library handles mid-request disconnections, btw (just in case it comes up :D).
Mar 23, 2014 at 11:07 PM
Edited Mar 23, 2014 at 11:09 PM
Thanks for the tips! :D

I would let you use my server if I had one but I don't :/ The one I'm using is not mine.

In this timer, that I have been speaking, I need to update some UI elements. Which timer do you recommend?

Can you provide a example usage of timeout/cancellationTokens? And what you mean by mid-request disconnections? Disconnection while sending a request?
Coordinator
Mar 24, 2014 at 2:48 PM
Edited Mar 24, 2014 at 2:51 PM
Like I said, I would recommend using DispatcherTimer if appropriate. This timer will execute each tick on the UI thread. It should work well if you use async/await on each tick. However, it may work more poorly if using synchronous methods there.

One example of using a timeout can be seen with RconClient.SendRequest.
RconClient client = ...;

try
{
    var result = client.SendRequest(1000 /* ms, or supply a TimeSpan */, "admin.listPlayers);
}
catch (TimeoutException ex)
{
    //...
}
Or with CancellationToken...
RconClient client = ...;
CancellationTokenSource cts = new CancellationTokenSource();

try
{
    var result = await client.SendRequestAsync(cts.Token, "admin.listPlayers");
}
catch (TaskCanceledException ex)
{
    //...
}

// somewhere in another thread or something
cts.Cancel();
Regarding disconnections during requests, what I mean is that requests won't get stuck when a disconnection occurs mid-request. Usually (or maybe always idk), a DisconnectionException will be thrown when this happens, usually (always?) with its InnerException populated with the original Socket/IOException.
Mar 24, 2014 at 5:47 PM
Yes you are right about disconnections. It throws a exception.

Thanks for the examples.