Планировка Фоновых Задач с Помощью Quartz. Окончание
Начало
Планирование повторяющихся заданий
Для повторяющихся фоновых заданий можно использовать расписания cron:
public record RecurringReminder(
string UserId,
string Message,
string CronExpression
);
app.MapPost("/api/recurring/schedule", async (
ISchedulerFactory schFactory,
RecurringReminder rem) =>
{
var scheduler = await schFactory.GetScheduler();
var jobData = new JobDataMap
{
{ "userId", rem.UserId },
{ "message", rem.Message }
};
var group = "recurring-reminders";
var job = JobBuilder.Create<EmailJob>()
.WithIdentity(
$"recurring-{Guid.NewGuid()}", group)
.SetJobData(jobData)
.Build();
var trigger = TriggerBuilder.Create()
.WithIdentity(
$"rectrigger-{Guid.NewGuid()}", group)
.WithCronSchedule(rem.CronExpression)
.Build();
await scheduler.ScheduleJob(job, trigger);
return Results.Ok(new {
scheduled = true,
cron = rem.CronExpression });
})
.WithName("RecurringReminder")
.WithOpenApi();
Триггеры Cron более эффективны, чем простые. Они позволяют определять сложные расписания, например «каждый будний день в 10 утра»:
POST /api/recurring/schedule
{
"userId": "user69",
"message": "Daily",
"cronExpression": "0 0 10 ? * MON-FRI"
}
Настройка хранения заданий
По умолчанию Quartz использует хранилище в памяти, т.е. задания теряются при перезапуске приложения. Для постоянного хранения поддерживается несколько провайдеров БД. Вот как настроить постоянное хранилище с надлежащей изоляцией схемы:
builder.Services.AddQuartz(opts =>
{
opts.AddJob<EmailJob>(c => c
.StoreDurably()
.WithIdentity(EmailJob.Name));
opts.UsePersistentStore(o =>
{
o.UsePostgres(cfg =>
{
cfg.ConnectionString = "…";
cfg.TablePrefix = "scheduler.qrtz_";
},
dataSourceName: "reminders"); // Имя БД
o.UseNewtonsoftJsonSerializer();
o.UseProperties = true;
});
});
Замечания:
- TablePrefix помогает организовать таблицы Quartz - в данном случае, помещая их в отдельную схему scheduler;
- Нужно будет запустить соответствующие скрипты БД для создания этих таблиц. Каждый поставщик БД имеет свои скрипты настройки.
Долгосрочные Задания
Мы настроили EmailJob с StoreDurably. Это позволяет определить задание 1 раз и повторно использовать его с разными триггерами:
public async Task ScheduleReminder(
string userId, string msg, DateTime dt)
{
var scheduler = await schFactory.GetScheduler();
// Извлекаем задание по его имени
var jobKey = new JobKey(EmailJob.Name);
var trigger = TriggerBuilder.Create()
// Используем задание по ссылке
.ForJob(jobKey)
.WithIdentity($"trigger-{Guid.NewGuid()}")
.UsingJobData("userId", userId)
.UsingJobData("message", msg)
.StartAt(dt)
.Build();
// Передаём только триггер
await scheduler.ScheduleJob(trigger);
}
Такой подход имеет несколько преимуществ:
- Определения заданий централизованы в стартовой конфигурации;
- Не получится случайно запланировать задание, которое не было правильно настроено;
- Конфигурации заданий согласованы во всех расписаниях.
Источник: https://www.milanjovanovic.tech/blog/scheduling-background-jobs-with-quartz-in-dotnet-advanced-concepts