Detect when a console application is closed? - c#

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.

Related

Prevent windows server from suspending my process

I've developed a program (winforms application, not a service) in C# that runs on a windows server.
The program starts multiple times based on requests from outside the server.
From time to time I see that the program is "Suspended" for an unknown reason. I think it is related to a lack of resources, but not sure.
How can I prevent windows from suspending my program?
Update
To be clear, I know that the program crash and it is OK. What I'm asking is not how to improve performance \ prevent the crash, but how to remove the process from the process list \ prevent this suspended status?
Depends in your hardware/software configuration, it's hard to know where is your bottleneck.
I recommend instead to do Multi-thread/task app where you're able to control threads and asign priority, resources, stop, resume, abort, etc...
use on command console to start and check if happends the same but with the parameter high:
start /HIGH <ProgramPath>
Read more how to change priority on executables
Task Scheduler on windows servers MSDN -> Priority
(It's only an opinion, start digging about others solutions.)
You must set the ServiceBase.CanPauseAndContinue Property to False in the constructor of the service before it is started.
NOTE the side effect is:
If CanPauseAndContinue is false, the SCM will not pass Pause or
Continue requests to the service, so the OnPause and OnContinue
methods will not be called even if they are implemented. In the SCM,
the Pause and Continue controls are disabled when CanPauseAndContinue
is false.
For more information see this Microsoft Doc
There are multiple methods of keeping an app awake.
One method would be to request a deferral and then only mark that deferral complete when you are done.
First you need a deferral object that will remain in scope of your process
SuspendingDeferral deferral
Then you need to override OnSuspending
async protected void OnSuspending(object sender, SuspendingEventArgs args)
{
deferral = args.SuspendingOperation.GetDeferral();
await SuspensionManager.SaveAsync();
}
Then you need to mark the deferral complete when your process is done doing whatever it was doing
if (deferral is not null) { deferral.Complete(); }
Full details can be found in the Microsoft docs
For discussion of other methods see this thread:
How to Disable UWP App Suspension?
Technically the process is suspended but if you look at the memory consumption of 32K you can tell it was not suspended. Your process did crash with an unhandled exception which in turn triggers Windows Error Reporting to take a memory dump.
This involves some kernel magic which keeps a process handle in the kernel (System process) alive. It is not a big deal or memory leak since the process did already terminate. Only the PEB (Process Environment Block) the 32K which includes mostly command line, loaded dlls and environment variables are still there.
I would not worry about suspended processes but why your process did crash with an unhandled exception. This could even be a feature to make programers aware that their process did crash by looking at a looong list of suspended processes in Task Manager ;-).
Since it is a .NET Application you will find a generic error messages that a process did crash in the Application event log and a .NET Runtime logged error message with more exception details.
Perhaps that is already enough to keep you going to fix your issue. If not you can configure WER to create a full memory dump via a registry setting (https://learn.microsoft.com/en-us/windows/win32/wer/collecting-user-mode-dumps). Now you have for each "suspended" process a full memory dump you can load into Visual Studio to look further what was the issue.
To further check who holds your process handle still open you can use handle e.g. ProcessHacker (the better Process Explorer) https://processhacker.sourceforge.io/nightly.php
If something else is happening you can see with this tool who is holding any outstanding handles to your process open. But I strongly suspect it is the Windows Kernel.

Proper way to suspend application while separate threads are working

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);

My Windows Forms Application is still running as task after closing

