#c# #wcf #c#-4.0 #scheduling #quartz.net
#c# #wcf #c #-4.0 #планирование #quartz.net
Вопрос:
Я использую Quartz.NET запланировать задание, которое загружает кучу данных из внешних источников и сохраняется в базе данных. После их загрузки на них также должна выполняться некоторая обработка, которая создаст дополнительные записи в другой таблице в базе данных.
Задание загрузчика является заданием с отслеживанием состояния и выполняется каждую минуту. Проблема, с которой я столкнулся, заключается в том, что после загрузки данных обработка их части может занять гораздо больше времени, чем я ожидал.
Как мне это сделать? Я подумал о создании другого задания (которое будет выполняться только один раз), когда завершится загрузка данных. В этом случае задание загрузчика может выполняться каждую минуту (таков был первоначальный план), потому что часть загрузки занимает всего 5-20 секунд, а другое задание может обрабатывать эти записи после завершения загрузчика. Задание обработчика будет извлекать записи, помеченные как необработанные, из базы данных и выполнять с ними работу.
Является ли это правильным подходом для обработки обработки? Другая идея, к которой я пришел, — настроить службу WCF, которая будет обрабатывать один загруженный элемент. Это будет вызываться для каждого загруженного элемента. Однако я не думаю, что это будет работать лучше, чем другой подход к работе.
Комментарии:
1.
processing part
Связана ли операция с ЦП или она также включает в себя тяжелые операции ввода-вывода?2. Под высокой нагрузкой я имел в виду загрузку процессора, поэтому в процессе нет интенсивного ввода-вывода.
3. Хорошо, так что можете ли вы попробовать выполнить эту обработку параллельно, используя TPL, и посмотреть, получите ли вы что-нибудь, чтобы это было сделано в приемлемое время
4. Итак, вы имеете в виду использовать TPL в Quartz.NET задание, которое также отвечает за загрузку? Я попробую, насколько это будет быстро, но я хочу придерживаться временных рамок в 1 минуту, чтобы не откладывать следующую загрузку.
Ответ №1:
Возможно, лучшим подходом должно быть использование задания в качестве события и выполнение загрузки другой службой.
Задание просто отправит сообщение, определяющее намерение, другой конечной точке.
Это очень распространено в архитектуре, управляемой событиями, с каким-то посредником сообщений или служебной шиной, такой как NServiceBus или MassTransit.
Таким образом, ваш планировщик будет оставаться экономичным и масштабируемым.
Вот пример:
public class DownloadFileJob : IJob
{
public IBus Bus { get; set; }
public ILogger Logger{ get; set; }
public void Execute(IJobExecutionContext context)
{
Bus.Send(new DownloadFileMessage());
Logger.Info("Sending message requesting download of file.");
}
}
Ответ №2:
Ваш подход к тому, чтобы задание загрузки планировало другое задание для выполнения обработки, выполним и широко используется.
Однако следует иметь в виду, что это работает до тех пор, пока задание загрузки не всегда планирует задание обработки. Если ваше задание загрузки всегда планирует задание (скажем, каждую минуту), а выполнение запланированного задания занимает больше времени, чем это требуется, у вас в конечном итоге закончатся потоки обработки, и вашему заданию загрузки придется ждать, пока поток будет доступен.
Комментарии:
1. Хм, я не думал о возможной проблеме, о которой вы упомянули. Существует ли какая-либо «рекомендуемая» стратегия или метод для предотвращения этой ситуации?
2. Вы могли бы запускать длительные задания в другом планировщике, возможно, с достаточной емкостью, чтобы у вас не заканчивались потоки.
3. Спасибо. Если я установлю приоритет заданий загрузчика на высокий и низкий для обработки, это не решит проблему? Я думаю, нет, если вы предложили запустить их в другом планировщике, но стоит спросить.
4. Приоритет используется только для разрыва связей, когда 2 триггера должны срабатывать одновременно, так что это не решит проблему. Quartz.net выполняет задания в порядке, основанном на времени следующего срабатывания триггера.
Ответ №3:
Вы можете изучить настройку a JobListener
для задания загрузки. Просто создайте класс, который реализует IJobListener
интерфейс, затем поместите свой код обработки в JobWasExecuted
метод:
public PostDownloadJobListener : IJobListener
{
string Name { get { return "MyJobListener"; } }
void JobToBeExecuted(JobExecutionContext context) { }
void JobExecutionVetoed(JobExecutionContext context) { }
void JobWasExecuted(JobExecutionContext context, JobExecutionException jobException)
{
// Perform processing here
}
}
Зарегистрируйте прослушиватель с помощью scheduler.AddJobListener(myJobListener);
, и пусть прослушиватель выполняет обработку после успешного выполнения задания.