Killing gracefully a .NET Core daemon running on Linux
Solution 1
You want to be able to send a SIGTERM to the running process:
kill <PID>
And the process should handle it to shutdown correctly.
Unfortunately .NET Core is not well documented, but it is capable of handling Unix signals (in a different fashion from Mono). GitHub issue
If you use Ubuntu with Upstart, what you need is to have an init script that sends the the kill signal on a stop request: Example init script
Add a dependency to your project.json:
"System.Runtime.Loader": "4.0.0"
This will give you the AssemblyLoadContext.
Then you can handle the SIGTERM event:
AssemblyLoadContext.Default.Unloading += MethodInvokedOnSigTerm;
Note:
Using Mono, the correct way of handling it would be through the UnixSignal: Mono.Unix.Native.Signum.SIGTERM
EDIT:
As @Marc pointed out in his recent answer, this is not anymore the best way to achieve this. From .NET Core 2.0 AppDomain.CurrentDomain.ProcessExit
is the supported event.
Solution 2
.NET Core has considerably evolved since @Stefano's answer a year ago. In .NET Core 2.0, you can now use the well-known AppDomain.CurrentDomain.ProcessExit
event instead of AssemblyLoadContext.Default.Unloading
. It works fine for console applications on Linux, also in Docker.
Related videos on Youtube
user4388177
Updated on July 09, 2022Comments
-
user4388177 almost 2 years
I created a .NET Core console application running as a daemon on a Ubuntu 14.04 machine.
I want to stop the service without forcing it, being able to handle a kill event.
How can I achieve this?
-
lasseschou over 7 yearsCare to share your code - turning a .NET Core console app into an Ubuntu daemon?
-
user4388177 over 7 yearsThe only thing I did was copying a default init script from GitHub; the start function calls
dotnet library.dll
and the stop one:kill dotnet library.dll
.
-
-
dcinadr almost 8 yearsThis works if the application is stops on its own gracefully. But if the kill command is called it does not trigger "AssemblyLoadContext.Default.Unloading". Am I doing something wrong?
-
Stefano d'Antonio almost 8 yearsWhat version of .NET Core are you using? Are you modifying the load context at some point?
-
dcinadr almost 8 yearsVersion: 1.0.0-preview2-003121 ... I have also noticed that when I run "dotnet run" it starts 2 processes. I think this is the reason it is not working because it kills one of the processes but not both.
-
Stefano d'Antonio almost 8 yearsTry getting to the published DLL folder and run using:
dotnet <DllName>.dll
(without run) that should run just one process and you can try killing that one. -
dcinadr over 7 yearsThank you. Yes, that is similar to how I got it working. Only difference I had was "dotnet exec <DllName>.dll".
-
Stefano d'Antonio over 7 yearsI didn't know about
exec
so I searched quickly and I found this: github.com/dotnet/cli/issues/2243 but I'm assuming has a similar behaviour todotnet <dll>
. -
Stefano d'Antonio over 7 years@dcinadr Here it recommends to use it without exec, but I would be curious to know the difference if you know. github.com/dotnet/core/issues/77
-
RQDQ over 5 yearsI made a simple example of how to handle this event: github.com/rquackenbush/DotNetSigTermTest
-
Parag over 5 years
AppDomain.CurrentDomain.ProcessExit
only allows for 2 seconds of cleanup, and there is no way to override it using managed code. -
Anders Emil almost 5 years@Parag I think you misread the documentation, or it has been changed. This time limit is only in .NET Framework, not in .NET Core. docs.microsoft.com/en-us/dotnet/api/…
-
Parag almost 5 years@AndersEmil I am sure it applies for .net core. Check the "Applies to" section in the docs link you sent.
-
Anders Emil almost 5 years@Parag the article is about the ProcessExit event, not the time limit. In the purple Note box it clearly says that the time limit does not exist in .NET Core, I'm surprised you miss it.
-
Parag about 4 years@AndersEmil I re-read it and you are right. Sorry for the misinformation.