簡體   English   中英

在 .NET Core 2 linux 守護進程中優雅地關閉通用主機

[英]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>后,會執行StopAsyncDispose方法,但不會執行其他任何操作:不會執行await之后的 in Mainfinally塊。

注意:我沒有使用 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM