代码之家  ›  专栏  ›  技术社区  ›  ctrlalt3nd

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

  •  79
  • ctrlalt3nd  · 技术社区  · 16 年前

    我有一个用C(.NET 1.1)编写的服务,希望它每晚午夜执行一些清理操作。我必须将所有代码都包含在服务中,那么实现这一点最简单的方法是什么?使用 Thread.Sleep() 然后检查时间的变化?

    10 回复  |  直到 7 年前
        1
  •  85
  •   Community CDub    10 年前

    我不会使用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();
        }
    }
    
        2
  •  69
  •   jeremcc chris    16 年前

    退房 Quartz.NET .您可以在Windows服务中使用它。它允许您基于配置的调度运行一个作业,甚至支持一个简单的“cron job”语法。我已经取得了很大的成功。

    下面是它的一个使用示例:

    // 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);
    
        3
  •  20
  •   Marc Gravell    16 年前

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

        4
  •  15
  •   Ian Jacobs    16 年前

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

        5
  •  3
  •   CubanX    16 年前

    我用计时器来完成这项工作。

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

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

    实际上,我把它抽象成了一个我称为OncedayRunner的基类。

    让我把代码整理一下,然后贴在这里。

        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();
            }
        }
    

    方法的要点在e.signalTime.minute/hour检查中。

    在那里有一些钩子用于测试等等,但是这就是您经过的计时器可以让它全部工作的样子。

        6
  •  2
  •   Community CDub    8 年前

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

    根据您的具体要求,可能不需要每分钟检查当前时间。 如果不需要执行操作 确切地 在午夜,但在午夜后一小时内,你可以去 Martin's approach 只检查日期是否更改。

    如果你想在午夜执行你的操作的原因是你期望你的计算机工作负荷很低,那么最好小心:同样的假设通常是由其他人做出的,突然你有100个清理操作在凌晨0:00到0:01之间启动。

    在这种情况下,您应该考虑在不同的时间开始清理。我通常不在上班时间做这些事情,而是在半小时内做(我个人喜欢凌晨1点30分)

        7
  •  1
  •   GWLlosa    16 年前

    我建议你用一个计时器,但把它设置为每45秒检查一次,而不是每分钟。否则,您可能会遇到这样的情况:在重载情况下,会错过对特定分钟的检查,因为在计时器触发的时间和代码运行和检查当前时间之间,您可能错过了目标分钟。

        8
  •  0
  •   Liam Joshua    7 年前

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

    实现抽象类 AbstractScheduledTask 打电话给 ScheduleUtilityFactory.AddScheduleTaskToBatch 静态法

        9
  •  0
  •   Fandango68    7 年前

    对于那些发现上述解决方案不起作用的人,这是因为 this 在类内部,这意味着一个扩展方法,正如错误消息所说,它只对非泛型静态类有意义。你的课不是静态的。这似乎不是一个有意义的扩展方法,因为它作用于相关实例,所以移除 .

        10
  •  -2
  •   Robert Mars_win    11 年前

    试试这个:

    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
        }
    }