Proper way to suspend application while separate threads are working - c#

I'm using a library that listens for incoming TCP messages (it uses BeginAcceptTcpClient). It's intended to work in the background, while my app does other data processing. After it opens some separate threads reading data from the internet, lets the main application thread to continue.
When testing, I used to use it that way:
static async Task Main(string[] args)
{
[...]
connectionsManager.Start();
logger.LogInformation("Application started");
Console.ReadLine();
}
When I'm testing it locally, it works as intended: I can open the application and it works until I press Enter. But now I decided to run it on VPS using docker. It turns out that when I run a docker container as a background app, it closes right after writing "Application started" to the logger. Console.ReadLine() doesn't suspend main thread and even if other threads are still working in connectionManager, the app closes.
Of course, I can make an infinite loop, but are there any better ways to do that? I don't want to waste processing power on irrelevant operations.

A very simple way of achieving that is
Thread.Sleep(Timeout.Infinite);
You can find the Timeout class in the System.Threading namespace, but in reality, Infinite is just a const with a value of -1.
For async you can go
await Task.Delay(Timeout.Infinite);

Related

Detect when a console application is closed?

I have an app that I need to clean up some resources before it shuts down. I've got it handling the event using:
AppDomain.CurrentDomain.ProcessExit += OnProcessExit;
private static async void OnProcessExit(object? sender, EventArgs e)
{
Console.WriteLine("We");
Thread.Sleep(1000);
Console.WriteLine("Are");
Thread.Sleep(1000);
Console.WriteLine("Closing");
}
But the event never gets fired? At least I don't see it, it instantly closes. I've tried this in an external and internal console and neither seem to catch it.
Using Linux Ubuntu 20.10
While you might see it as overkill in the beginning, I can recommend wrapping your console app in .NET Generic Host. This enables you to easily handle resource initialisation and cleanup, it also encapsulates logging and DI and nested services if available. The console app becomes easy to startup in an integration test, install as a Windows service (e.g. via Topshelf) or just keep running as a console app.
https://learn.microsoft.com/en-us/dotnet/core/extensions/generic-host
To get started you can run in command prompt
dotnet new worker
Then in Worker.cs you can override the StopAsync
public override async Task StopAsync(CancellationToken cancellationToken)
{
await Task.Delay(1000);
_logger.LogInformation("Ended!");
}
Running with dotnet run you will see logging each second, and when you Ctrl+C you will see "Ended!" after 1 second - here you do any resource cleanup needed.
Normally you should use AppDomain.ProcessExit rather than AppDomain.CurrentDomain.ProcessExit. Is there a specific reason why you're using the second form?
How is your console app closing? Is it a normal exit after finishing its work, or failing due to an unmanaged exception, or dying due to a rude shutdown (eg Ctrl-C, Environment.FailFast, etc)?
In the first two cases AppDomain.ProcessExit should be invoked normally. But if that isn't happening for some reason, you can use Try..Finally to do resource cleanup.
In the third case, it's very likely that AppDomain.ProcessExit won't be invoked. And there's not a lot you can do about that.
Are you using a Debug or Release build? Because shutdown behaviour can be different depending on the build type. In addition, apps hosted within Docker might have unusual shutdown behaviour.

Should I Use An Always-Running Console Program on Server to Do Task

What I want to achieve is quite simple, and it can be accomplished by a always-running console program like below:
class Program
{
static void Main(string[] args)
{
while (true) {
DateTime now = DateTime.Now;
if(now==timeToRunTask)
runMyTask();//e.g. send an email to Joe
}
}
}
I wonder if this approach is very inefficient in terms of what I'm trying to achieve. And I saw some information about using Task Scheduler so I wonder if I should use that. I'm using Windows Server. But I'd like to know why I shouldn't use the above approach first. Thanks!
Even if you stick with this approach, you still need a way to launch the console app. You can't just log in and run it, because it will terminate when you log off.
The simplest approach is to use the tools Windows provides, in this case Task Scheduler. You can configure a task to launch your application on an interval. Then in the application, just run the task once and exit.
If you truly require that the application stays running indefinitely, I recommend moving from a console app to a Windows Service.
On a server you have little to no control over the app. E.g. if the server reboots (due to installed updates for example), you have to restart the app manually.
If you only have this one app, I'd recommend making it a windows service. It's incredibly simple to do in C#. If you need multiple tasks in the long run, having multiple services (maybe even on multiple servers) for it can become quite the hassle, though.

