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 个工作使用租约。
我目前有一个 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 个工作使用租约。