簡體   English   中英

BackgroundService Graceful Shutdown - 完成工作並寫入數據庫

[英]BackgroundService Graceful Shutdown - Complete work and write to DB

我有一個實現 BackgroundService(由 MS 提供)的后台工作人員。

看這個簡單的實現:

public class MyService : BackgroundService {

    private readonly MyDbContext _context;

    public MyService(MyDbContext context) {
        //...
    }
    
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        try {
            while (true)
            {
                stoppingToken.ThrowIfCancellationRequested();
                // Do some work
            }
        } catch(OperationCancelledException) {
            _context.Add(new MyLogMessage(){ Error = "MyService cancelled!" });
            _context.SaveChanges();
        }
        // ...
    }
}

當請求正常關閉(在控制台中:CTRL+C)時,觸發了 catch 塊,並且SaveChanges()似乎也被執行了。 但是,有時錯誤會存儲到數據庫中,而大多數情況下不會。 EntityFramework 也在控制台上打印插入語句,但日志不在數據庫中。 我假設關閉速度比將數據寫入數據庫更快? 誰能給我一個提示如何處理這種情況並將錯誤存儲到數據庫中?

當應用程序關閉時,似乎stoppingToken沒有按預期取消。 我設法使用IHostApplicationLifetime和一個新字段來解決這個問題,如果正在進行關機,我可以在其中存儲。

public class TestService : BackgroundService {
    private readonly IHostApplicationLifetime _lifetime;
    private readonly ILogger<TestService> _logger;

    private bool _shutownRequested;

    public TestService(IHostApplicationLifetime lifetime, ILogger<TestService> logger) {
        _lifetime = lifetime;
        _logger = logger;
    }

    public override Task StartAsync(CancellationToken cancellationToken) {
        _lifetime.ApplicationStopping.Register(OnShutdown);
        return Task.CompletedTask;
    }

    private void OnShutdown() {
        _shutdownRequested = true;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
        try {
            while(true) {
                stoppingToken.ThrowIfCancellationRequested();
                if(_shutdownRequested) {
                    throw new OperationCanceledException();
                }

                await Task.Delay(100, CancellationToken.None);
            }
        } catch(OperationCanceledException) {
            _logger.LogWarning("TestService canceled");
        }
    }
}

現在最好現在在那里拋出一個新的異常,但作為一個例子,它會這樣做。

日志條目沒有出現在數據庫中的原因是主機關閉時間低於在while循環中處理任務並將日志發送到數據庫所需的時間。 默認超時為 5 秒。

您可以做的是將超時增加到更大的值,例如一分鍾一兩:

services.Configure<HostOptions>(
    opts => opts.ShutdownTimeout = TimeSpan.FromMinutes(2));

確保讓服務有足夠的時間在while循環內完成迭代並記錄消息。

請檢查擴展關閉超時設置以確保 IHostedService 正常關閉以了解更多詳細信息。

暫無
暫無

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

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