[英]Gracefully shutdown a generic host in .NET Core 2 linux daemon
我對 .NET Core 和開發 linux 守護進程都是全新的。 我遇到過幾個類似的問題,例如優雅地殺死在 Linux 上運行的 .NET Core 守護程序或在 .NET Core 2.1 中使用通用主機優雅地關閉,但它們沒有解決我的問題。
我使用托管服務構建了一個非常簡單的控制台應用程序作為測試。 我希望它作為守護進程運行,但我無法正確關閉它。 當它在 Windows 和 Linux 中從控制台運行時,一切正常。
public static async Task Main(string[] args)
{
try
{
Console.WriteLine("Starting");
var host = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<DaemonService>();
});
System.IO.File.WriteAllText("/path-to-app/_main.txt", "Line 1");
await host.RunConsoleAsync();
System.IO.File.WriteAllText("/path-to-app/_main.txt", "Line 2");
}
finally
{
System.IO.File.WriteAllText("/path-to-app/_main-finally.txt", "Line 1");
}
}
public class DaemonService : IHostedService, IDisposable
{
public Task StartAsync(CancellationToken cancellationToken)
{
System.IO.File.WriteAllText("/path-to-app/_Start.txt", "Line 1");
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
System.IO.File.WriteAllText("/path-to-app/_Stop.txt", "Line 1");
return Task.CompletedTask;
}
public void Dispose()
{
System.IO.File.WriteAllText("/path-to-app/_Dispose.txt", "Line 1");
}
}
如果我從控制台運行該應用程序,一切都會按預期進行。 但是,當它作為守護進程運行時,在執行kill <pid>
或systemctl stop <service>
后,會執行StopAsync
和Dispose
方法,但不會執行其他任何操作:不會執行await
之后的 in Main
或finally
塊。
注意:我沒有使用 ASP.NET Core 中的任何東西。 AFAIK 這對我正在做的事情沒有必要。
難道我做錯了什么? 這是預期的行為嗎?
這個答案對於 dotnet core 3.1 是正確的,但應該是一樣的。
host.RunConsoleAsync() 等待 Sigterm 或 ctrl + C。
切換到 host.Start() 並且程序在 IHostedServices 完成時停止。
我不認為這條線目前受到打擊:
System.IO.File.WriteAllText("/path-to-app/_main.txt", "Line 2");
總結初始問題下方的對話。
看來IHostedService
中使用的HostBuilder
是控制SIGTERM
的。 一旦Task
被標記為已完成,它就確定服務已正常關閉。 通過移動System.IO.File.WriteAllText("/path-to-app/_main.txt", "Line 2");
服務范圍內的 finally 塊中的代碼可以修復。 下面提供了修改后的代碼。
public static async Task Main(string[] args)
{
Console.WriteLine("Starting");
var host = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<DaemonService>();
});
System.IO.File.WriteAllText("/path-to-app/_main.txt", "Line 1");
await host.RunConsoleAsync();
}
public class DaemonService : IHostedService, IDisposable
{
public Task StartAsync(CancellationToken cancellationToken)
{
System.IO.File.WriteAllText("/path-to-app/_Start.txt", "Line 1");
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public void Dispose()
{
try
{
System.IO.File.WriteAllText("/path-to-app/_Dispose.txt", "Line 1");
System.IO.File.WriteAllText("/path-to-app/_Stop.txt", "Line 1");
}
finally
{
System.IO.File.WriteAllText("/path-to-app/_main-finally.txt", "Line 1");
}
}
}
由於這是作為服務運行的,我們得出的結論是,將服務本身的最終確定包含在該范圍內實際上是有意義的,類似於 ASP.NET Core 應用程序通過僅在Program.cs
文件中提供服務來運行的方式並允許服務本身維護其依賴關系。
我的建議是在服務中包含盡可能多的內容,並讓Main
方法初始化它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.