Background Process in web application Asp.Net [duplicate]

I need to execute an infinite while loop and want to initiate the execution in global.asax.
My question is how exactly should I do it? Should I start a new Thread or should I use Async and Task or anything else? Inside the while loop I need to do await TaskEx.Delay(5000);
How do I do this so it will not block any other processes and will not create memory leaks?
I use VS10,AsyncCTP3,MVC4
EDIT:
public void SignalRConnectionRecovery()
{
while (true)
{
Clients.SetConnectionTimeStamp(DateTime.UtcNow.ToString());
await TaskEx.Delay(5000);
}
}
All I need to do is to run this as a singleton instance globally as long as application is available.
EDIT:SOLVED
This is the final solution in Global.asax
protected void Application_Start()
{
Thread signalRConnectionRecovery = new Thread(SignalRConnectionRecovery);
signalRConnectionRecovery.IsBackground = true;
signalRConnectionRecovery.Start();
Application["SignalRConnectionRecovery"] = signalRConnectionRecovery;
}
protected void Application_End()
{
try
{
Thread signalRConnectionRecovery = (Thread)Application["SignalRConnectionRecovery"];
if (signalRConnectionRecovery != null && signalRConnectionRecovery.IsAlive)
{
signalRConnectionRecovery.Abort();
}
}
catch
{
///
}
}
I found this nice article about how to use async worker: http://www.dotnetfunda.com/articles/article613-background-processes-in-asp-net-web-applications.aspx
And this:
http://code.msdn.microsoft.com/CSASPNETBackgroundWorker-dda8d7b6
But I think for my needs this one will be perfect:
http://forums.asp.net/t/1433665.aspx/1
ASP.NET is not designed to handle this kind of requirement. If you need something to run constantly, you would be better off creating a windows service.
Update
ASP.NET is not designed for long running tasks. It's designed to respond quickly to HTTP requests. See Cyborgx37's answer or Can I use threads to carry out long-running jobs on IIS? for a few reasons why.
Update
Now that you finally mentioned you are working with SignalR, I see that you are trying to host SignalR within ASP.NET, correct? I think you're going about this the wrong way, see the example NuGet package referenced on the project wiki. This example uses an IAsyncHttpHandler to manage tasks.
You can start a thread in your global.asax, however it will only run till your asp.net process get recycled. This will happen at least once a day, or when no one uses of your site. If the process get recycled, the only way the thread is restarted agian, is when you have a hit on your site. So the thread is not running continueuosly.
To get a continues process it is better to start a windows service.
If you do the 'In process' solution, it realy depends on what your are doing. The Thread itself will not cause you any problems in memory or deadlocks. You should add a meganism to stop your thread when the application stops. Otherwise restarting will take a long time, because it will wait for your thread to stop.
This is an old post, but as I was seraching for this, I would like to report that in .NET 4.5.2 there is a native way to do it with QueueBackgroundWorkItem.
Take a look at this post: https://blogs.msdn.microsoft.com/webdev/2014/06/04/queuebackgroundworkitem-to-reliably-schedule-and-run-background-processes-in-asp-net/
MarianoC
It depends what you are trying to accomplish in your while loop, but in general this is the kind of situation where a Windows Service is the best answer. Installing a Windows Service is going to require that you have admin privileges on the web server.
With an infinite loop you end up with a lot of issues regard the Windows message pump. This is the thing that keeps a Windows application alive even when the application isn't "doing" anything. Without it, a program simply ends.
The problem with an infinite loop is that the application is stuck "doing" something, which prevents other applications (or threads) from "doing" their thing. There have been a few workarounds, such as the DoEvents in Windows Forms, but they all have some serious drawbacks when it comes to responsiveness and resource management. (Acceptable on a small LOB application, maybe not on a web server.) Even if the while-loop is on a separate thread, it will use up all available processing power.
Asynchronus programming is really designed more for long-running processes, such as waiting for a database to return a result or waiting for a printer to come online. In these cases, it's the external process that is taking a long time, not a while-loop.
If a Window Service is not possible, then I think your best bet is going to be setting up a separate thread with its own message pump, but it's a bit complicated. I've never done it on a web server, but you might be able to start an Application. This will provide a message pump for you and allow you to respond to Windows events, etc. The only problem is that this is going to start a Windows application (either WPF or WinForms), which may not be desirable on a web server.
What are you trying to accomplish? Is there another way you might go about it?
I found this nice article about how to use async worker, will give it a try. http://www.dotnetfunda.com/articles/article613-background-processes-in-asp-net-web-applications.aspx
And this:
http://code.msdn.microsoft.com/CSASPNETBackgroundWorker-dda8d7b6
But I think for my needs this one will be perfect:
http://forums.asp.net/t/1433665.aspx/1

