Необходимый:
Требуемый:
Фон:
Акцент:
Учитывая, что вы имеете дело с очередью базы данных, у вас есть значительная часть работы, которая уже была сделана за вас из-за транзакционной природы баз данных. Типичное приложение, управляемое очередью, имеет цикл, который:
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.
Сначала вам нужно подумать
Реализация
Вот основная структура всех этих идей. Он включает в себя способ отладки, что является проблемой
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
Возможно, вы захотите взглянуть на Quartz.Net для управления планированием заданий. Не уверен, подойдет ли он для вашей конкретной ситуации, но посмотреть стоит.
Некоторые вещи, о которых я могу подумать, основываясь на вашей правке:
Re: провал задания:
Re: contention:
Re: поддержание работы службы
На самом деле я здесь просто копаюсь в темноте. Я бы настоятельно рекомендовал создать прототип службы и вернуться с любыми конкретными вопросами о том, как она функционирует.