Настраиваемый сервисный таймер в C # - PullRequest
3 голосов
/ 04 октября 2011

Я пытаюсь написать службу Windows, которая работает бесконечно.Windows-формы и фоновые программы для Linux не кажутся слишком плохими, но, возможно, я просто ужасно неумел в службах Windows.В отличие от некоторых других вопросов, связанных со сном или таймером, которые я здесь выкопал, время пробуждения или сна может быть регулярным интервалом, но не всегда таковым.Программа считывает некоторые файлы данных, которые могут дать ей команду изменить свое расписание, и это должно вступить в силу со следующего пробуждения.Он казался довольно простым, как консольная программа, и вел себя там отлично:

while (true)
{
  // Calculate next time to run.
  DateTime nextRun = NextWakeup();
  TimeSpan nextTime = nextRun - DateTime.Now;
  int sleepMs = (int)nextTime.TotalMilliseconds;
  // Sleep until scheduled time
  System.Threading.Thread.Sleep(sleepMs);
  // Do a code cycle of more stuff here...
}

Однако, когда я пытаюсь запустить его как часть службы, чтобы он продолжал быть активным, пока пользователь вышел из системы,Service Manager упорно отказывается запустить его.Я получаю прекрасную ошибку 1053: «Служба не ответила на запрос запуска или управления своевременно».

Множество ответов на смежные вопросы здесь, кажется, предлагают использовать таймер любой ценой для сна.Если бы я сделал такую ​​вещь вместо комбинации время / сон, как бы я изменил интервал таймера при каждом запуске?Или все это прекрасно, и я собираюсь неправильно настроить свой сервис?

Большое спасибо заранее!

Ответы [ 3 ]

6 голосов
/ 04 октября 2011

Службы Windows обычно должны отвечать на контрольный запрос (обычно запуск / остановка, а также приостановка / возобновление) за 30 секунд.Это означает, что если вы спите в главном потоке в OnStart, ваш сервис вернет ошибку, на которую вы ссылаетесь.

Способ решения вашей проблемы - выполнить свою работу в отдельном потоке, где высвободно спать нить так, как вы описываете.Просто запустите эту ветку в сервисах 'OnStart, и вы сможете легко вернуться в течение 30 секунд.

В качестве отдельного слова вместо while(true) вы должны учитывать, что остановленная служба также должна возвращатьв этом 30-секундном пределе.Если у вас есть спящий поток, спящий, служба не будет корректно закрываться без Abort добавления потока (плохо) или обеспечения какого-либо механизма для правильного выхода из потока.Именно поэтому большинство людей используют подход опроса;служба может либо определить, пора ли ей запускаться, либо определить, был ли выполнен запрос на остановку.Пока частота этого опроса <30 с, служба всегда будет корректно закрываться. </p>

1 голос
/ 04 октября 2011

Я думаю, вы можете искать что-то вроде этого:

static class ConsoleProgram
{
    static void Main()
    {
        ServiceBase[] servicesToRun = new ServiceBase[] { new MyService(config, Logger) };
        ServiceBase.Run(servicesToRun);
    }
}



public partial class MyService : ServiceBase
{
    private bool _stopped = true;

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

    protected override void OnStop()
    {
        StopTimer();
    }

    public void StartTimer()
    {
        _stopped = false;
        Timer t = new Timer(TimerProc);
        // Calculate your desired interval here.
        t.Change(_config.Interval, new TimeSpan(0, 0, 0, 0, -1));
    }

    public void StopTimer()
    {
        _stopped = true;
    }

    private void TimerProc(object state)
    {
        // The state object is the Timer object.
        Timer t = (Timer) state;
        t.Dispose();

        ThreadPool.QueueUserWorkItem(DoWork);

        if (!_stopped) {
            StartTimer();
        }
    }

}
1 голос
/ 04 октября 2011

Если вы хотите использовать таймеры, это довольно легко сделать. Я бы использовал System.Timers.Timer и изменить его интервал так же просто, как mytimer.Inverval = nextTime.Seconds или аналогичный.

Я бы лично запустил таймер без AutoReset = false (поэтому он не перезапускает таймер автоматически), а затем каждый раз, когда он просыпается, запускает вашу "работу", а затем в конце работы, когда вы работаете, когда Вы хотите, чтобы он запускался следующим, установите соответствующий интервал, а затем снова вызовите Start на таймере.

Конечно, в вашем сервисе ваш метод запуска просто устанавливает первый таймер, а затем возвращается, чтобы запуск был приятным и быстрым. При выключении вы просто очищаете свой таймер (остановитесь и утилизируйте и тому подобное), а затем просто возвращаетесь. Красиво и чисто.

...