我如何安排 C# Windows 服务每天执行任务?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/503564/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 05:54:02  来源:igfitidea点击:

How might I schedule a C# Windows Service to perform a task daily?

c#windows-servicesschedulingscheduled-tasks

提问by ctrlalt3nd

I have a service written in C# (.NET 1.1) and want it to perform some cleanup actions at midnight every night. I have to keep all code contained within the service, so what's the easiest way to accomplish this? Use of Thread.Sleep()and checking for the time rolling over?

我有一个用 C# (.NET 1.1) 编写的服务,并希望它在每晚午夜执行一些清理操作。我必须保留服务中包含的所有代码,那么完成此任务的最简单方法是什么?使用Thread.Sleep()和检查时间滚动?

采纳答案by M4N

I wouldn't use Thread.Sleep(). Either use a scheduled task (as others have mentioned), or set up a timer inside your service, which fires periodically (every 10 minutes for example) and check if the date changed since the last run:

我不会使用 Thread.Sleep()。要么使用计划任务(正如其他人提到的那样),要么在您的服务中设置一个计时器,它会定期触发(例如每 10 分钟)并检查自上次运行以来日期是否更改:

private Timer _timer;
private DateTime _lastRun = DateTime.Now.AddDays(-1);

protected override void OnStart(string[] args)
{
    _timer = new Timer(10 * 60 * 1000); // every 10 minutes
    _timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
    _timer.Start();
    //...
}


private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    // ignore the time, just compare the date
    if (_lastRun.Date < DateTime.Now.Date)
    {
        // stop the timer while we are running the cleanup task
        _timer.Stop();
        //
        // do cleanup stuff
        //
        _lastRun = DateTime.Now;
        _timer.Start();
    }
}

回答by CubanX

The way I accomplish this is with a timer.

我完成此操作的方法是使用计时器。

Run a server timer, have it check the Hour/Minute every 60 seconds.

运行服务器计时器,让它每 60 秒检查一次小时/分钟。

If it's the right Hour/Minute, then run your process.

如果是正确的小时/分钟,则运行您的流程。

I actually have this abstracted out into a base class I call OnceADayRunner.

我实际上已经将它抽象为一个基类,我称之为OnceADayRunner。

Let me clean up the code a bit and I'll post it here.

让我稍微清理一下代码,然后将其发布在这里。

    private void OnceADayRunnerTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
        using (NDC.Push(GetType().Name))
        {
            try
            {
                log.DebugFormat("Checking if it's time to process at: {0}", e.SignalTime);
                log.DebugFormat("IsTestMode: {0}", IsTestMode);

                if ((e.SignalTime.Minute == MinuteToCheck && e.SignalTime.Hour == HourToCheck) || IsTestMode)
                {
                    log.InfoFormat("Processing at: Hour = {0} - Minute = {1}", e.SignalTime.Hour, e.SignalTime.Minute);
                    OnceADayTimer.Enabled = false;
                    OnceADayMethod();
                    OnceADayTimer.Enabled = true;

                    IsTestMode = false;
                }
                else
                {
                    log.DebugFormat("Not correct time at: Hour = {0} - Minute = {1}", e.SignalTime.Hour, e.SignalTime.Minute);
                }
            }
            catch (Exception ex)
            {
                OnceADayTimer.Enabled = true;
                log.Error(ex.ToString());
            }

            OnceADayTimer.Start();
        }
    }

The beef of the method is in the e.SignalTime.Minute/Hour check.

该方法的关键在于 e.SignalTime.Minute/Hour 检查。

There are hooks in there for testing, etc. but this is what your elapsed timer could look like to make it all work.

那里有用于测试等的钩子,但这就是您的经过计时器使其全部工作的样子。

回答by Ian Jacobs

Does it have to be an actual service? Can you just use the built in scheduled tasks in the windows control panel.

它必须是一个实际的服务吗?您可以只使用 Windows 控制面板中的内置计划任务吗?

回答by Marc Gravell

A daily task? Sounds like it should just be a scheduled task (control panel) - no need for a service here.

日常任务?听起来它应该只是一个计划任务(控制面板)——这里不需要服务。

回答by jeremcc

Check out Quartz.NET. You can use it within a Windows service. It allows you to run a job based on a configured schedule, and it even supports a simple "cron job" syntax. I've had a lot of success with it.

查看Quartz.NET。您可以在 Windows 服务中使用它。它允许您根据配置的计划运行作业,它甚至支持简单的“cron 作业”语法。我已经取得了很多成功。

