Служба Windows для запуска функции в указанное время

Я хотел запустить службу Windows, чтобы запускать функцию каждый день в определенное время.

Какой метод я должен рассмотреть, чтобы реализовать это? Таймер или использование потоков?

6 ответов

Решение

(1) При первом запуске установите для параметра _timer.Interval значение в миллисекундах между временем запуска службы и расписанием. В этом примере время расписания установлено на 7:00: _scheduleTime = DateTime.Today.AddDays (1).AddHours (7);

(2) При значении Timer_Elapsed сбросьте _timer.Interval на 24 часа (в миллисекундах), если текущий интервал не равен 24 часам.

System.Timers.Timer _timer;
DateTime _scheduleTime; 

public WinService()
{
    InitializeComponent();
    _timer = new System.Timers.Timer();
    _scheduleTime = DateTime.Today.AddDays(1).AddHours(7); // Schedule to run once a day at 7:00 a.m.
}

protected override void OnStart(string[] args)
{           
    // For first time, set amount of seconds between current time and schedule time
    _timer.Enabled = true;
    _timer.Interval = _scheduleTime.Subtract(DateTime.Now).TotalSeconds * 1000;                                          
    _timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
}

protected void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    // 1. Process Schedule Task
    // ----------------------------------
    // Add code to Process your task here
    // ----------------------------------


    // 2. If tick for the first time, reset next run to every 24 hours
    if (_timer.Interval != 24 * 60 * 60 * 1000)
    {
        _timer.Interval = 24 * 60 * 60 * 1000;
    }  
}

Редактировать:

Иногда люди хотят запланировать запуск службы в день 0, а не завтра, поэтому они меняются DateTime.Today.AddDays(0).Если они делают это и устанавливают время в прошлом, это вызывает ошибку, устанавливая Интервал с отрицательным числом.

//Test if its a time in the past and protect setting _timer.Interval with a negative number which causes an error.
double tillNextInterval = _scheduleTime.Subtract(DateTime.Now).TotalSeconds * 1000;
if (tillNextInterval < 0) tillNextInterval += new TimeSpan(24, 0, 0).TotalSeconds * 1000;
_timer.Interval = tillNextInterval;

Вы уверены, что вам нужна служба, которая работает только один раз в день?

Может быть, Windows Task Schedule будет лучшим решением?

Хороший ответ (я использовал ваш код), но одна проблема с этой строкой:

_timer.Interval = _scheduleTime.Subtract(DateTime.Now).TotalSeconds * 1000;

Если DateTime.now позже, чем scheduleTime, вы получите отрицательный результат, и это сгенерирует исключение при назначении timer.Interval.

Я использовал:

if (DateTime.now > scheduleTime)
    scheduleTime = scheduleTime.AddHours(24);

Затем сделайте вычитание.

Используйте встроенный планировщик задач Windows ( http://windows.microsoft.com/en-us/windows7/schedule-a-task) или Quartz.net.

Если... у вас нет службы, которая выполняет много другой обработки и должна работать постоянно, в этом случае таймер может быть подходящим.

private static double scheduledHour = 10;
private static DateTime scheduledTime;

public WinService()
{
     scheduledTime = DateTime.Today.AddHours(scheduledHour);//setting 10 am of today as scheduled time- service start date
}

private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
      DateTime now = DateTime.Now;
      if (scheduledTime < DateTime.Now)
      {
         TimeSpan span = now - DateTime.Now;
         scheduledTime = scheduledTime.AddMilliseconds(span.Milliseconds).AddDays(1);// this will set scheduled time to 10 am of next day while correcting the milliseconds
         //do the scheduled task here
      }  
}

Вы можете сделать это с потоком и событием; таймер не нужен.

using System;
using System.ServiceProcess;
using System.Threading;

partial class Service : ServiceBase
{
    Thread Thread;

    readonly AutoResetEvent StopEvent;

    public Service()
    {
        InitializeComponent();

        StopEvent = new AutoResetEvent(initialState: false);
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            StopEvent.Dispose();

            components?.Dispose();
        }

        base.Dispose(disposing);
    }

    protected override void OnStart(string[] args)
    {
        Thread = new Thread(ThreadStart);

        Thread.Start(TimeSpan.Parse(args[0]));
    }

    protected override void OnStop()
    {
        if (!StopEvent.Set())
            Environment.FailFast("failed setting stop event");

        Thread.Join();
    }

    void ThreadStart(object parameter)
    {
        while (!StopEvent.WaitOne(Timeout(timeOfDay: (TimeSpan)parameter)))
        {
            // do work here...
        }
    }

    static TimeSpan Timeout(TimeSpan timeOfDay)
    {
        var timeout = timeOfDay - DateTime.Now.TimeOfDay;

        if (timeout < TimeSpan.Zero)
            timeout += TimeSpan.FromDays(1);

        return timeout;
    }
}

Если один в день, почему вы не используете планировщик задач? Служба Windows полезна, когда вы хотите запускать задачу много раз в минуту. поэтому, если вы хотите запустить программу в определенное время, лучше использовать планировщик задач и установить событие планировщика задач в определенное время дня. Я много делаю с планировщиком задач, и он идеален. Вы можете установить маршрут программы в планировщике задач и установить интервал времени для ее запуска. Если вы хотите запускать программу каждые 5 минут в день, вы все равно можете использовать планировщик задач и его лучший способ.

Другие вопросы по тегам