Search code examples
c#asp.net-coreasp.net-core-webapiasp.net-core-2.2windows-process

dotnet core how to shutdown child process gracefully


I have a dotnet core 2.2 console app.
I hosted it as windows service.
Service starts up another dotnet core WebAPI.
The problem is, how do I gracefully shutdown WebAPI process when the the service is stopped?
Note: I don't want to use Kill() method.

Sample code:

public class MyService : IHostedService, IDisposable
{
    private Timer _timer;
    static Process webAPI;

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _timer = new Timer(
            (e) => StartChildProcess(),
            null,
            TimeSpan.Zero,
            TimeSpan.FromMinutes(1));

        return Task.CompletedTask;
    }

    public void StartChildProcess()
    {
        try
        {
            webAPI = new Process();
            webAPI.StartInfo.UseShellExecute = false;
            webAPI.StartInfo.FileName = @"C:\Project\bin\Debug\netcoreapp2.2\publish\WebAPI.exe";
            webAPI.Start();
        }
        catch (Exception e)
        {
            // Handle exception
        }
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        // TODO: Add code to stop child process safely

        _timer?.Change(Timeout.Infinite, 0);

        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }
}

Solution

  • Technically you could simply call Process.Kill() in order to immediately shut down the process. However, a lot of the time that is not the way to go simply because the WebAPI might be in middle of important operations and you can't really tell when those actions may be happening and Process.Kill() is not really considered "graceful".

    What would be most prudent to do is to tell the process that you would like for it to shut down at the earliest convenience and then allow for the WebAPI to clean things up before it exits itself. If you are desiging the WebAPI that is even better because that way you can decide on how to do this. Only calling Kill() when it is absolutely necessary.

    You can do that multiple ways of course. Some that come to mind are Sockets that are periodically checked and sending a CTRL+C input to the WebAPI.

    
        public Task StopAsync(CancellationToken cancellationToken)
        {
            // send request to shut down
    
            // wait for process to exit and free its resources
            process.WaitForExit();
            process.Close();
            process.Dispose();
    
    
    
            _timer?.Change(Timeout.Infinite, 0);
    
            return Task.CompletedTask;
        }
    

    Of course if this is Async then it wouldn't make sense to wait for it to exit inside of the method so you would simply wait or check if it has exited outside of this method.