ASP.NET Core BackgroundService 运行了几次

ASP.NET Core BackgroundService runs several times

我目前有一个 ASP.NET 带有 .NET Core SDK v5.0.403 的核心应用程序。

在这个应用程序中,我定义了几个 BackgroundService,其中之一是:

public class DueDateNotificationService : BackgroundService
{
    private readonly ILogger _logger;
    private readonly IServiceScopeFactory _serviceProvider;

    private readonly int _actionDueDateGenerationDelay;
    private readonly int _startupDelayInSeconds;

    protected static int instances = 0;

    public DueDateNotificationService(ILogger<DueDateNotificationService> logger,
        IServiceScopeFactory serviceProvider,
        IConfiguration configuration)
    {
        _logger = logger;
        _serviceProvider = serviceProvider;

        _actionDueDateGenerationDelay = configuration["BackgroundServices:DueDateNotificationService:DueDateGenerationDelay"].ToInt(240);
        _startupDelayInSeconds = Math.Max(configuration["BackgroundServices:DueDateNotificationService:StartupDelayInSeconds"].ToInt(), 60);
    }

    /// <summary>
    /// Service execution
    /// </summary>
    /// <param name="stoppingToken"></param>
    /// <returns></returns>
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // Adding basic data to the logging context
        using (LogContext.PushProperty("AppName", "Api-DueDateNotificationService"))
        {
            _logger.LogInformation("DueDateNotificationService Hosted Service is starting.");
            await Task.Delay(TimeSpan.FromSeconds(_startupDelayInSeconds), stoppingToken);

            
                while (!stoppingToken.IsCancellationRequested)
                {


                    try
                    {
                        using (var scope = _serviceProvider.CreateScope())
                        {
                            var service = scope.ServiceProvider.GetRequiredService<IMyService>();
                            _logger.LogInformation($"doing stuff");
                            service.DoStuff();

                        }
                        // waiting until we should check again
                        _logger.LogInformation($"Job finished at {DateTime.UtcNow}. Next job at {DateTime.UtcNow.AddMinutes(_actionDueDateGenerationDelay)}");
                        await Task.Delay(TimeSpan.FromMinutes(_actionDueDateGenerationDelay));
                    }
                    catch (TaskCanceledException)
                    {
                        _logger.LogWarning("The DueDateNotificationService Hosted Service was cancelled, likely because the site was shutdown (possibly due to inactivity or a force update)");
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, $"Error occurred executing the automated DueDateNotificationService service.");
                    }
                }
            
            _logger.LogInformation("DueDateNotificationService Hosted Service is stopping.");
        
    }
}

我的服务只添加到 DI 的一个地方,在 startup.cs:

EnableHostedService<DueDateNotificationService>(services, "BackgroundServices:DueDateNotificationService:Enabled");

EnabledHostedService 为:

private IServiceCollection EnableHostedService<T>(IServiceCollection services, string configurationKey) where T : class, IHostedService
        {
            // Background services to run
            if (Configuration[configurationKey].Equals("true", StringComparison.OrdinalIgnoreCase))
            {
                return services.AddHostedService<T>();
            }

            return services;
        }

这是我唯一注册后台服务的地方,除了默认提供的以外,应用程序中没有任何 autofac 或自定义 DI。

我的问题是,每当我的应用托管在 Azure 应用服务中时,所有后台服务都会同时 运行 多次。

当我查看日志时,

DueDateNotificationService Hosted Service is starting.

至少显示两次,我的 while 循环中的所有日志也是如此(我在此处删除以减轻 post)。

但是当我在本地调试它时,它只 运行 一次,这是应该的。

当我评论我的注册行时,它根本没有启动(即使在 Azure 上)。

它从何而来?

谢谢

更新 我什至尝试过类似的东西:

protected static int instances = 0;
                ....
                Interlocked.Increment(ref instances);
                if (instances > 1)
                {
                    _logger.LogInformation("An instance of DueDateNotificationService is already started.");
                }
                else
                {
                     MyWhileLoop();
                }

还是启动/执行了几次,日志如下:

An instance of DueDateNotificationService is already started.

从未出现。

azure app service

这几乎可以肯定是由于您的应用程序有多个实例运行。

What would be the safest way to have the backgroundservice running only once, beside going through some data persist / check in DB?

外部“租约”是最安全的方法。您可以使用 CosmosDb/Redis 作为后端自行构建一个,或者您可以使用 built-in 方法,将您的后台服务从您的 Web 应用程序分解为 Azure WebJob 或 Azure Functions。这两项服务都自​​动为 timer-triggered 个工作使用租约。