【问题标题】:.NET Core BackgroundService Run Only Once.NET Core BackgroundService 只运行一次
【发布时间】:2021-01-15 02:01:15
【问题描述】:

我正在创建一个 .net 核心 BackgroundService 控制台应用程序。默认模板提供了一个带有 ExecuteAsync() 方法的 Worker 类,非常棒。

我的计划是使用 Windows 任务计划程序来安排每天执行一次控制台应用程序。但是,我意识到 ExecuteAsync() 是一个连续执行的方法。所以我的问题是——我如何只执行一次 ExecuteAsync() 中的代码然后终止 Worker?我可能还有其他进程仍在运行,因此每个单独的进程都需要运行一次并自行终止。

或者BackgroundService不是我的最佳选择?

【问题讨论】:

    标签: .net .net-core background-service


    【解决方案1】:

    FlashOver 的答案是正确的——ExecuteAsync 被调用了一次。不重复。

    如果您想在 IHostedService 中的特定时间发生某些事情,请阅读 Microsoft 的 this article

    我会把代码贴在这里,以防链接失效:

    public class TimedHostedService : IHostedService, IDisposable
    {
        private int executionCount = 0;
        private readonly ILogger<TimedHostedService> _logger;
        private Timer _timer;
    
        public TimedHostedService(ILogger<TimedHostedService> logger)
        {
            _logger = logger;
        }
    
        public Task StartAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation("Timed Hosted Service running.");
    
            _timer = new Timer(DoWork, null, TimeSpan.Zero, 
                TimeSpan.FromSeconds(5));
    
            return Task.CompletedTask;
        }
    
        private void DoWork(object state)
        {
            var count = Interlocked.Increment(ref executionCount);
    
            _logger.LogInformation(
                "Timed Hosted Service is working. Count: {Count}", count);
        }
    
        public Task StopAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation("Timed Hosted Service is stopping.");
    
            _timer?.Change(Timeout.Infinite, 0);
    
            return Task.CompletedTask;
        }
    
        public void Dispose()
        {
            _timer?.Dispose();
        }
    }
    

    这样注入:

    services.AddHostedService<TimedHostedService>();
    

    现在,请记住,如果您的应用程序在您拥有多个实例的情况下水平扩展,那么您将运行多个计时器。这通常不是一件好事。

    如果我需要在一天中的特定时间运行任务,我会使用设置为 CRON 作业的 Azure 函数。

    【讨论】:

      【解决方案2】:

      恐怕你弄错了: 已注册的BackgroundServiceExecuteAsync(CancellationToken) 仅由您通过dotnet new worker 模板使用的.NET Generic Host 执行一次。

      抽象类BackgroundService 是“用于实现长期运行IHostedService 的基类”。 当遇到await 运算符时,它会调用您的覆盖 ExecuteAsync(CancellationToken) 实现并将控制权交给Host。 这使得另一个IHostedServiceStartAsync(CancellationToken) 在您的BackgroundService.ExecuteAsync(CancellationToken) 运行完成之前在启动期间被调用。 同样,这也可以在关闭期间调用另一个 IHostedServiceStopAsync(CancellationToken),然后优雅地取消您的 BackgroundService.ExecuteAsync(CancellationToken)

      注意Worker Service-Template 中的“repeat-until-your-BackgroundService-is-stopped”循环

      while (!stoppingToken.IsCancellationRequested)
      {...}
      

      代表长期运行的服务。

      如果您的计划工作是您的应用程序中唯一的 IHostedService 和/或它实际上不是一个长期运行的服务 - 它似乎不是每天执行时 - 而不是源自 @987654344 @,你可以直接实现IHostedService,将你的逻辑添加到StartAsync,并通过AddHostedService注册。

      当您的工作完成后,您想通过IHostApplicationLifetime.StopApplication() 关闭您的应用程序主机。 为此,您可以通过Constructor Injection 访问IHostApplicationLifetime,然后在StartAsync 结束您的日常操作后拨打StopApplication()。 由Host.CreateDefaultBuilder 创建的HostBuilder 已经添加了一个Singleton ApplicationLifetime

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-07-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-13
        相关资源
        最近更新 更多