简体   繁体   中英

ASP.NET Core web application running as a Linux service does not stop properly

I created a simple ASP.NET Core web application to run as a service on a Linux Ubuntu machine. When I run systemctl start webapp.service to start the application, it starts fine. However, when I run systemctl stop webapp.service to stop it, the command freezes for a long time and eventually times out. Looking at the application's stdout while it's stopping shows that it doesn't get past the await this.app.StopAsync() statement. Here's the output:

Nov 21 08:59:57 LinxServer systemd[1]: Stopping WebApp...
Nov 21 08:59:57 LinxServer dotnet[6746]: info: Microsoft.Hosting.Lifetime[0]
Nov 21 08:59:57 LinxServer dotnet[6746]:       Application is shutting down...

It's supposed to write "Stopped" after StopAsync() returns, which doesn't happen.

However, when I run the application directly using the command do.net WebApplication1.dll , it starts fine and when I press Ctrl+C, it shuts down as expected:

info: Microsoft.Hosting.Lifetime[0]
      Application is shutting down...
Stopping...
Stopped.

Here is the application code:

await Host
    .CreateDefaultBuilder(args)
    .ConfigureServices((hostContext, services) =>
    {
        services.AddHostedService<Application>();
    })
    .UseSystemd()
    .Build()
    .RunAsync();


class Application : IHostedService
{
    private WebApplication app;

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        Console.WriteLine("Starting...");
        var builder = WebApplication.CreateBuilder();
        builder.WebHost.UseKestrel(options => options.ListenAnyIP(8010));
        this.app = builder.Build();

        this.app.MapGet("/", () => "Hello World!");

        await this.app.StartAsync();
        Console.WriteLine("Started.");
    }

    public async Task StopAsync(CancellationToken cancellationToken)
    {
        Console.WriteLine("Stopping...");
        await this.app.StopAsync();
        Console.WriteLine("Stopped.");
    }
}

Here's the content of the Systemd service unit configuration file:

[Unit]
Description=WebApp

[Service]
Type=notify
ExecStart=dotnet WebApplication1.dll
WorkingDirectory=/home/myuser/webapp
KillSignal=SIGINT
User=myuser
Environment=ASPNETCORE_ENVIRONMENT=Production

[Install]
WantedBy=multi-user.target

Any ideas?

Edit: As suggested, I tried the following for Program.Main() as well ( Application class unchanged):

using var host = Host
    .CreateDefaultBuilder(args)
    .ConfigureServices((hostContext, services) =>
    {
        services.AddHostedService<Application>();
    })
    .UseSystemd()
    .Build();
host.Start();
host.WaitForShutdown();

The behavior is the same as before.

You have here a long explanation of the host shutdown lifecycle: https://github.com/do.net/runtime/blob/main/src/libraries/Microsoft.Extensions.Hosting/docs/HostShutdown.md . When u do systemctl stop it calls Environment.Exit and Environment.Exit != CTRL+C . Add to your code host.WaitForShutdown(); You have here a short general example that might help u.

 using Microsoft.Extensions.Hosting;

  ......

 using (IHost host = builder.Build())
    {
        host.Services.GetRequiredService<OtherService>();
        host.Start();            
        host.WaitForShutdown();
        Console.WriteLine("Ran cleanup code inside using host block.");
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM