25

Is there a way to gracefully shut-down a DOTNET CORE application which is running in DOCKER? If yes, which event I should listen?

All I want is upon cancellation request I would like to pass my cancellation token/s to current methods and postpone the shut-down while they are working.

Looking for a sample code, reference link etc. which are relevant to dotnet core and not generic info

UPDATE This question is not a duplicate of docker container exits immediately even with Console.ReadLine() in a .net core console application because I'm not having an immediate exit issue. I need to tap into event something like Windows.SystemsEvents.SessionEnding and relying on Console.CancelKeyPress and/or implementing WebHostBuilder() doesn't fit the bill.

Community
  • 1
  • 1
cilerler
  • 9,010
  • 10
  • 56
  • 91
  • Like this perhaps? http://shazwazza.com/post/aspnet-core-application-shutdown-events/ – DavidG Nov 22 '16 at 12:48
  • [System.Runtime.Loader.AssemblyLoadContext.Default.Unloading](http://www.michael-whelan.net/replacing-appdomain-in-dotnet-core/) maybe – stuartd Nov 22 '16 at 12:49
  • @DavidG looking for **DOTNET CORE** and not **ASP.NET CORE** it doesn't have `IApplicationLifetime` but thank you for your time! – cilerler Nov 22 '16 at 12:50
  • 3
    @cilerler your question is tagged with [asp.net-core] – stuartd Nov 22 '16 at 12:51
  • @stuartd I know, due to having 29 people in **dotnet-core** tag, I tried my chance and made it in distinguish in question. Also it is most likely **aspnet-core** tag followers may have more idea then **.net** tag about the issue. looking into what you sent right now, thank you for your time. – cilerler Nov 22 '16 at 12:56
  • @DavidG you removed my tag but did you see my answer above? do you really believe I don't have base here to add [tag:aspnet-core] ? – cilerler Nov 22 '16 at 13:34
  • Possible duplicate of [docker container exits immediately even with Console.ReadLine() in a .net core console application](http://stackoverflow.com/questions/38549006/docker-container-exits-immediately-even-with-console-readline-in-a-net-core-c) – Jay Nov 22 '16 at 13:34
  • 3
    @cilerler Yes, your question is specifically NOT about ASP.Net Core so it shouldn't contain that tag. Adding it just to give your question a broader audience is not the right thing to do. – DavidG Nov 22 '16 at 13:35
  • @DavidG I agree your disagree. – cilerler Nov 22 '16 at 13:38
  • 1
    Please make sure you guys have more evidence about the duplication then just a second thought process before you mark it. Just because someone thinks it is a duplicate shouldn't make you to mark it as duplicate. It makes question less attractive and effect like that should be considered before the decision. **Great power should come with great responsibility** Anyway, thank you for your attention! – cilerler Nov 22 '16 at 14:30
  • @cilerler I have the same problem with .NET Core 2.0.0-preview2-006497 and Docker under Windows. Neither `Console.CancelKeyPress`, `AssemblyLoadContext.Default.Unloading` nor `AppDomain.CurrentDomain.ProcessExit` is triggered when the Docker container is stopped. Do you have any working solution? I also tested with Linux containers (running on Win 10), there both Unloading and ProcessExit events are triggered. So it seems to be a Windows/Docker for Windows problem... – Tobias Jul 05 '17 at 14:14

4 Answers4

18

In .NET Core 2.0, you can use the AppDomain.CurrentDomain.ProcessExit event, which works fine on Linux in Docker. AssemblyLoadContext.Default.Unloading probably works as well, even before .NET Core 2.0.

Marc Sigrist
  • 3,964
  • 3
  • 22
  • 23
  • 2
    'docker stop ' will trigger AppDomain.CurrentDomain.ProcessExit. The caveat is, your code only gets 2 seconds to handle it. See: https://learn.microsoft.com/en-us/dotnet/api/system.appdomain.processexit?view=netcore-2.1 and https://github.com/dotnet/coreclr/issues/2688#issuecomment-394843595 – J. Andrew Laughlin Aug 20 '18 at 23:05
  • 5
    @J.AndrewLaughlin: Yes, and the timing is different depending on the environment. E.g., in Kubernetes, the `kubectl delete deployment ...` commant seems to trigger a SIGTERM, usually allowing the app about 30 seconds for cleanup. On the other hand, `kubectl apply ...` _over_ an existing deployment seems to cause an immediate SIGKILL, leaving no time for cleanup at all. Unfortunately, documentation on these behaviors is scant to nonexisting. – Marc Sigrist Aug 21 '18 at 15:17
  • @cilerler: Your concern re "I need to tap into event something like..." seems to have been answered. If so, please mark your chosen answer, so that other people can find it faster. Thanks. – Marc Sigrist Aug 21 '18 at 15:25
6

System.Console has an event called CancelKeyPress. I believe this is fired when a sigint event is passed into dotnet.

System.Console.CancelKeyPress += (s,e) => { /* do something here */};
TerribleDev
  • 2,195
  • 1
  • 19
  • 31
4

Using 2.0.0-preview2-006497 I did some testing, and now the AssemblyLoadContext.Default.Unloading is fired when Docker sends a SIGTERM/SIGINT to the container.

Example code looks like:

System.Runtime.Loader.AssemblyLoadContext.Default.Unloading += ctx =>
{
    // code here...
};

See also this issue for some details: https://github.com/aspnet/Hosting/issues/870

Stef Heyenrath
  • 9,335
  • 12
  • 66
  • 121
1

If your container is running in Linux then Loader.AssemblyLoadContext.Default.Unloading works since it can trap the SIGTERM signal, however Windows do not have the equivalent mechanism for this(dotnet issue). Here's an answer to handle shutdown notification in Windows by using SetConsoleCtrlHandler originally from gist

namespace Routeguide
{
    using System;
    using System.Threading;
    ...

    class Program
    {
        [DllImport("Kernel32")]
        internal static extern bool SetConsoleCtrlHandler(HandlerRoutine handler, bool Add);

        internal delegate bool HandlerRoutine(CtrlTypes ctrlType);

        internal enum CtrlTypes
        {
            CTRL_C_EVENT = 0,
            CTRL_BREAK_EVENT,
            CTRL_CLOSE_EVENT,
            CTRL_LOGOFF_EVENT = 5,
            CTRL_SHUTDOWN_EVENT
        }

        static void Main(string[] args)
        {
            // do the server starting code
            Start();
            ....

            var shutdown = new ManualResetEvent(false);
            var complete = new ManualResetEventSlim();
            var hr = new HandlerRoutine(type =>
            {
                Log.Logger.Information($"ConsoleCtrlHandler got signal: {type}");

                shutdown.Set();
                complete.Wait();

                return false;
            });
            SetConsoleCtrlHandler(hr, true);

            Console.WriteLine("Waiting on handler to trigger...");

            shutdown.WaitOne();

            Console.WriteLine("Stopping server...");

            // do the server stopping code
            Stop();

            complete.Set();
            GC.KeepAlive(hr);
        }
    }
}
Feiyu Zhou
  • 4,344
  • 32
  • 36
  • Doesn't work for both .NET Framework 4.5.2 and .NET Core 2.0 console apps. Docker version 18.05.0-ce-win67 (18263) – atomaras Jun 29 '18 at 18:08
  • 2
    For dotnet core, you can use Microsoft.Extensions.Hosting, checking my this answer:https://stackoverflow.com/questions/35176091/how-should-a-grpc-service-be-hosted/49503713#49503713 – Feiyu Zhou Jun 30 '18 at 16:19