Каков наилучший способ вызывать / запускать службу Windows каждые x секунд? - PullRequest
1 голос
/ 15 мая 2009

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

Один из методов - просто вызвать Thread.Sleep, а затем снова вызвать метод Start, например,

protected override void OnStart(string[] args)
{
    // get config settings
    CheckMailbox();
}

public void CheckMailbox()
{
    int x = 5000;

    // do stuff

    Thread.Sleep(x);
    CheckMailbox();
}

Не уверен, что это лучший способ сделать это. Для дальнейшего изучения этого, я понимаю, что вы можете вызвать Службу Windows, предоставив Службу через WCF. В этом случае, если веб-приложение под названием «Процесс запускается», будут конфликтующие потоки, я прав? Как бы я тогда справился с этим? Должен ли я каждый раз создавать новый поток и помещать его в очередь?

Ответы [ 6 ]

7 голосов
/ 15 мая 2009

Спать, как правило, плохая идея. Помимо всего прочего, это означает, что вы не будете быстро реагировать на событие Stop.

Вы должны использовать Timer. Есть два, которые подходят для услуг:

В каждом случае вы в основном говорите, что хотите, чтобы происходило каждый раз, когда таймер «тикает» и когда вы хотите, чтобы он срабатывал.

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

Я не уверен насчет вашего вопроса о WCF, но я не думаю, что ваш веб-сервис явно запустил бы сервис - он просто связался бы с ним через WCF. Да, вам потенциально нужно быть осторожным с потоками. То, с чем вам нужно быть осторожным, зависит от того, что предоставляет служба WCF.

1 голос
/ 15 мая 2009

Базовый System.Threading.Timer код:

// Class level variable in the Windows Service:
private System.Threading.Timer timer;

// This is in the constructor for a Windows Service.
// interval would be the time in milliseconds in between ticks.
// 0 is how long until it should start.
timer = new Timer(new TimerCallback(TimerElapsed), null, 0, interval);

// The TimerCallback in the Windows Service:
private void TimerElapsed(object o)
{
    // Do email stuff here.
}
0 голосов
/ 15 мая 2009

Хорошо, хотя ваш вопрос о времени в значительной степени решен (и я согласен с большинством из вышеперечисленных), я могу предложить некоторую информацию, касающуюся WCF. Служба WCF просто размещается в домене приложения. Этот домен может быть формой Windows, консольным приложением, ASP.net и, в данном случае, службой Windows.

Таким образом, в некотором смысле вы не выставляете службу Windows через WCF , вы более размещаете службу WCF в приложении Windows Service домен. Я бы посоветовал протестировать ваш сервис (включая объекты таймера) в форме Windows , прежде чем переходить на службу Windows. Проще отлаживать и тестировать.

Размещенный сервис WCF фактически работает в своем собственном потоке:

    serviceType_MyEmailer = typeof(MyEmailerServiceType);
    ServiceHost host_MyEmailer;


    host_MyEmailer = new ServiceHost(serviceType_MyEmailer);

Найдите в Интернете пример "DerivativesCalculatorService". Показывает, как разместить службу WCF в коде.

Хитрость времени здесь находится внутри вашего сервиса. Вы можете создать свой класс обслуживания как одноэлементный класс, который будет инициализирован немедленно, и после его инициализации он может запустить свой объект Timer (как видно из других ответов).

Таким образом, ваша служба WCF будет иметь постоянный экземпляр вашего класса, а его объект Timer будет молчать. Разместите все это в службе Windows, и все готово.

Надеюсь, это поможет.

0 голосов
/ 15 мая 2009

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

Quartz.NET - это компонент планирования с открытым исходным кодом, который может сделать это. Это позволяет вам настроить расписание точно так, как вы хотите, и его довольно просто использовать.

0 голосов
/ 15 мая 2009

В вашем коде есть проблема добавления в стек вызовов для каждого вызова, поскольку вы вызываете метод изнутри себя. В какой-то момент вы получите исключение переполнения стека. Одно ожидание - вызвать другой метод в «ожидающем потоке», который через определенный промежуток времени отправит сигнал:

private void CheckMailBox()
{
    _waitHandle = new AutoResetEvent(true);
    while (_waitHandle.WaitOne())
    {
        // do the mail checking
        ((IDisposable)_waitHandle).Dispose();
        _waitHandle = new AutoResetEvent(false);
        ThreadPool.QueueUserWorkItem(WaitSomeTime, 2000);
    }

}

private void WaitSomeTime(object state)
{

    Thread.Sleep((int)state);
    _waitHandle.Set();
}
0 голосов
/ 15 мая 2009

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

Другой вариант - иметь таймер, который вызывает свой обработчик события «Tick» каждые 5 секунд или около того.

Или, если ваши проверки выполняются не так часто, вы также можете создать консольное приложение командной строки и просто запланировать его как «запланированное задание» в Windows.

Марк

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...