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):
using System; using System.Threading; var waitForProcessShutdownStart = new ManualResetEventSlim(); var waitForMainExit = new ManualResetEventSlim(); AppDomain.CurrentDomain.ProcessExit += (sender, e) => { // We got a SIGTERM, signal that graceful shutdown has started waitForProcessShutdownStart.Set(); Console.WriteLine("Waiting for main"); // Don't unwind until main exists waitForMainExit.Wait(); }; Console.WriteLine("Waiting for shutdown"); // Wait for shutdown to start waitForProcessShutdownStart.Wait(); // This is where the application performs graceful shutdown // Now we're done with main, tell the shutdown handler waitForMainExit.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:
Environment.Exit
at the wrong point in the application.This is what waiting for CTRL+C looks like:
var waitForProcessShutdownStart = new ManualResetEventSlim(); Console.CancelKeyPress += (sender, e) => { e.Cancel = true; waitForProcessShutdownStart.Set(); }; Console.WriteLine("Waiting for shutdown"); // Wait for shutdown to start waitForProcessShutdownStart.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.
cc @janvorli @stephentoub @kouvel
Proposed APInamespace 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:
using var reg = SignalHandlerRegistration.Register(Signal.SIGINT, context => { context.Cancel = true; // Start graceful shutdown });
Waiting synchronously on shutdown to start:
var waitForProcessShutdownStart = new ManualResetEventSlim(); using var reg = SignalHandlerRegistration.Register(Signal.SIGINT, context => { context.Cancel = true; waitForProcessShutdownStart.Set(); }); Console.WriteLine("Waiting for shutdown"); // Wait for shutdown to start waitForProcessShutdownStart.Wait();
The hosting model in Microsoft.Extensions.Hosting will look like this in .NET 6:
public class ConsoleLifetime : IHostLifetime, IDisposable { ... private IHostApplicationLifetime ApplicationLifetime { get; } private SignalHandlerRegistration _sigterm; private SignalHandlerRegistration _sigInt; public Task WaitForStartAsync(CancellationToken cancellationToken) { Action<SignalContext> handler = OnShutdownSignal; _sigInt = SignalHandlerRegistration.Register(Signal.SIGINT, handler); _sigterm = SignalHandlerRegistration.Register(Signal.SIGTERM, handler); // Console applications start immediately. return Task.CompletedTask; } private void OnShutdownSignal(SignalContext context) { context.Cancel = true; ApplicationLifetime.StopApplication(); } public void Dispose() { _sigterm.Dispose(); _sigInt.Dispose(); } ... }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.
RisksNone
tibel, watfordgnf, ReubenBond, ValonK, henry701 and 5 more
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4