sdk: terminating `dotnet run` doesn't terminate child
Steps to reproduce
[Terminal 1]
$ dotnet new razor
$ dotnet run
Hosting environment: Production
Content root path: /home/mistria/runtime-EclipseApplication/tst
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
[Terminal 2]
$ ps aux | grep dotnet
mistria 24040 2.2 0.7 3296988 88604 pts/0 SLl+ 12:07 0:01 dotnet run
mistria 24143 1.1 0.5 21300684 71156 pts/0 SLl+ 12:07 0:00 dotnet exec /home/mistria/runtime-EclipseApplication/tst/bin/Debug/netcoreapp2.0/tst.dll
$ kill -15 24040 #SIGTERM on host
$ ps aux | grep dotnet
mistria 24143 1.1 0.5 21300684 71156 pts/0 SLl+ 12:07 0:00 dotnet exec /home/mistria/runtime-EclipseApplication/tst/bin/Debug/netcoreapp2.0/tst.dll
# child still there like a zombie
Expected behavior
Child process terminated
Actual behavior
Child process is still there
This can be confusing for IDEs (like Eclipse IDE) which bind the “stop” button and other UI actions to the Terminate signal. In such case, the developer trying dotnet run from the IDE will face issues because of the zombi-ish processes
Environment data
dotnet --info output:
.NET Command Line Tools (2.0.1-servicing-006924)
Product Information:
Version: 2.0.1-servicing-006924
Commit SHA-1 hash: 1ed6be56ca
Runtime Environment:
OS Name: fedora
OS Version: 26
OS Platform: Linux
RID: fedora.26-x64
Base Path: /home/mistria/apps/dotnet-2/sdk/2.0.1-servicing-006924/
Microsoft .NET Core Shared Framework Host
Version : 2.0.0
Build : e8b8861ac7faf042c87a5c2f9f2d04c98b69f28d
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 25
- Comments: 26 (8 by maintainers)
Looks like this thread is still active but stale. It was originally open almost a year ago: do we have consensus that this is real and should be addressed somewhere and slotted for a future release?
@livarcocc
Steps to reproduce:
dotnet testprocexp.exeand find parent donet.exeExpected
Actually
on @mickaelistria’s case, about dotnet razor, I don’t think it is dotnet’s job to terminate those processes. The CTRL+C message there is coming from asp.net itself and when you CTRL+C it is asp.net’s responsibility to terminate any extra processes that it may have initiated when it gets terminated.
Also, I couldn’t repro this right now when I tried.
As for dotnet test, @psmolkin would you happen to have a repro for it?
Hi @herebebeasties. Consistent
SIGINT/Ctrl-C handling fromdotnet runis a different issue and one I am also producing a fix for.SIGINTis sent to the foreground process group in POSIX and, similarly, to all processes attached to the current console on Windows. Thus, the children ofdotnet runsee the signal and can respond to it appropriately; for example, this is why Ctrl-C of an ASP.NET Core application running fromdotnet runprints the shutdown message. The problem there is that the default handling ofSIGINTfromdotnet runcauses a different exit status to the parent then it would have if the parent had spawned the child program directly. It also causes an immediate return back to the waiting parent and the child program may still be writing to stdout when handling the signal, resulting in inconsistent and undesirable output in an interactive shell session.This issue is about sending
SIGTERMor using task manager /taskkillto terminate thedotnet runprocess and having it reliably clean up the child processes. UnlikeSIGINT,SIGTERMis usually sent with thekillcommand and that, unless you manually tell it to send to a process group, will only go to the individual process specified. On Windows, killing a process that has no message queues (e.g. a console .NET application like thedotnetCLI) from task manager /taskkillwill rudely terminate the process, resulting in zombied children unless the application takes (complex) steps to prevent it.getting this with 2.1.0-preview2-26406-04, both on Linux and on Windows
@Code-DJ Task Scheduler has been unreliable for ages. I’ve had better luck creating services that do this programatically.
I am considering making a fix that addresses this issue.
On POSIX systems,
dotnet runwould handle theSIGTERMsignal (viaAppDomain.CurrentDomain.ProcessExit) and then first attempt to kill its own pid as a process group (i.e.-pid), maskingSIGTERMfor its process to prevent reentry. This should kill all the children ofdotnetthat did not break away from the process group. However, ifdotnetis not running in its own process group (i.e. it was spawned with an inherited pgid) then at best we can try to kill the child pid becauseProcess.Startspawns new processes with inherited pgid (see dotnet/corefx#17412).On Windows, we could potentially create a job object, associate the new process to the job, and set the job object to terminate all processes in the job upon rude termination of
dotnet. I’m loathe to introduce job objects where we don’t have explicit control over the process tree, however. I know from experience that spawning user programs that suddenly find themselves in a job may fail when spawning their own processes (i.e. break-away).Still, considering the fix would effectively translate the user action of
kill -15 $dotnet_pidtokill -15 -- -$dotnet_pid(or usetaskkill /t /pid $dotnet_pidon Windows), it seems like the workaround is trivial compared to the effort of a fix. The question comes down to user expectation and experience with process tree management, really.If closing a asp.net app is not terminating the process, I believe this is an issue that should be investigated by the ASP.NET team. Please, file a new issue on aspnet/home.
Another possibility is that dotnet has three long running processes that stay around to help with inner loop performance: roslyn, msbuild and razor. You can terminate these processes by running
dotnet build-server shutdown.I’d really like this to be fixed. I’m just getting into the dotnet platform and would really like to take advantage of the speed of linux over windows for our server, but in testing we keep running into this issue which putting us down a bit.
How I encountered the issue
System
Ubuntu 18.04.1 LTS 1 cpu, 1gb ram (AWS EC2 free tier)
Install dotnet-sdk-2.1
Install Node.js
Create Angular / .net project
dotnet new angular -o angular-test-projectStart project
Wait for the angular build to finish. After this, kill the project with Ctrl + C. Sometimes it successfully says
Application is shutting downand then shuts down. Other times, it will just sayApplication is shutting downand then sit there forever meaning something is blocking in some way most likely (my best guess). If you Ctrl + C again after this, the memory will remain being used by this zombie process. You can see in the screenshot below I had to press Ctrl + C twice before it went back to bash.If you look in htop, it seems to be a bunch of ng processes which is strange. So maybe it is just something as simple as the ng serve is stuck open. You can see htop below.
@omajid @livarcocc Hopefully this helps move this along in some way.
A few PowerShell (run as Administrator) one-liners to work around that:
Run at your own risk. You can adjust the
CommandLinefilter to be more specific. Which goes well with runningdotnet --project .\project1.csprojwhich then allows you to match the particular .csproj file on theCommandLine. TheGet-Processpipeline step is unnecessary but I left it in there for easier diagnosing.