You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Many systems use SIGTERM as a way to signal a graceful shutdown. To make this work well in container scenarios, we need to start the shutdown process and wait for some timeframe until it's done. To coordinate that, Microsoft.Extensions.Hosting sets up a bunch of events to allow the main thread to exit before continuing the process exit handler. Here's what that would look like (without the dependencies):
usingSystem;usingSystem.Threading;varwaitForProcessShutdownStart=newManualResetEventSlim();varwaitForMainExit=newManualResetEventSlim();AppDomain.CurrentDomain.ProcessExit+=(sender,e)=>{// We got a SIGTERM, signal that graceful shutdown has startedwaitForProcessShutdownStart.Set();Console.WriteLine("Waiting for main");// Don't unwind until main existswaitForMainExit.Wait();};Console.WriteLine("Waiting for shutdown");// Wait for shutdown to startwaitForProcessShutdownStart.Wait();// This is where the application performs graceful shutdown// Now we're done with main, tell the shutdown handlerwaitForMainExit.Set();
The above code shows how a user could set this up today. It's much more complex than the windows equivalent (handling Ctrl+C) for a couple of reasons:
SIGTERM is the signal used to communicate starting a graceful shutdown, this means we need to stop the app from shutting down until some point.
We want the main thread to continue executing for as long as it can until it has unwound. This lets us run any clean up code or logging before exit (see IHost.RunAsync() never completes #44086)
It can result in deadlocks if someone calls Environment.Exit at the wrong point in the application.
This is what waiting for CTRL+C looks like:
varwaitForProcessShutdownStart=newManualResetEventSlim();Console.CancelKeyPress+=(sender,e)=>{e.Cancel=true;waitForProcessShutdownStart.Set();};Console.WriteLine("Waiting for shutdown");// Wait for shutdown to startwaitForProcessShutdownStart.Wait();// Do graceful shutdown here
The runtime itself handles e.Cancel = true and doesn't shut down the process after the event handler runs. Instead the application can use this to coordinate letting the application gracefully unwind from the main thread.
The request here is to treat SIGTERM like Ctrl+C and support e.Cancel.
namespace System.Runtime.InteropServices
{
+ public enum Signal // This may need more unique name+ {+ SIGHUP = 1,+ SIGINT = 2,+ SIGQUIT = 3,+ SIGTERM = 15,+ }+ public class SignalContext+ {+ public Signal Signal { get; }+ public bool Cancel { get; set; }+ }+ public struct SignalHandlerRegistration : IDisposable+ {+ public static SignalHandlerRegistration Create(Signal signal, Action<SignalContext> handler);+ }
}
NOTES:
SignalContext.Signal provides the signals that fired to cause the event to trigger so that can be checked in the callback to take action if the same handler was used for different registrations.
SignalContext.Cancel cancels default processing.
We will map windows behavior to linux signal names:
varwaitForProcessShutdownStart=newManualResetEventSlim();usingvarreg=SignalHandlerRegistration.Register(Signal.SIGINT, context =>{context.Cancel=true;waitForProcessShutdownStart.Set();});Console.WriteLine("Waiting for shutdown");// Wait for shutdown to startwaitForProcessShutdownStart.Wait();
The hosting model in Microsoft.Extensions.Hosting will look like this in .NET 6:
Background and Motivation
Many systems use SIGTERM as a way to signal a graceful shutdown. To make this work well in container scenarios, we need to start the shutdown process and wait for some timeframe until it's done. To coordinate that, Microsoft.Extensions.Hosting sets up a bunch of events to allow the main thread to exit before continuing the process exit handler. Here's what that would look like (without the dependencies):
The above code shows how a user could set this up today. It's much more complex than the windows equivalent (handling Ctrl+C) for a couple of reasons:
Environment.Exitat the wrong point in the application.This is what waiting for CTRL+C looks like:
The runtime itself handles
e.Cancel = trueand doesn't shut down the process after the event handler runs. Instead the application can use this to coordinate letting the application gracefully unwind from the main thread.The request here is to treat SIGTERM like Ctrl+C and support e.Cancel.
cc @janvorli @stephentoub @kouvel
Proposed API
namespace System.Runtime.InteropServices { + public enum Signal // This may need more unique name + { + SIGHUP = 1, + SIGINT = 2, + SIGQUIT = 3, + SIGTERM = 15, + } + public class SignalContext + { + public Signal Signal { get; } + public bool Cancel { get; set; } + } + public struct SignalHandlerRegistration : IDisposable + { + public static SignalHandlerRegistration Create(Signal signal, Action<SignalContext> handler); + } }NOTES:
SignalContext.Signalprovides the signals that fired to cause the event to trigger so that can be checked in the callback to take action if the same handler was used for different registrations.SignalContext.Cancelcancels default processing.We will map windows behavior to linux signal names:
Usage Examples
Waiting synchronously on shutdown to start:
The hosting model in Microsoft.Extensions.Hosting will look like this in .NET 6:
Alternative Designs
Don't add new API but overload the existing Console.CancelKeyPress. This would cover one specific scenario but wouldn't handle the arbitrary signals.
Risks
None