簡體   English   中英

如何防止 .net 6 通用托管控制台應用程序日志記錄隊列在應用程序停止時被關閉?

[英]How to prevent .net 6 generic hosted console apps logging queue from being shutdown on application stop?

我目前正在為 do.net 控制台應用程序開發一個小型演示項目,使用通用托管進行日志記錄和配置。 在編寫這個演示/概念驗證應用程序的上下文中,我遇到了一個問題,控制台的日志消息停止寫入,但程序本身沒有問題地完成了他的工作。

這里的控制台應用程序應該進行批處理,而不是作為一個長期運行的服務。 我們打算找出是否(以及如何)以並行方式處理這些項目。 因此我們創建了這個演示程序。 在這個演示程序中,我們特意決定使用異步調用。 首先,使其盡可能線性,其次,使其盡可能易於理解。 在即將到來的迭代中,我們將添加/刪除此類功能,具體取決於我們探索的路徑和運行時行為。

這是我第一次體驗 do.net 6(+) 中的通用托管。 我想受益於 DI、配置和日志記錄等開箱即用的功能。

現在我的問題:

  • 對於 do.net 中的批處理控制台應用程序:通用托管環境是正確的方法嗎?
  • 對於批處理, IHostedService是正確的方法嗎? 我應該使用BackgroundService嗎?
  • 理想情況下:我如何控制應用程序,以便它等待console logger queue完成其工作?
  • 這是絕望的我問:我做錯了什么? 我錯過了哪個細節?

這是非常簡化的設置:

程序.cs

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

using var host = Host.CreateDefaultBuilder(args)
    .ConfigureLogging(logging =>
    {
        logging.ClearProviders();
        logging.AddConsole();
    })
    .ConfigureServices((_, services) =>
    {
        services.AddHostedService<Worker>();
    })
    .Build();

host.Start();
// host.Run(); // could be used instead of host.Start();

工人.cs

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

internal class Worker : IHostedService
{
    private readonly ILogger<Worker> _log;
    private readonly IHostApplicationLifetime _appLifetime;

    public Worker2(ILogger<Worker> log,
        IHostApplicationLifetime appLifetime
    ) => (_log, _appLifetime) = (log, appLifetime);

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _log.LogInformation("now load a list of item numbers");
        var itemNumbers = Enumerable.Range(1, 1000);

        foreach (var itemNumber in itemNumbers)
        {
            if (cancellationToken.IsCancellationRequested)
                break;
            _log.LogInformation("processing item nr {itemNumber}", itemNumber);
        }

        _log.LogInformation("I'm done here. good bye!");

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }
}

例如 output 到控制台

info: Worker2[0]
      now load a list of item numbers
info: Worker2[0]
      processing item nr 1
info: Worker2[0]
      processing item nr 2
info: Worker2[0]
      processing item nr 3
...
info: Worker2[0]
      processing item nr 22
info: Worker2[0]
      processing item nr 23
info: Worker2[0]
      processing item nr 24

Process finished with exit code 0.

調試這個簡單的應用程序時,它顯示它實際上運行了所有 1000 個項目,並且還記錄了最后一條消息(“我在這里完成了。再見。”),不幸的是。 來自項目 nr 的日志。 25 及以上永遠不會寫入控制台。

我發現了什么:

  • 該應用程序創建兩個主線程:一個用於worker線程,一個用於console logger queue
  • 我無法控制console logger queue線程
  • 如果我關閉worker (或它完成),它會關閉應用程序,並且應用程序不會等待console logger queue (因此會殺死它)。
  • 使用BackgroundService給我相同的結果。
  • 使用host.Run()而不是host.Start()確實有效,盡管我必須手動停止應用程序,這也不是我想要的。 當它完成它的工作時,它應該終止。

先感謝您!

我會將 app.Start 包裝在 try/catch/finally 中……並根據您是否使用 Serilog 之類的東西……在最后調用 Log.CloseAndFlush()。

此處類似的問題: How can I flush all loggers in a do.net core appliation just before doing a Environment.Exit()

暫無
暫無

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

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