首页 > 解决方案 > 在 ASP.NET Core 3.1 中,如何在未来的特定日期和时间安排具有托管服务的后台任务(Cron 作业)?

问题描述

我正在开发一个基于 ASP.NET Core 3.1 的项目,我想向它添加一个特定的功能,以安排将来在帖子作者指定的日期和时间发布帖子(类似于 Wordpress 通过它的 cron 工作)。例如,如果我们从用户那里收到这个日期和时间:

2020-09-07 14:08:07

那么,如何通过使用托管服务只运行一次并更改数据库中的标志并在此之后保存更改来为其安排后台任务?

我读过一些关于它的文章,但他们没有指定日期和时间,只是提到了每 5 秒重复的任务以及类似 cron 表达式的东西,但是,我需要知道的是如何安排后台任务特定日期和时间?

先感谢您。

标签: c#asp.net-corescheduled-tasksasp.net-core-hosted-services

解决方案


我将 CrontabSchedule 与 IHostedService 结合起来。下面的实现是轻量级的(没有架构强加库)并且没有轮询。

public class SomeScheduledService: IHostedService
{
    private readonly CrontabSchedule _crontabSchedule;
    private DateTime _nextRun;
    private const string Schedule = "0 0 1 * * *"; // run day at 1 am
    private readonly SomeTask _task;

    public SomeScheduledService(SomeTask task)
    {
        _task = Task;
        _crontabSchedule = CrontabSchedule.Parse(Schedule, new CrontabSchedule.ParseOptions{IncludingSeconds = true});
        _nextRun = _crontabSchedule.GetNextOccurrence(DateTime.Now);
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        Task.Run(async () =>
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                await Task.Delay(UntilNextExecution(), cancellationToken); // wait until next time

                await _task.Execute(); //execute some task

                _nextRun = _crontabSchedule.GetNextOccurrence(DateTime.Now);
            }
        }, cancellationToken);

        return Task.CompletedTask;
    }

    private int UntilNextExecution() => Math.Max(0, (int)_nextRun.Subtract(DateTime.Now).TotalMilliseconds);

    public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}

推荐阅读