【问题标题】:How to start BackgroundService in ASP.Net core 3.1 API如何在 ASP.Net core 3.1 API 中启动 BackgroundService
【发布时间】:2021-08-13 09:35:37
【问题描述】:

我已尝试关注this tutorial,了解如何创建后台工作人员。

大部分内容对我没有用,所以我没有包括在内。我不需要排队。我只需要让这个后台工作人员每 X 小时在后台运行一次 我的工人看起来像这样。不幸的是,它似乎从不调用 ExecuteAsync 方法

public class EnergySolutionBackgroundWorker : BackgroundService
{       
    private readonly ILogger<EnergySolutionBackgroundWorker> _logger;

    public EnergySolutionBackgroundWorker(ILogger<EnergySolutionBackgroundWorker> logger)
    {         
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("{Type} is now running in the background.", nameof(BackgroundWorker));

        await BackgroundProcessing(stoppingToken);
    }

    public override Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogCritical("The {Type} is stopping due to a host shutdown.", nameof(BackgroundWorker));

        return base.StopAsync(cancellationToken);
    }

    private async Task BackgroundProcessing(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                await Task.Delay(new TimeSpan(0, 0, 1), stoppingToken);

                // Doing some tasks
            }
            catch (Exception ex)
            {
                _logger.LogCritical("An error occurred when publishing a book. Exception: {@Exception}", ex);
            }
        }
    }        
}

在 Startup.cs 我有以下内容:

public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();

        services.AddHostedService<EnergySolutionBackgroundWorker>();
    }

据我了解,这应该足以让它在启动期间自动启动后台工作程序,但事实并非如此。我做错了什么?

【问题讨论】:

  • “它似乎从不调用 ExecuteAsync 方法” 这条消息是否记录在"{Type} is now running in the background."
  • 我刚刚尝试了您的代码,它运行良好。 // Doing some tasks 可能有问题
  • 我看不到任何地方记录的消息。那不是在输出窗口中吗?我还尝试在 ExecuteAsync 方法中添加一些代码,它应该写入 C:\Temp 中的简单 txt 文件,但它也没有这样做

标签: c# asp.net-core asp.net-web-api


【解决方案1】:
  1. 您可以在启动功能中添加计时器。 定时后台任务使用 System.Threading.Timer 类。计时器触发任务的 DoWork 方法。计时器在 StopAsync 上禁用,并在服务容器在 Dispose 上释放时释放:
internal class TimedHostedService : IHostedService, IDisposable
{
    private readonly ILogger _logger;
    private Timer _timer;

    public TimedHostedService(ILogger<TimedHostedService> logger)
    {
        _logger = logger;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Timed Background Service is starting.");

        _timer = new Timer(DoWork, null, TimeSpan.Zero, 
            TimeSpan.FromSeconds(5));

        return Task.CompletedTask;
    }

    private void DoWork(object state)
    {
        _logger.LogInformation("Timed Background Service is working.");
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Timed Background Service is stopping.");

        _timer?.Change(Timeout.Infinite, 0);

        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }
}
  1. 有一个reference

【讨论】:

  • 不过,定时器不能异步工作。它在等待时不会将线程释放到线程池。
  • @abdusco 一个计时器异步的。事实上,Task.Delay 在内部使用计时器来发送 TaskCompletionSource 信号。回调可以是async void
【解决方案2】:

我相信我找到了答案!在第一次调用 API 之前不会运行 Startup.cs。在我的一个控制器中调用一个简单的测试方法后,调用了 BackgroundProcessing 方法 这有点烦人,因为我希望以后可以创建一个后台工作程序,将大量数据加载到内存中,而不是在第一次调用时发生

【讨论】:

  • 那是你的代码中的一个错误。 Startup.cs 用于配置 API。根据定义,这发生在 API 甚至可以接收单个请求之前。 BackgroundService 是一个单例,因此它确实在任何请求之前启动。这并不意味着它在完成之前阻塞请求。如果你的 BackgroundService 启动代码太慢,可能在第一个 API 请求到达之前它还没有完成
  • 这是有道理的。不幸的是,我看不到我可能做错了什么,因为在我发出第一个请求之前没有调用 Program.Main。
  • await Task.Delay 保证某些请求将在循环运行之前到达。至少,延迟第一次执行之后。或者使用计时器
  • 我明白你在说什么,在上面提到的场景中,我应该在第一次请求之前加载一些数据,我需要等到加载数据之后。我目前正在处理的后台工作人员只需要每天午夜后的某个时间运行。但问题仍然是 Program.Main 直到调用第一个请求之后才被调用。因此,即使我将 Task.Delay 代码推到执行后,它仍然不会在第一个请求发出之前被调用。而且由于我的任何代码都没有在 Program.Main 之前运行,因此我的代码中的任何错误都不会导致这种情况
  • 如果您想在第一次请求之前加载数据,请在Startup 中进行,并且绝对在调用.Run() 之前之前。仅使用后台服务刷新数据。如果您使用 ASP.NET Core 的 IMemoryCache,请检查 How do I put data in a MemoryCache on startup?。可以在Configure方法中添加初始数据
猜你喜欢
  • 1970-01-01
  • 2019-03-24
  • 2020-12-06
  • 2022-12-01
  • 1970-01-01
  • 2022-07-06
  • 2020-12-07
  • 1970-01-01
  • 2019-05-12
相关资源
最近更新 更多