runtime: CoreCLR should handle SIGTERM as equivalent to Environment.Exit()

SIGTERM is meant to be used for graceful shutdown of an app. The runtime should handle it by doing the equivalent of Environment.Exit(). Then with https://github.com/dotnet/corefx/issues/5205, apps will also be able to plug in their own cleanup that’ll be triggered on any graceful shutdown, including those triggered by SIGTERM.

As an example, docker stop will initially send a SIGTERM to give the app a chance to gracefully shutdown before it eventually then sends SIGKILL if the process is still alive. https://github.com/aspnet/Hosting/issues/516

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 4
  • Comments: 17 (10 by maintainers)

Most upvoted comments

I am wondering the same thing, @tugberkugurlu. There was a lot of discussion on the implementation details but I can’t find any guidance on how I should be implementing graceful shutdown in a .NET Core console application so it behaves the same on any OS.

@adityamandaleeka, @stephentoub might not be relevant here but how should I listen on SIGTERM on a .NET Core console application? My app level entry point accepts CancellationToken and I am planning to trigger a cancellation through a CancellationTokenSource when I receive SIGTERM in my static Main method.

gracefully handle SIGTERM and SIGKILL events

According to this, SIGKILL can’t be caught or ignored.

SIGTERM raises the AssemblyLoadContext.Default.Unloading and AppDomain.CurrentDomain.ProcessExit events. The equivalent on Windows is CTRL_CLOSE_EVENT.

The events above are equivalent. The Unloading event was added when AppDomain was initially not going to be exposed in the .NET Core API. That has since changed, so now both events exist.

At the point when these events are raised, nothing significant has been torn down yet, so the event handlers should be able to do most things. Those events are currently raised on the finalizer thread, so finalizers can’t be relied upon, even with GC.WaitForPendingFinalizers(). Probably would be good to raise those events on a different thread in the future.

Any exception thrown by an event handler will crash the process.

SIGINT and SIGQUIT are currently treated as abrupt termination and do not raise the events above. However, a Console.CancelKeyPress handler can prevent termination.

AssemblyLoadContext.Default.Unloading (no documentation at all)

Thanks for pointing that out, I’ll file an issue.

In the former it says one has 2 seconds to do the work

That is for .NET Framework, the docs need to be updated, I’ll file an issue. .NET Core currently does not time-out the event handlers above, though that may change in the future.

but here it says in Kubernetes one has 30 seconds. How do we do this bit: ‘The system [Kubernetes] waits terminationGracePeriodSeconds (default 30s), or until the Pod completes on it’s own.’?

Kubernetes may have its own timeout but that’s separate and not in .NET Core’s control. The parent of the .NET Core process may for instance issue a SIGTERM and if the process does not exit within a timeout the parent may issue a SIGKILL. A parent process may do something like that to ensure that a child process is torn down in a timely manner. It may be possible to configure the timeout, you’d have to consult the container’s docs.

The discussion in coreclr git are a mess. Here, for example, it talks about having to look for a keypress event!

Yea there was a time when SIGTERM was not handled. There was some other bug related to handling the CancelKeyPress event, I don’t remember the details. You can ignore these.

I was just editing to add that above 😃