1

Not a duplicate. The code directly below also hangs and causes the console to wait for input 'randomly' - Bigger underlying issue somewhere.

int i = 0;
while (true)
{
    Console.WriteLine(++i);
    System.Threading.Thread.Sleep(3000);
}

So i have the strangest bug and nothing online seems to ever have this. I recently moved my task scheduler to a different server (Windows server 2016 standard) and since the move the app seems to randomly hang on the Task.Delay line and never execute past it.

It will simply say 'Check completed next run at 09:31' for example, then never execute again.

Interestingly pressing enter into the console window seems to trigger it to execute, however then every time it hangs on the sleep until the application is closed and re-opened.

It can go many days without experiencing this issue, then it will seemingly randomly crop up.

I've tried with Thread.Sleep instead of Task.Delay and both experience the same issue. I also added a check to see if possibly the Directory.Exists command was causing it to hang, so stored the directories in memory instead.

I have no idea what could be causing this - I've never experienced anything like it before. Any ideas?

Code is below - however will be impossible to replicate id imagine due to the weird nature of the bug

TLDR: Windows server 2016 console application hangs on Task.Delay (and Thread.Sleep) until key push on console window

        // This is the main execution loop
            while (true)
        {
            Task run = checkDirectoriesForAppsToRun();
            run.Wait();
        }

       static async Task checkDirectoriesForAppsToRun()
    {
        Console.WriteLine("Starting apps...");
        foreach (string subFolder in listOfSubfolders)
        {
            if (directoryExists.ContainsKey(currentDirectory + @"\" + subFolder) || System.IO.Directory.Exists(currentDirectory + @"\" + subFolder)) // Only if the sub directory exists!
            {
                if (directoryExists.ContainsKey(currentDirectory + @"\" + subFolder) == false)
                    directoryExists.Add(currentDirectory + @"\" + subFolder, true);
                foreach (string directory in System.IO.Directory.GetDirectories(currentDirectory + @"\" + subFolder))
                {
                    CheckDirectoryForApp(directory); // Load the apps xml file, and check if we need to run it.
                }
            }
            else
            {
                Console.WriteLine(subFolder + " Doesn't exist in the root directory - Please check");
            }
        }
        Console.WriteLine("Check completed next run at " + DateTime.Now.Add(timeToPause).ToShortTimeString());
        await Task.Delay(timeToPause);
    }
Jeax
  • 47
  • 7
  • You seem to be blocking on an async Task `run.Wait();`. This I'd imagine, it's hard to be 100% clear without more context, is causing a deadlock situation. – Liam Sep 07 '18 at 08:49
  • Possible duplicate of [How to call asynchronous method from synchronous method in C#?](https://stackoverflow.com/questions/9343594/how-to-call-asynchronous-method-from-synchronous-method-in-c) – Liam Sep 07 '18 at 08:49
  • note in that duplicate [the line *There's no solution that works in every situation, though.*](https://stackoverflow.com/a/9343733/542251). Your best solution is to make the whole context `async`. – Liam Sep 07 '18 at 08:50
  • 2
    *side note* Why not use`System.Threading.Timer` instead of creating your own version that is a loop? – Igor Sep 07 '18 at 08:52
  • 2
    `Task.Delay()` doesn't block. `Thread.Sleep()` is the one that does. You *shouldn't* use `.Wait()`, that *blocks*. Change your code to *await* that task. Put the delay *outside* the worker function. The loop should look like `while(someRealCondition){ await checkDirectoriesForAppsToRun(); await Task.Delay(..);}` – Panagiotis Kanavos Sep 07 '18 at 08:52
  • Just to clarify, this was originally just a normal method that invoked Thread.Sleep - I moved to Task.Delay to see if maybe windows server 2016 just didn't like Thread.Sleep very much however same exact issue. – Jeax Sep 07 '18 at 08:52
  • 1
    @Jeax that doesn't clarify anything. Using Thread.Sleep() is wrong. Task.Delay doesn't block but *this* code can easily lead to deadlock. After `await` execution returns to the original sync context. In a desktop application, that's the UI thread. Which is blocked by `.Wait()`. ==> Deadlock – Panagiotis Kanavos Sep 07 '18 at 08:53
  • [`Thread.Sleep` and `Task.Delay` work in different ways](https://stackoverflow.com/questions/20082221/when-to-use-task-delay-when-to-use-thread-sleep) so this isn't a like for like replacement. – Liam Sep 07 '18 at 08:54
  • 1
    @Jeax post the code for the loop as well. And do consider using a Timer. – Panagiotis Kanavos Sep 07 '18 at 08:54
  • 1
    @Jeax `pressing enter into the console window` that probably means you have a Console.ReadLine or Console.ReadKey somewhere. – Panagiotis Kanavos Sep 07 '18 at 08:56
  • There is nothing else running besides this one loop in the entire application. it was working perfectly fine with Thread.Sleep on a different system for years. the blocking is intended, the quick Task.Delay was a weak attempt at seeing if perhaps it could alleviate the issue. There are zero ReadLines or ReadKeys anywhere at all.This is a strange issue. Essentially a simple 4 line application of while (true) { Console.WriteLine("Hello"); System.Threading.Sleep(30000); } will stop printing 'randomly' and i have no idea why – Jeax Sep 07 '18 at 08:59
  • One things for sure the moving to Windows 2016 is just a coincidence. @Jeax Panagiotis has given you some really good advice. I'd follow it. – Liam Sep 07 '18 at 08:59
  • @Jeax btw you can get *all* nested subdirectories if you [pass the SearchOption.AllDirectories](https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.getdirectories?view=netframework-4.7.2#System_IO_Directory_GetDirectories_System_String_System_String_System_IO_SearchOption_) to `GetDirectories`. You can find all `.xml` files, in all nested folders if you pass "*.xml" as `searchPattern` and SearchOption.AllDirectories as `searchOption` to Directory.GetFiles. You can probably remove most of that code – Panagiotis Kanavos Sep 07 '18 at 09:02
  • 1
    @Jeax there's nothing wrong with Windows 2016. There's nothing wrong with Task.Delay. If there was, people would have noticed in the last 6 years (that's when Task.Delay was introduced). Whatever the problem is, it's in the code you didn't post, combined with the blocking call – Panagiotis Kanavos Sep 07 '18 at 09:03
  • I've literally posted every single piece of the code. I really do appreciate the help, and i know that the obvious answer is "its some code you're hiding". But here - I literally just ran this code on the system int i = 0; while (true) { Console.WriteLine(i++); System.Threading.Sleep(1000); } and it has stopped printing. That is the entire application. I don't know what more information i can give that you aren't going to say "its in the code you havent posted" – Jeax Sep 07 '18 at 09:07
  • The application originally was using Thread.Sleep(timeToPause); for years, with no async or tasks and ran perfectly fine, because the main thread doesn't care if its blocked since it does this one single task. So why would that also block and wait for a key press now suddenly, with zero code changes, and why only since moving servers... The code i posted is literally the entire application (except the CheckDirectoryForApp method, which we know executes since the last message is always 'check completed next run at ' before it waits for a key press – Jeax Sep 07 '18 at 09:12
  • I see no reason to make this program async, given what it does. It's a little risky to use async in a console program because there is no synchronization context. If you do it wrong your `main` will exit while there are still continuations to finish, and you can get strange results when that happens. I suggest removing the async logic. Also, I'd program it to run only once (no loop), then schedule it with a [task manager](https://learn.microsoft.com/en-us/windows/desktop/taskschd/task-scheduler-start-page) of some kind. – John Wu Sep 07 '18 at 09:16
  • Hi John, it was originally non async and just using System.Threading.Thread.Sleep(timeToSleep); until the server move at which point it subsequently started playing up, and the async move was simply trying to mitigate and remove the issue as it was unexpected behaviour (And assumed perhaps simply a weird quirk of Thread.Sleep() on that specific server. or the newer console windows). The reason it is a loop is because it is an internal task manager, designed specifically to run tasks at a predefined time. Windows task scheduler was far too inconsistent – Jeax Sep 07 '18 at 09:18
  • Is it possible that you are "barking up the wrong tree"? I recommend using Windows Task Manager to create a full memory dump of the application when it hangs. Then use [WinDbg](https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-download-tools) or [Debug Diag](https://www.microsoft.com/en-us/download/details.aspx?id=49924) to find the LoC that is causing the deadlock. – Igor Sep 07 '18 at 09:46
  • Great idea, i will try this. – Jeax Sep 07 '18 at 10:00

2 Answers2

1

Why not use System.Threading.Timer instead of creating your own version that is a loop? That is what they were created for. See the already excellent comments on the question as to why the posted code would/could be deadlocking, this is easy to do if you mix synchronous calls with async/await and it is also not necessary to use async/await as you are only using it for Task.Delay

private static System.Threading.Timer _timer;

static void Main(string[] args)
{
  // start the timer
  _timer = new System.Threading.Timer(checkDirectoriesForAppsToRun, null, 0, timeToPause);
}

static void StopTimer()
{
  // call this method when you want to stop the timer
  _timer?.Dispose();
}


static void checkDirectoriesForAppsToRun(object state)
{
  Console.WriteLine("Starting apps...");
  /* exising code not considered in this answer... */
  Console.WriteLine("Check completed next run at " + DateTime.Now.Add(timeToPause).ToShortTimeString());

  // await Task.Delay(timeToPause); // removed
}
Igor
  • 60,821
  • 10
  • 100
  • 175
  • Hi Igor. Just used this and it has displayed the exact same issue. However i appreciate the help - But it seems there is something very wrong going on somewhere, which seems to carry forward even into .NETs own Timer class. For what its worth it ran 5 times successfully before failing. This is consistant with every other method i've tried, being that it will work for a in determined amount of time then 'suddenly' stop. Can be minutes, can be days. – Jeax Sep 07 '18 at 09:59
1

So it seems this is an issue with RDP connectivity freezing .NET applications at runtime.

Was not an issue on Windows server 2008 - is an issue on later windows server versions. See link below. Currently been unable to resolve - Got rid of RDP in favour of VNC to sidestep the issue

https://social.msdn.microsoft.com/Forums/vstudio/en-US/f1d6d2e3-417f-4bc4-be83-1e659852d6cb/application-hang-when-using-remote-desktop?forum=vcgeneral

Jeax
  • 47
  • 7