Требуется: служба Windows, которая выполняет задания из очереди заданий в БД;Требуются: пример кода - PullRequest
6 голосов
/ 16 июля 2010

Требуется:

  • Служба Windows, которая выполняет задания из очереди заданий в БД

Требуется:

  • Пример кода,Руководство или рекомендации для этого типа приложений

Справочная информация:

  • Пользователь щелкает ссылку Ashx, которая вставит строку в базу данных.
  • Мне нужна моя служба Windows для периодического опроса строк в этой таблице, и она должна выполнять единицу работы для каждой строки.

Акцент:

  • Для меня это не совсем новая местность.
    • РЕДАКТИРОВАТЬ: Можно предположить, что я знаю, как создать службу Windows и базовый доступ к данным.
  • Но мне нужно написать эту службус нуля.
  • И я просто хотел бы заранее знать, что мне нужно учитывать.
  • РЕДАКТИРОВАТЬ: Я больше всего волнуюсь из-за неудачных заданий,заданий и поддержание службы в рабочем состоянии.

Ответы [ 4 ]

8 голосов
/ 16 июля 2010

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

while(1) {
 Start transction;
 Dequeue item from queue;
 process item;
 save new state of item;
 commit;
}

Если обработка прерывается на полпути, транзакция откатывается и элемент обрабатывается при следующем запуске службы.

Но написание очередей в базе данных на самом деле много сложнее, чем вы думаете. Если вы развернете наивный подход, вы обнаружите, что ваши очереди и очереди блокируют друг друга, и страница Ashx перестает отвечать на запросы. Далее вы обнаружите, что очереди по сравнению с dequeue являются взаимоблокировками, и ваш цикл постоянно вызывает ошибку 1205. Я настоятельно рекомендую вам прочитать эту статью Использование таблиц в качестве очередей .

Ваша следующая задача будет получить «правильную» ставку пула. Слишком агрессивно, и ваша база данных будет перегреваться от запросов на объединение. Слишком слабый и ваша очередь будет расти в часы пик и будет истощать слишком медленно. Вам следует рассмотреть возможность использования совершенно другого подхода: использовать встроенный в SQL Server объект QUEUE и полагаться на магию семантики WAITFOR(RECEIVE). Это позволяет полностью опросить поведение службы самонастройки. На самом деле, есть еще кое-что: вам не нужен сервис для начала. См. Выполнение асинхронных процедур для объяснения того, о чем я говорю: запуск обработки асинхронно в SQL Server из вызова веб-службы, абсолютно надежным способом. И наконец, если логика должна быть в процессе C #, вы можете использовать External Activator , который позволяет размещать обработку в автономных процессах, а не в процедурах T-SQL.

4 голосов
/ 16 июля 2010

Сначала вы должны рассмотреть

  1. Как часто нужно опрашивать за
  2. Ваша служба просто останавливается и запускается или поддерживает паузу и продолжение.
  3. параллелизм. Услуги могут увеличить вероятность возникновения проблемы

Реализация

  1. Использовать System.Timers.Timer, а не Threading.Timer
  2. Создатель уверен, что для Timer.AutoReset установлено значение false. Это остановит проблему повторного входа.
  3. Обязательно укажите время выполнения

Вот основные рамки всех этих идей. Это включает способ отладки этого, который является болью

        public partial class Service : ServiceBase{

        System.Timers.Timer timer;


        public Service()
        {

        timer = new System.Timers.Timer();
        //When autoreset is True there are reentrancy problme 
        timer.AutoReset = false;


        timer.Elapsed += new System.Timers.ElapsedEventHandler(DoStuff);
    }


     private void DoStuff(object sender, System.Timers.ElapsedEventArgs e)
     {

        Collection stuff = GetData();
        LastChecked = DateTime.Now;

        foreach (Object item in stuff)
        {
            try
                    {
                        item.Dosomthing()
                    }
                    catch (System.Exception ex)
            {
                this.EventLog.Source = "SomeService";
                this.EventLog.WriteEntry(ex.ToString());
                this.Stop();
        }


        TimeSpan ts = DateTime.Now.Subtract(LastChecked);
        TimeSpan MaxWaitTime = TimeSpan.FromMinutes(5);


        if (MaxWaitTime.Subtract(ts).CompareTo(TimeSpan.Zero) > -1)
            timer.Interval = MaxWaitTime.Subtract(ts).TotalMilliseconds;
        else
            timer.Interval = 1;

        timer.Start();





     }

        protected override void OnPause()
     {

         base.OnPause();
         this.timer.Stop();
     }

     protected override void OnContinue()
     {
         base.OnContinue();
         this.timer.Interval = 1;
         this.timer.Start();
     }

     protected override void OnStop()
     {

         base.OnStop();
         this.timer.Stop();
     }


     protected override void OnStart(string[] args)
     {
        foreach (string arg in args)
        {
            if (arg == "DEBUG_SERVICE")
                    DebugMode();

        }

         #if DEBUG
             DebugMode();
         #endif

         timer.Interval = 1;
         timer.Start();

        }

    private static void DebugMode()
    {

        Debugger.Break();
    }



 }

РЕДАКТИРОВАТЬ Исправлена ​​петля в Start ()

РЕДАКТИРОВАТЬ Оказывается, миллисекунды не совпадают с TotalMilliseconds

2 голосов
/ 16 июля 2010

Возможно, вы захотите взглянуть на Quartz.Net для управления расписанием заданий.Не уверен, что он подойдет для вашей конкретной ситуации, но стоит посмотреть.

1 голос
/ 16 июля 2010

Некоторые вещи, которые я могу придумать, основываясь на ваших изменениях:

Re: сбой задания:

  • Определите, можно ли повторить задание, и выполните одно из следующих действий:
    • Переместить строку в таблицу «ошибок» для ведения журнала / отчетности позже ИЛИ
    • Оставить строку в очереди, чтобы она была повторно обработана службой заданий
    • Вы можете добавить столбец, такой как WaitUntil или что-то похожее, чтобы отложить повторную попытку задания после сбоя

Re: утверждение:

  • Добавьте столбец отметки времени, например «JobStarted» или «Locked», чтобы отслеживать, когда задание было запущено. Это предотвратит попытки других потоков (при условии, что ваш сервис многопоточный) пытаться выполнить задание одновременно.
  • Вам понадобится какой-то процесс очистки, который проходит и очищает устаревшие задания для повторной обработки (в случае сбоя службы заданий и снятия блокировки никогда).

Re: сохранение службы в рабочем состоянии

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

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

...