Необходимый: служба Windows, которая выполняет задания от очереди заданий в DB; требуемый: пример кода

Необходимый:

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

Требуемый:

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

Фон:

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

Акцент:

  • Это не абсолютно новый ландшафт для меня.
    • Править: Можно предположить, что я знаю, как создать доступ основных данных и служба Windows.
  • Но я должен записать этот сервис с нуля.
  • И я был бы точно так же, как для знания заранее, что я должен рассмотреть.
  • Править: Я больше всего волнуюсь по поводу заданий, что перестали работать, конкуренция для заданий и поддерживание в рабочем состоянии сервиса.
6
задан Jim G. 16 July 2010 в 15:36
поделиться

4 ответа

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

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

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

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

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

8
ответ дан 8 December 2019 в 15:58
поделиться

Сначала вам нужно подумать

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

Реализация

  1. Используйте System.Timers.Timer, а не Threading.Timer
  2. Maker, убедитесь, что вы установили 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();
    }



 }

EDIT Фиксированный цикл в Start ()

EDIT Оказывается, миллисекунды - это не то же самое, что TotalMilliseconds

4
ответ дан 8 December 2019 в 15:58
поделиться

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

2
ответ дан 8 December 2019 в 15:58
поделиться

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

Re: провал задания:

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

Re: contention:

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

Re: поддержание работы службы

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

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

1
ответ дан 8 December 2019 в 15:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: