-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
.NET 5 apps can no longer intercept SIGINT signals (receive CancelKeyPress events) when running under Docker #51221
Comments
Tagging subscribers to this area: @carlossanlop Issue DetailsDescriptionMy company has hundreds of microservices processing petabytes of data per month. We have been using SIGINT as the stop signal in our Dockerfiles. A service will intercept the SIGINT signal in the Console.CancelKeyPress event handler, set the Cancel arg to false, and initiate a final shutdown sequence to perform any cleanup and avoid data loss. SIGTERM is actually the default signal that Docker uses and that signal will call the In versions prior to .NET 5 (.NET Core 3.1 for instance), our services running inside a Docker container have been able to capture Docker stop signals of SIGINT. In .NET 5, the SIGINT signals are no longer being intercepted and Console.CancelKeyPress is never called. This issue resulted in some data loss in our services. SIGTERM signals will still invoke the Unloading and ProcessExit handlers. We are currently using SIGTERM as a temporary workaround, but we believe that the new SIGINT behavior is a regression and a breaking change. It may not have been reported earlier because SIGINT is not the default stop signal that Docker uses; it needs to be specified alongside a STOPSIGNAL keyword in the Dockerfile. Note: The behavior does not depend on whether the signal was issued via the keyboard or a kill system call. Our dockerfiles contain the following code. Changing the stop signal from SIGINT to SIGTERM allows the signal to be intercepted and for a clean shutdown to occur. Similarly, changing from dotnet5 to dotnet3 allowed the the signal to be intercepted. FROM xxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/base:dotnet5
STOPSIGNAL SIGINT
WORKDIR /app
COPY . .
ENTRYPOINT ["dotnet", "Sdk.Service.dll"] ConfigurationThe problem only occurs in .NET 5.0 or higher. Regression?This worked in .NET Core 3.1. It fails in .NET 5.0. Other informationThere are two related issues that I uncovered: "
"
"dotnet run doesn't handle ctrl-c well #4779"
|
I recall SIGQUIT also had the same issues as SIGINT. |
This works fine when I try to reproduce the issue: $ dotnet new console -o console
$ cd console Edit Program.cs: using System;
using System.Threading;
namespace console
{
class Program
{
static void Main(string[] args)
{
System.Console.WriteLine("Press Ctrl+C to stop the app.");
ManualResetEventSlim mre = new();
Console.CancelKeyPress += (_, e) => { mre.Set(); e.Cancel = true; };
mre.Wait();
Console.WriteLine("CancelKeyPress received... stopping");
Thread.Sleep(2000);
Console.WriteLine("Bye!");
}
}
} Publish the app:
Write a FROM mcr.microsoft.com/dotnet/runtime:5.0
WORKDIR /root
ADD bin/Release/net5.0/publish .
ENTRYPOINT ["dotnet", "console.dll"] Build an image: $ podman build -t cancelapp . Now run it and press Ctrl+C: $ podman run -ti cancelapp
Press Ctrl+C to stop the app.
^CCancelKeyPress received... stopping
Bye! |
I will reproduce your steps and get back to you. I will also get additional environment information. |
Thank you so much for looking at this. Here are my repro steps using your steps as closely as possible. (same)
(additional step) (same)
(same)
(different)
docker build: (different, but likely just because i'm not familiar with podman)
(for me, dropping to wsl)
open another wsl
grab the container id
output from the app:
no additional logging. Now the exact same steps but with .net 3 work totally fine for me. |
How does it behave when you do |
with
|
Now if you change TargetFramework in the .csproj to
and one minor edit to your program.cs since target-typed object creation isn't available with that target:
to:
And run the exact same test as I outlined above via the
So some change between 3.1 and 5 appears to have a different behavior. |
#34297 added a check in .NET 5: runtime/src/libraries/System.Console/src/System/ConsolePal.Unix.cs Lines 922 to 927 in c7e02f3
This means: when there is no terminal, The This is indeed a breaking change. For terminating containers, the recommended signal is @jeffhandley @adamsitnik @carlossanlop @jozkee do you prefer the .NET Core 3.1, or the .NET 5 behavior? |
Feels like this should be reverted to 3.1 behavior and focus on this #50527 for signal handling improvements. Using SIGTERM to shutdown currently in .NET Core requires more code and blocking code in process exit in order to let other code run (and can result in deadlocks if done incorrectly). |
Another example of why performing shutdown in ProcessExit is undesirable is the non-deterministic ordering and processing of exit handlers: NLog performs automatic shutdown of logging in a ProcessExit event handler. Unfortunately, that event handler is executed before our own cleanup handler. The shutdown of the logging library occurs before our cleanup routines, which also log important information. |
…#52891) * Console.Unix: fix, make SIGINT work when input is redirected. * Fix misplaced s_initialized assignment
Description
My company has hundreds of microservices processing petabytes of data per month. We have been using SIGINT as the stop signal in our Dockerfiles. A service will intercept the SIGINT signal in the Console.CancelKeyPress event handler, set the Cancel arg to false, and initiate a final shutdown sequence to perform any cleanup and avoid data loss. SIGTERM is actually the default signal that Docker uses and that signal will call the
AssemblyLoadContext.Current.Unloading
and theAppDomain.Current.ProcessExit
handlers before abruptly exiting. SIGINT has some advantages over SIGTERM in .NET Core such as system-recognized keystrokes and the option to exit through main.In versions prior to .NET 5 (.NET Core 3.1 for instance), our services running inside a Docker container have been able to capture Docker stop signals of SIGINT. In .NET 5, the SIGINT signals are no longer being intercepted and Console.CancelKeyPress is never called. This issue resulted in some data loss in our services. SIGTERM signals will still invoke the Unloading and ProcessExit handlers. We are currently using SIGTERM as a temporary workaround, but we believe that the new SIGINT behavior is a regression and a breaking change. It may not have been reported earlier because SIGINT is not the default stop signal that Docker uses; it needs to be specified alongside a STOPSIGNAL keyword in the Dockerfile.
Note: The behavior does not depend on whether the signal was issued via the keyboard or a kill system call.
Our dockerfiles contain the following code. Changing the stop signal from SIGINT to SIGTERM allows the signal to be intercepted and for a clean shutdown to occur. Similarly, changing from dotnet5 to dotnet3 allowed the the signal to be intercepted.
Configuration
The problem only occurs in .NET 5.0.
The containers are run in Amazon Linux AMI 2018.03 (like rhel fedora)
Also, reproduced in WSL2 Linux subsystem under Windows.
Regression?
This worked in .NET Core 3.1. It fails in .NET 5.0.
Other information
There are two related issues that I uncovered:
"
CancelKeyPress
not firing on coreclr on ubuntu #16088"#16088
dotnet run
was called which introduced a wrapper instead ofdotnet
, which does not use a wrapper.dotnet
in our Dockerfile. One speculation is that, in .NET 5,dotnet
may forward todotnet run
."
AppDomain.ProcessExit
is not invoked on docker stop"#36089
"dotnet run doesn't handle ctrl-c well #4779"
dotnet/sdk#4779 (comment)
The text was updated successfully, but these errors were encountered: