问题描述
Microsoft永久/连续 IHostedService
的示例,位于使用而
+ Task.Delay
样式。
这用简化的代码片段在下面说明。
Microsoft's example for a forever/continous IHostedService
at Implement background tasks in microservices with IHostedService and the BackgroundService class uses while
+Task.Delay
'pattern'. This illustrated with a code snippet that a simplified version is just below.
public class GracePeriodManagerService : BackgroundService
(...)
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
//Do work
await Task.Delay(timeSpan, stoppingToken);
}
}
这种模式正经历着缓慢的转变-工作是每 timeSpan
+ how_long_work_took
完成一次。即使 how_long_work_took
在一段时间内非常小,它也会累加起来。
This pattern suffers from a creeping shift - the work is done every timeSpan
+how_long_work_took
. Even when how_long_work_took
is very small over a period of time it adds up.
我想避免根据工作时间$ c计算
timeSpan
$ c>。
I would like to avoid calculating timeSpan
based on how long work
took.
每运行 fixed_amount_of_time 的健壮解决方案是什么?
What would a robust solution be to run every fixed_amount_of_time?.
大声考虑:如果我使用任务计划程序库,例如确实使用了 IHostedService
/ BackgroundService
甚至有意义吗?
Thinking out loud: If I use a task scheduler library, like HangFire, inside ExecuteAsync
does using IHostedService
/BackgroundService
even make sense any more?
奖励是能够在某个时间点(例如,午夜)运行任务
A bonus would be to be able to run a task at a point in time (e.g. at midnight)
推荐答案
这就是我处理此类问题的方式...就我而言,我需要在特定的日期,特定的时间启动服务,并每隔x天重复一次。但是我不知道这是否正是您要寻找的东西:)
This is how I handle such thing... In my case I need to start the service on specific day, specific hour and repeat every x days. But I don't know if it's what are you looking for exactly :)
public class ScheduleHostedService: BackgroundService
{
private readonly ILogger<ScheduleHostedService> _logger;
private readonly DaemonSettings _settings;
public ScheduleHostedService(IOptions<DaemonSettings> settings, ILogger<ScheduleHostedService> logger)
{
_logger = logger;
_settings = settings.Value;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
DateTime? callTime=null;
if (_settings.StartAt.HasValue)
{
DateTime next = DateTime.Today;
next = next.AddHours(_settings.StartAt.Value.Hour)
.AddMinutes(_settings.StartAt.Value.Minute)
.AddSeconds(_settings.StartAt.Value.Second);
if (next < DateTime.Now)
{
next = next.AddDays(1);
}
callTime = next;
}
if (_settings.StartDay.HasValue)
{
callTime = callTime ?? DateTime.Now;
callTime = callTime.Value.AddDays(-callTime.Value.Day).AddDays(_settings.StartDay.Value);
if (callTime < DateTime.Now)
callTime = callTime.Value.AddMonths(1);
}
if(callTime.HasValue)
await Delay(callTime.Value - DateTime.Now, stoppingToken);
else
{
callTime = DateTime.Now;
}
while (!stoppingToken.IsCancellationRequested)
{
//do smth
var nextRun = callTime.Value.Add(_settings.RepeatEvery) - DateTime.Now;
await Delay(nextRun, stoppingToken);
}
}
static async Task Delay(TimeSpan wait, CancellationToken cancellationToken)
{
var maxDelay = TimeSpan.FromMilliseconds(int.MaxValue);
while (wait > TimeSpan.Zero)
{
if (cancellationToken.IsCancellationRequested)
break;
var currentDelay = wait > maxDelay ? maxDelay : wait;
await Task.Delay(currentDelay, cancellationToken);
wait = wait.Subtract(currentDelay);
}
}
}
我写了Delay函数来处理延迟时间超过28天。
I wrote Delay function to handle delays longer that 28 days.
这篇关于IHostedService / BackgroundService按计划运行(与Task.Delay相对)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!