Reputation: 2170
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 dotnet 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 😕.
Upvotes: 1
Views: 1879
Reputation: 2072
You have here a long explanation of the host shutdown lifecycle: https://github.com/dotnet/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.");
}
Upvotes: 1