Требуется: служба Windows, которая выполняет задания из очереди заданий в БД; Разыскивается: пример кода

Нужный:

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

Хотел:

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

Задний план:

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

Акцент:

  • This isn't completely new terrain for me.
    • EDIT: You can assume that I know how to create a Windows Service and basic data access.
  • Но мне нужно написать эту услугу с нуля.
  • И я просто хотел бы заранее знать, что мне нужно учесть.
  • РЕДАКТИРОВАТЬ: меня больше всего беспокоят невыполненные задания, конкуренция за задания и сохранение работоспособности службы.

person Jim G.    schedule 16.07.2010    source источник
comment
В чем конкретно вы хотите посоветоваться? Visual studio содержит шаблон проекта для создания служб Windows. Я предполагаю, поскольку вы не спрашиваете, как вставлять строки в БД, о которых вы знаете базовый доступ к данным. Я не уверен, что вы достаточно конкретны в своем запросе.   -  person Chris    schedule 16.07.2010
comment
Хорошо структурированный вопрос. Я бы хотел увидеть больше таких. +1   -  person citronas    schedule 25.07.2010
comment
Я по-прежнему предлагаю Quartz.Net делать именно то, о чем вы просите. У него есть API для создания заданий и подключаемый механизм устойчивости со встроенной поддержкой сохранения заданий в базе данных. Он обрабатывает опрос, предоставляет несколько вариантов обработки сбоев, включая задания, пропущенные по расписанию. Он выполняет опрос за вас, обрабатывает необработанные выражения CRON и т. Д. И т. Д. И т. Д. Вы не можете использовать другой компонент?   -  person quentin-starin    schedule 19.08.2010


Ответы (4)


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

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

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

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

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

person Remus Rusanu    schedule 16.07.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 ()

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

person Conrad Frix    schedule 16.07.2010
comment
Просто любопытно ... почему вы добавляете аргументы в список только для того, чтобы перебирать список точно так же, как вы могли бы перебирать исходный массив? - person Chris; 16.07.2010
comment
@Крис. gArgs имеет другую область действия, чем код, из которого это произошло. Это 2.0, поэтому такие вещи, как args.Contains ‹string› (DEBUG_SERVICE), мне не помогают. - person Conrad Frix; 16.07.2010

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

person quentin-starin    schedule 16.07.2010

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

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

  • Determine whether a job can be retried and do one of the following:
    • Move the row to an "error" table for logging / reporting later OR
    • Оставьте строку в очереди, чтобы она была повторно обработана службой заданий.
    • Вы можете добавить столбец типа WaitUntil или что-то подобное, чтобы отложить повторную попытку задания после сбоя.

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

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

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

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

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

person Chris    schedule 16.07.2010