Threading in Visual Studio requires Join to work properly

This is more of an "I'd like to know" kind of question, than a real problem.
While working on improving my threading skills, and I'm running into the following conundrum.
The source code
internal class Program
{
private static void Main(string[] args)
{
var thread = new Thread(() => Print("Hello from t"));
thread.Start();
//thread.Join();
}
private static void Print(string message)
{
Console.WriteLine(message);
}
}
The problem
If I run the application from Visual Studio (regardless of whether it's Debug or Release configuration), the message is never displayed in the Output window unless I wait for the thread to exit (using Join).
The solution
Run the compiled executable from a command prompt, and you see the expected output.
My question
I'm gonna throw a wild guess and say that the Visual Studio environment makes all the difference.
What I'm wondering is, if I were working on a real-world application, how would I use Visual Studio to debug said application, without being forced to modify the source code (to use Join)?
In a real-world application, this code should not appear because of the problem with the app quitting before the thread is completed. If you do have this problem, it usually signals a problem with the code.
If you are making use of a message pump (WinForms) or similar (WPF), the application will run as normal, meaning it won't exit until the user (or the application) breaks the loop by requesting the application exit. In this case, the thread will work until it finishes, or until the program exits. Thread.Join() may need to be called anyway, depending on the scenario.
If you are creating a console application, Thread.Join() should be called at the end of the program to ensure the worker thread completes. An alternative is to start the message pump with System.Windows.Forms.Application.Run(). However, it is not designed for this, and should not be used unless you are interacting with the user.
Another aspect, there are two kinds of threads in C#: foreground threads and background threads. Foreground threads keep running after the main thread has stopped. Background threads are stopped when all foreground threads are completed. The default type is a foreground thread. You can explicitly set a thread to background with the Thread.IsBackground property. Visual Studio apparently monkeys around with the threads to the point that the foreground thread doesn't prevent the application from quitting. Running the program outside of the debugger works fine.
It is still a good idea to be sure all threads terminate before the main thread. Who knows what might happen if you have more advanced code running after Main exits.
The call thread.Start() just starts the subsidiary thread and then returns. Since that's the end of your Main function, the program finishes and its process exits before the subsidiary thread has a chance to print the message.
No mystery, nothing weird about Visual Studio environment, just normal Windows process behaviour.

Most appropriate thing to do with Main() method for long running async processes

I have a basic C# console application that executes a fairly long running process involving timers and asynchronous requests. The sole purpose of the Main() method is to initialize the timers and then let them do their thing for the next few hours.
I know that Windows Services are appropriate for many long running processes, but doesn't feel appropriate for this use case (executed manually when needed, always terminated within a day, no hurdles of having to install the Service, etc).
Right now, I simply do:
while (true)
Thread.Sleep(5000);
Throwing in a Thread.Sleep seems ... dirty for some reason. Or is that really the best thing to do to stop the application from terminating before the async process are complete?
You could use one/multiple ManualResetEvent to communicate from the background threads to the foreground thread.
The foreground thread in Main could wait until all background threads signaled that they are finished.
You shouldn't be Thread.Sleep, but isntead you should be waiting on some sort of event that would get signaled when there is anything to do, including shuting yourself down.
The application you describe though would much better fit as a service, not as a console app.

Categories