I have build a C# Windows Forms Application with Visual Studio 2010.
Run and close application is done successfully within a short time.
The process is not running in Task-Manager. As well the debugging process close. No problem occurs.
But if the Application is running a while the program does not close and still leave running in Task-Manager
(I just open the apllication and do nothing else, just wait few hours to reproduce the problem).
In Debug mode i have to click on STOP DEBUGGING button to end process.
What can i do to find the rootcause?
A process ends after all of the foreground threads stop.
In a typical Winforms application, there's one main foreground thread - the UI thread. This stops after the main form (the one used in Application.Run) is closed. Check what your Main method is doing afterwards, or just put a breakpoint there to see if the thread successfuly
You might also have some foreground worker thread if you're doing multi-threading. It's your responsibility to ensure they're all stopped. The tricky part is that some of the classes you're using might spin up such threads on their own, without you knowing about it. The first thing to keep in mind is that any object you create that implements IDisposable should actually be disposed. This might take care of the issue. One example that often causes trouble is System.Threading.Timer (or System.Timers.Timer) - if you don't Dispose it, it will keep your application running indefinitely.
To investigate the problem, you can use the thread list in Visual Studio's debugger (Debug -> Windows -> Threads). Run the application, wait as long as needed, close the form and then pause the debugger. The thread list will show all the managed threads in the process. Look at the location on the threads that are running - double-clicking a thread will switch your debugger view to that thread, and you can then see the call stack. This might give you some insight about where that thread came from, and what code it's currently executing (i.e. why it is stuck). You'll probably see a wait there somewhere (unless it's actually doing CPU work); just look at the call stack (Debug -> Windows -> Call Stack) and look for something to identify.
If you checked all the threads, and you can't see anything suspicious in the call stacks, you might have to do a bit of configuration in the debugger. There's two main things you can try - first, in the call stack window, right click and select "Show external code". If that doesn't help, you might have to disable Just My Code (Options -> Debugger), and enable symbol loading for the modules involved. This is a bit more complicated.
If your project contains more than 1 form than you should go to the events of the last form and double click on "FormClosed" event. After this action sends you to the code, write between the brackets:
Application.Exit();
You can use
Environment.Exit(0);
instead.
If the process is still pending that means you are not disposing your resources properly.
Using Application.Exit() or asking the system to do it Environment.Exit(0) may be logged in the system as an error occurred and you are better to know how to properly close a process than relied on Application.Exit(), if you want to close a thread of your app you have to know how to collect those garbage.
You can re-implement the Dispose method to Dispose services, sockets, streams, almost everything that has a .Dispose available.
public class MyClass: IMyClass, IDisposable
{
private bool _disposed = false;
// ...
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
if (disposing)
{
// dispose your stuff you created in this class
// do the same for other classes
// some examples
/*
_webClient.Dispose();
_connector.DataAvailable -= ConnectorHasDataComing
_socket.Dispose();
_timer.Dispose();
_taskLogs.ForEach(x => {
x.Token.Cancel();
x.Task.Wait();
x.Task.Dispose();
});
*/
}
// dispose native events
_disposed = true;
}
If you use System.Threading.Thread or System.Threading.Tasks.Task or System.IO.MemoryStream (or other kind of Stream - Writer/Reader), and others that requires a CancellationTokenSource. If you created the ressource in the class when you are disposing the class, use the Token.Cancel() method to let it know its parent is being disposed and .Wait() for it before calling .Dispose()
public async Task Run(CancellationTokenSource cancellationTokenSource)
{
// ...
while (Running) {
if (cancellationTokenSource.IsCancellationRequested) return;
// ....
}
// ....
using (var reader = new WaveFileReader(tempFile))
{
reader.Position = 0;
await reader.CopyToAsync(fileWriter,81920, cancellationTokenSource.Token);
}
}
I found my issue using the Diagnostic Tools when my Debug was still pending on something after closing the app.
If you use CPU Usage you can click on Break All and it set a breakpoint.
You can then see profiler and find what are your top functions, you might find out that your form is disposed but you have a Thread or Task that invokes fields on your form.
For my case, I was using a filewriter and I implemented IDisposable in that class but it sometimes was about or actual doing a transfer of data between a filereader and itself using .copyTo so it was pending without throwing an exception.
After clicking on one the events, click on Go to Source code and place a breakpoint, you may see events that your code is stocked on.
Otherwise, you can use in the same tool the tab Memory Usage to take a snapshot and look at the Heap and Objects diff or the tab CPU Usage and look at a recorded Profile. If find my copyTo issue that way.
You can also run your app with Throw on all exceptions

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

C# NET Application not shutting down Java Process

I wrote a C# NET application (Console app that is run as a Service) that manages a Java process (Minecraft Game Server), and our Web Panel software manages my application. When the Java process stops, my application stops itself, and when my application stops, it stops the Java process.
The issue I am running into is that I deployed the software to all of our machines after extensive bug testing, but there seems to be a bug we missed where it is NOT shutting down the Java process sometimes. This bug is horrible as the Web Software tries to start my application, my application tries to start the Java process, but fails due to it being unable to IP bind (since the old process stayed open) and we wind up with 15-30 bugged Java processes running.
I am using CurrentDomain_UnhandledException to catch my application's crashes and call TerminateProcess().
I am using CtrlTypes.CTRL_C_EVENT and CtrlTypes.CTRL_CLOSE_EVENT to detect my application being closed which also calls the TerminateProcess() function.
I have tried both of the following methods...
static void TerminateProcess()
{
log.LogMessage("Minecraft Process Shutdown.");
SendProcessCmd("stop");
}
and
static void TerminateProcess()
{
log.LogMessage("Minecraft Process Shutdown.");
minecraftProcess.Kill();
}
However, I seem to be missing another way that my C# application is being shut down, because both ways seem to leave a Java process running every once in a while that I can't reproduce locally.
Well, you did not state any question, I’m going to guess you wanted to ask for other ways a process can get shut down, so that you can intercept it and ensure the Java process termination. Simply said: That is impossible (in full generality).
Just look at your own code: You are doing exactly the same thing to Minecraft: Calling TerminateProcess causes the target process to terminate immediately, without any chance to clean up. Should anyone call TerminateProcess on you (e.g. a user killing the process from Task Manager), your process just terminates immediately.
Also, some fatal exceptions are uncatchable, e.g. when your process dies on a stack overflow, you are not told, just terminated.
I guess you’d need to create another process, watching over your process… (Or rethink the whole architecture, creating and killing processes, especially with TerminateProcess, seems a bit rough to me.)

Categories