簡體   English   中英

Windows 服務使用.net核心BackgroundService,如何優雅停止?

[英]Windows Service using .net core BackgroundService, how to gracefully stop?

我正在使用 .Net Core 3.1 開發 windows 服務

許多在線資源建議我為此使用BackgroundService 問題是我無法通過重寫ExecuteAsync方法正常停止服務。

用於測試的代碼設置非常簡單:

public class MyService: BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        Console.WriteLine($"Service started at {DateTimeOffset.Now}");
        await DoLongRunningWork(stoppingToken);
    }

    public override async Task StopAsync(CancellationToken cancellationToken)
    {
        Console.WriteLine("Service is being stopped...");
        await base.StopAsync(cancellationToken);
        Console.WriteLine("Service stopped at {DateTimeOffset.Now}");
    }

    private static async Task DoLongRunningWork(CancellationToken token)
    {
        Console.WriteLine("I'm working...");
        while (!token.IsCancellationRequested)
        {
            Console.WriteLine($"\t... doing work ...");
            await Task.Delay(1000, token);
        }

        // THE BELOW LINE IS NEVER REACHED. i.e The line "Cancel requested? True" is never logged out...
        Console.WriteLine($"Cancel requested? {token.IsCancellationRequested}");
    }
}

Main方法


static void Main(string[] args)
{
    Console.WriteLine("Starting My Service...");
    Host.CreateDefaultBuilder(args)
        .UseWindowsService()
        .ConfigureServices(services =>
        {
            services.AddHostedService<MyService>();
        })
        .Build()
        .Run();
}

我可以做的一件事是實現我自己的Stop方法並在我的覆蓋StopAsync中調用它。 但我很好奇為什么這個簡單的設置沒有按預期工作。

我已經閱讀了BackgroundService.cs源代碼,它看起來應該按我預期的方式工作(即這一行Cancel requested? True應該被注銷,但它沒有......

我試過將它作為控制台應用程序運行並使用Ctrl+C停止它,以及將它安裝為 Windows 服務並使用service.msc來控制它。 相同的行為(即沒有正常關機......)

非常感謝任何幫助!

我忘記了這么久。 當我回到它時,我發現了問題......這只是一個混亂

這條特別的線

await Task.Delay(1000, token);

將拋出TaskCancelledException因此循環將退出該方法將停止... @Jeremy Lakeman 確實對此發表了評論,但當時我沒有想通我猜...

我只需要小心使用帶有取消令牌的await Task.Delay(..., token) ...

所以,我創建了一個簡單的擴展

    public static async Task SafeDelay(this Task source)
    {
        try
        {
            await source;
        }
        catch (TaskCanceledException)
        {
            // I don't want a throw on TaskCanceledException...
        }
    }
    private static async Task DoLongRunningWork(CancellationToken token)
    {
        Console.WriteLine("I'm working...");
        while (!token.IsCancellationRequested)
        {
            Console.WriteLine($"\t... doing work ...");
            
            // I simply want the loop to keep running, I don't want an absurd stop...
            await Task.Delay(1000, token).SafeDelay();
        }

        // This line is now reached...
        Console.WriteLine($"Cancel requested? {token.IsCancellationRequested}");
    }

在按照官方示例進行操作時,我遇到了同樣的問題,捕捉到TaskCanceledException就成功了,這是我的代碼現在的樣子:

public class Worker : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Started");

        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                await Task.Delay(60000, stoppingToken);
            }
            catch (TaskCanceledException)
            {
                continue;
            }
        }

        _logger.LogInformation("Stopped");
    }
}

我現在收到“已停止”日志:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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