Как я могу запланировать службу Windows C # для выполнения задачи ежедневно? - PullRequest
81 голосов
/ 02 февраля 2009

У меня есть служба, написанная на C # (.NET 1.1), и я хочу, чтобы она выполняла некоторые действия по очистке в полночь каждую ночь. Я должен сохранить весь код, содержащийся в сервисе, так каков самый простой способ сделать это? Использование Thread.Sleep() и проверка времени пролонгации?

Ответы [ 10 ]

86 голосов
/ 02 февраля 2009

Я бы не использовал 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();
    }
}
69 голосов
/ 02 февраля 2009

Выезд Кварц .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);
21 голосов
/ 02 февраля 2009

Ежедневное задание? Похоже, это должно быть только запланированное задание (панель управления) - здесь нет необходимости в обслуживании.

15 голосов
/ 02 февраля 2009

Должен ли это быть фактический сервис? Можете ли вы просто использовать встроенные запланированные задачи в панели управления Windows.

3 голосов
/ 02 февраля 2009

Я делаю это с помощью таймера.

Запустите серверный таймер, пусть он проверяет часы / минуты каждые 60 секунд.

Если это правильный час / минута, запустите ваш процесс.

На самом деле это абстрагировано в базовый класс, который я называю OnceADayRunner.

Позвольте мне немного почистить код, и я выложу его здесь.

    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.

Там есть ловушки для тестирования и т. Д., Но именно так может выглядеть ваш истекший таймер, чтобы все это работало.

2 голосов
/ 02 февраля 2009

Как уже писали другие, таймер - лучший вариант в сценарии, который вы описали.

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

Если причина, по которой вы хотите выполнить свое действие в полночь, заключается в том, что вы ожидаете небольшой нагрузки на своем компьютере, лучше позаботьтесь: такое же предположение часто делают другие, и внезапно у вас возникает 100 действий по очистке, начинающихся между 0: 00 и 0:01

В этом случае вам следует начать очистку в другое время. Обычно я делаю эти вещи не в часы, а в полчаса (1.30 утра - мое личное предпочтение)

1 голос
/ 02 февраля 2009

Я бы посоветовал вам использовать таймер, но установите его для проверки каждые 45 секунд, а не минут. В противном случае вы можете столкнуться с ситуациями, когда при большой нагрузке проверка на определенную минуту пропускается, потому что между временем срабатывания таймера и временем, в течение которого ваш код выполняет проверку, и текущим временем, вы могли пропустить заданную минуту.

0 голосов
/ 24 апреля 2018

Для тех, кто обнаружил, что вышеупомянутые решения не работают, это потому, что у вас может быть this внутри вашего класса, что подразумевает метод расширения, который, как говорится в сообщении об ошибке, имеет смысл только для неуниверсального статического класса. Ваш класс не статичен. Похоже, это не то, что имеет смысл как метод расширения, поскольку он действует на рассматриваемый экземпляр, поэтому удалите this.

0 голосов
/ 03 марта 2014

Вы также можете попробовать библиотеку TaskSchedulerLibrary здесь http://visualstudiogallery.msdn.microsoft.com/a4a4f042-ffd3-42f2-a689-290ec13011f8

Реализуйте абстрактный класс AbstractScheduledTask и вызовите ScheduleUtilityFactory.AddScheduleTaskToBatch статический метод

0 голосов
/ 09 августа 2013

Попробуйте это:

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