Here's a quick example of its usage:

这是其用法的快速示例:

// Instantiate the Quartz.NET scheduler
var schedulerFactory = new StdSchedulerFactory();
var scheduler = schedulerFactory.GetScheduler();

// Instantiate the JobDetail object passing in the type of your
// custom job class. Your class merely needs to implement a simple
// interface with a single method called "Execute".
var job = new JobDetail("job1", "group1", typeof(MyJobClass));

// Instantiate a trigger using the basic cron syntax.
// This tells it to run at 1AM every Monday - Friday.
var trigger = new CronTrigger(
    "trigger1", "group1", "job1", "group1", "0 0 1 ? * MON-FRI");

// Add the job to the scheduler
scheduler.AddJob(job, true);
scheduler.ScheduleJob(trigger);

回答by GWLlosa

I would suggest that you use a timer, but set it to check every 45 seconds, not minute. Otherwise you can run into situations where with heavy load, the check for a particular minute is missed, because between the time the timer triggers and the time your code runs and checks the current time, you might have missed the target minute.

我建议您使用计时器,但将其设置为每 45 秒检查一次,而不是每分钟检查一次。否则,您可能会遇到负载很重的情况,会错过特定分钟的检查,因为在计时器触发的时间和您的代码运行并检查当前时间的时间之间,您可能已经错过了目标分钟。

回答by Treb

As others already wrote, a timer is the best option in the scenario you described.

正如其他人已经写的那样,计时器是您描述的场景中的最佳选择。

Depending on your exact requirements, checking the current time every minute may not be necessary. If you do not need to perform the action exactlyat midnight, but just within one hour after midnight, you can go for Martin's approachof only checking if the date has changed.

根据您的确切要求,可能不需要每分钟检查一次当前时间。如果您不需要恰好在午夜执行操作,而是在午夜后的一小时内执行操作,则可以采用Martin 的方法,只检查日期是否已更改。

If the reason you want to perform your action at midnight is that you expect a low workload on your computer, better take care: The same assumption is often made by others, and suddenly you have 100 cleanup actions kicking off between 0:00 and 0:01 a.m.

如果您想在午夜执行操作的原因是您希望计算机上的工作负载较低,请更好地注意:其他人经常做出相同的假设,并且突然之间您有 100 个清理操作在 0:00 和 0 之间启动:01 上午

In that case you should consider starting your cleanup at a different time. I usually do those things not at clock hour, but at half hours (1.30 a.m. being my personal preference)

在这种情况下,您应该考虑在不同的时间开始清理。我通常不是在时钟时间做这些事情,而是在半小时(1.30 am 是我个人的喜好)

回答by Shailendra Tiwari

Try this:

尝试这个:

public partial class Service : ServiceBase
{
    private Timer timer;
    public Service()
    {
        InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
        SetTimer();
    }

    private void SetTimer()
    {
        if (timer == null)
        {
            timer = new Timer();
            timer.AutoReset = true;
            timer.Interval = 60000 * Convert.ToDouble(ConfigurationManager.AppSettings["IntervalMinutes"]);
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            timer.Start();
        }
    }

    private void timer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
    {
        //Do some thing logic here
    }

    protected override void OnStop()
    {
        // disposed all service objects
    }
}

回答by Samuel

You can also try the TaskSchedulerLibrary here http://visualstudiogallery.msdn.microsoft.com/a4a4f042-ffd3-42f2-a689-290ec13011f8

您也可以在这里尝试 TaskSchedulerLibrary http://visualstudiogallery.msdn.microsoft.com/a4a4f042-ffd3-42f2-a689-290ec13011f8

Implement the abstract class AbstractScheduledTaskand call the ScheduleUtilityFactory.AddScheduleTaskToBatchstatic method

实现抽象类AbstractScheduledTask并调用ScheduleUtilityFactory.AddScheduleTaskToBatch静态方法

回答by Fandango68

For those that found the above solutions not working, it's because you may have a thisinside your class, which implies an extension method which, as the error message says, only makes sense on a non-generic static class. Your class isn't static. This doesn't seem to be something that makes sense as an extension method, since it's acting on the instance in question, so remove the this.

对于那些发现上述解决方案不起作用的人,这是因为您this的类内部可能有一个,这意味着一个扩展方法,正如错误消息所说,只有在非通用静态类上才有意义。你的课程不是静态的。这似乎不是作为扩展方法有意义的东西,因为它作用于有问题的实例,因此删除this.