.Net Core 上的计划任务 [英] Scheduled task on .Net Core

查看:36
本文介绍了.Net Core 上的计划任务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要将几个计划任务从 widows 服务器的 Scheduler 任务转换为使用 .Net 的独立应用程序.

I need to convert a couple of scheduled tasks from the Scheduler task of widows server to a standalone application using .Net.

过去我在 .Net framework 4.x 上使用过 Quartz,但在基于不同调度程序的多个长时间运行的任务时遇到了一些小问题.

In the past I've used Quartz on .Net framework 4.x, having some small issue with multiple long running tasks based on different schedulers.

现在我正在使用 .Net 5,我想知道是否有一种新的方法来安排任务,比如工作人员服务,或者使用 Quartz.Net 仍然更好、更灵活.

Now I'm using .Net 5 and I'm wondering if there is a new way to schedule tasks, like the worker service or it's still better and more flexible to use Quartz.Net.

由于我需要运行长时间的任务,从 30 秒到 2 小时,我需要创建一个定时后台任务,使用 System.Threading.Timer

Since I need to run long time tasks, from 30s to 2 hrs, I need to create a timed background task, using System.Threading.Timer

代码应该如下:

    public Task StartAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Timed Hosted Service running.");

        _timer = new Timer(DoSomething, null, TimeSpan.Zero, 
            TimeSpan.FromHours(24));

        return Task.CompletedTask;
    }

它应该每 24 小时调用一次 DoSomething.

and it should call DoSomething every 24 hrs.

我的疑问是:

  • 它什么时候开始工作并计算 24 小时,当我第一次运行时应用程序?
  • 我怎么能说任务必须在一天中的特定时间,例如午夜?
  • Worker Service 是否适合管理计划任务?

推荐答案

当我第一次运行应用程序时,它什么时候开始工作并计算 24 小时?

When does it start to work and to count the 24hrs, when I first run the application?

是的.设置断点并启动您的应用程序.你会看到它点燃的速度有多快.

Yes. Set a breakpoint and start your application. You'll see how quickly it fires.

Worker Service 是否适合管理计划任务?

Is the Worker Service suitable for managing scheduled tasks?

是的.

如何说任务必须在一天中的特定时间运行,例如午夜?

How can I say that the task must be run at a specific time in a day, at midnight for example?

我们来看看这段代码:

public sealed class MyTimedBackgroundService : BackgroundService
{

    private static int SecondsUntilMidnight()
    {
        return (int)(DateTime.Today.AddDays(1.0) - DateTime.Now).TotalSeconds;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        var countdown = SecondsUntilMidnight();

        while (!stoppingToken.IsCancellationRequested)
        {
            if (countdown-- <= 0)
            {
                try
                {
                    await OnTimerFiredAsync(stoppingToken);
                }
                catch(Exception ex)
                {
                    // TODO: log exception
                }
                finally
                {
                    countdown = SecondsUntilMidnight();
                }
            }
            await Task.Delay(1000, stoppingToken);
        }
    }

    private async Task OnTimerFiredAsync(CancellationToken stoppingToken)
    {
        // do your work here
        Debug.WriteLine("Simulating heavy I/O bound work");
        await Task.Delay(2000, stoppingToken);
    }
}

这根本不使用 System.Threading.Timer 以防您担心由于某些边界而不会真正触发计时器.有些人对此感到偏执.我从来没有遇到过这种情况.我经常使用 Timer 来处理这种类型的工作.

This doesn't use System.Threading.Timer at all incase you are worried about the timer never actually firing off because of some boundary. Some people are paranoid of this. I have never had that happen to me. And I use Timer a lot for this type of work.

它将计算到午夜的秒数,然后循环直到到达那里.

It will calculates the number of seconds until midnight then loop until it gets there.

这是一个不可重入的计时器,由于处理延迟的业务逻辑,会有轻微的时间滑移.

This is a non-reentrant timer and there will be slight time slippage due to the business logic for processing the delay.

这是另一个使用 System.Threading.Timer 的例子:

Here is another example using System.Threading.Timer:

public sealed class MyTimedBackgroundService : IHostedService
{
    private Timer _t;

    private static int MilliSecondsUntilMidnight()
    {
        return (int)(DateTime.Today.AddDays(1.0) - DateTime.Now).TotalMilliseconds;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        // set up a timer to be non-reentrant
        _t = new Timer(async _ => await OnTimerFiredAsync(cancellationToken),
            null, MilliSecondsUntilMidnight(), Timeout.Infinite);
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _t?.Dispose();
        return Task.CompletedTask;
    }

    private async Task OnTimerFiredAsync(CancellationToken cancellationToken)
    {
        try
        {
            // do your work here
            Debug.WriteLine("Simulating heavy I/O bound work");
            await Task.Delay(2000, cancellationToken);
        }
        finally
        {
            // set timer to fire off again
            _t?.Change(MilliSecondsUntilMidnight(), Timeout.Infinite);
        }
    }
}

(此代码未经测试,可能存在一些拼写/语法错误)

这是一个不可重入的计时器,这意味着如果它当前正在处理数据,您可以保证它不会再次触发.

This is a non-reentrant timer meaning you are guaranteed that it will not fire off again if it's currently processing data.

它将计算到午夜的毫秒数,然后根据该计算设置一个计时器.

It will calculates the number of milliseconds until midnight then set a timer based on that calculation.

这个想法被采纳了来自微软.

这两个例子都可以这样注入:

Both of these examples can be injected as so:

services.AddHostedService<MyTimedBackgroundService>();

云原生警告:

请记住,由于这些示例对于您的应用程序而言是本地的,如果您的应用程序在运行多个实例的情况下横向扩展,您将运行两个或更多个计时器,只是在单独的进程.只是一个善意的提醒.如果您的应用程序永远无法扩展,请忽略此警告.

Keep in mind that since these examples are local to your application, that if your application scales up horizontally where you have more than one instance running, you will be running two or more timers, just in separate processes. Just a friendly reminder. If your application will never scale, then ignore this warning.

这篇关于.Net Core 上的计划任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