Children processes created in ASP.NET Core Process gets killed on exit

前提是你 提交于 2020-05-24 21:13:29

问题


I'm spawning a child process in ASP.NET Core (.NET Framework) with Process class:

var process = new Process
            {
                StartInfo = new ProcessStartInfo(executableDir)
                {
                    Arguments = commandDefinition.CommandDef.ArgumentsAsString,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    WorkingDirectory = _contentPath,
                },
            };

process.Start()

As far as I understand when parent (ASP.Net Core) process gets killed, the children process should stay alive. I have tested this behaviour using two console applications and children process never gets killed after killing parent process. However when I spawn a new process in ASP.NET Core then children process gets killed when:

  • IIS recycles app.
  • MSDeploy publishes a new version of ASP.NET Core app.
  • When using dotnet watch and the application is restarted during to code change.

It doesn't get killed ONLY if parent is killed through task manager.(after some tests it's not always the case)

From the above I suspect that there is a mechanism in ASP.NET Core that kills all children processes on successful exit. Is it documented somewhere? Is there a way to avoid it? I couldn't find any info about such behaviour.

Edit: The repro is actually pretty easy.

  1. Create ASP.NET Core project (.NET Framework or .NET Core, doesn't matter)
  2. Add below code somewhere to your Startup class
  3. Start web app. It will be hosted under IIS Express. The calc process will start. Now either kill your app through task manager or close it through IIS express tray icon.
  4. Calc process will get killed. (Sometimes you need to try to refresh the your offline webpage)
 var process = new Process
 {
      StartInfo = new ProcessStartInfo("calc.exe")
      {
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            UseShellExecute = false,
            CreateNoWindow = true,
      },
 };
 process.Start();

Edit2: The issue seems to be in IIS. I have two profiles in launchSettings.json. If I run it with IISExpress then it gets closed, however when using a second one it lives.

"IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "api/values",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "WebApplication3Core": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "api/values",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "http://localhost:52135/"
    }

Edit4:

I did some research with process monitor and here is the output:

As you can see in ss1 that there is a "Process Exit" operation with iisexpress, then there are many irrevelant logs and after some time there is a Process Exit for calc.exe. It's not any different than normal exit. The only difference is the latter log which says "CloseFile" and path to my web app, I don't know what it actually means. It's definitely iis who kills calc.exe. I have IIS Express 10.0.14358 version (Server version where I found this is also 10)


回答1:


As I said in my comment, there is a Job Object which is created by ASP.NET core in the out-of-process scenario. The relevant source code portion is here:

https://github.com/aspnet/AspNetCore/blob/master/src/Servers/IIS/AspNetCoreModuleV2/OutOfProcessRequestHandler/serverprocess.cpp#L89

HRESULT
SERVER_PROCESS::SetupJobObject(VOID)
{
    HRESULT                                 hr = S_OK;
    JOBOBJECT_EXTENDED_LIMIT_INFORMATION    jobInfo = { 0 };

    if (m_hJobObject == NULL)
    {
      ....
            jobInfo.BasicLimitInformation.LimitFlags =
                JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;

            if (!SetInformationJobObject(m_hJobObject,
                JobObjectExtendedLimitInformation,
                &jobInfo,
                sizeof jobInfo))
            {
                hr = HRESULT_FROM_WIN32(GetLastError());
            }
        }
    }

    return hr;
}

As per documentation, JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE:

Causes all processes associated with the job to terminate when the last handle to the job is closed.

If you dig the source further, it does not seem to be optional.

Now, you can actually see this by yourself, if you reproduce your steps. Use Process Explorer, and navigate to your dotnet.exe process, this is what it will display:

  • note 1: in fact calc.exe stays alive (at least in my Windows 10 installation because it's now a WinRT app, so it will not end up as child of dotnet.exe), that's why I used notepad.exe
  • note 2: iisexpress.exe also creates a job object, but it's configured as breakaway ok, which means it won't kill child processes.
  • note 3: if you run from Visual Studio (not my screenshot), you may see an intermediary VSIISExeLauncher.exe process between iisexpress.exe and dotnet.exe. This one also creates a Job Object with 'kill on close' to add to the confusion...



回答2:


Edit

Solution not working for notepad.exe - I will try to see if there is any optionn based on Simon's answer as yo why this behaviour happens

Old answer (to be removed)

I have to wash my hands now for writing this code, but I think you can work around this limitation if that is what you need in your context. I advise against running external processes, especially from the "web server". It's asking for trouble. Replacing the process by some malicious person, credential escalation, unexpected behaviour because of syntax changes just to name a few.

Anyway this might work for you (interposing cmd.exe in between, to try to break the child-parent relationship):

var process = new Process
{
  StartInfo = new ProcessStartInfo 
      { 
         FileName ="cmd.exe",  
         Arguments = "/c calc.exe", 
         WindowStyle =  ProcessWindowStyle.Hidden
      }
};

process.Start();


来源:https://stackoverflow.com/questions/54105795/children-processes-created-in-asp-net-core-process-gets-killed-on-exit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!