Планировка Фоновых Задач с Помощью Quartz. Начало
Большинству приложений ASP.NET Core необходимо обрабатывать фоновые задачи. Хотя существует множество способов их реализации, Quartz.NET выделяется своими надёжными возможностями планирования, настройкой хранения заданий и богатой функциональностью. Основы Quartz в этом посте. Здесь рассмотрим некоторые продвинутые настройки. Извините за многокода.
Настройка Телеметрии Quartz в ASP.NET Core
Сначала установим пакеты Quartz:
Install-Package Quartz.Extensions.Hosting
Install-Package Quartz.Serialization.Json
# Пока в предрелизе
Install-Package OpenTelemetry.Instrumentation.Quartz
Также потребуются некоторые пакеты OpenTelemetry.
Затем настроим сервисы Quartz и инструментарий OpenTelemetry:
builder.Services.AddQuartz();
builder.Services.AddQuartzHostedService(opts =>
{
opts.WaitForJobsToComplete = true;
});
builder.Services.AddOpenTelemetry()
.WithTracing(trc =>
{
trc
.AddHttpClientInstrumentation()
.AddAspNetCoreInstrumentation()
.AddQuartzInstrumentation();
})
.UseOtlpExporter();
Определение и планирование заданий
Все задания реализуют IJob и выполняются как сервисы с ограниченной областью действия, поэтому при необходимости можно внедрять зависимости. Quartz позволяет передавать данные заданию с помощью словаря JobDataMap. Рекомендуется использовать только примитивные типы для данных задания, чтобы избежать проблем с сериализацией и использовать MergedJobDataMap для извлечения данных задания.
Создадим задание для email-напоминания:
public class EmailJob(
IEmailService emailSvc) : IJob
{
public const string Name = nameof(EmailJob);
public async Task Execute(
IJobExecutionContext ctx)
{
var data = ctx.MergedJobDataMap;
try
{
await emailSvc.SendAsync(
data.GetString("userId"),
data.GetString("message"));
}
catch (Exception ex)
{
// … обработка … и throw,
// чтобы Quartz попробовал снова
throw;
}
}
}
Замечание: JobDataMap не строго типизирован. Поэтому рекомендуется:
- Использовать константы для ключей;
- Проверять данные в методе Execute;
- Создавать сервисы-обёртки для планирования заданий.
Вот как запланировать одноразовые напоминания:
public record Reminder(
string UserId,
string Message,
DateTime ScheduleTime
);
app.MapPost("/api/reminders/schedule", async (
ISchedulerFactory schFactory,
Reminder rem) =>
{
var scheduler = await schFactory.GetScheduler();
var jobData = new JobDataMap
{
{ "userId", rem.UserId },
{ "message", rem.Message }
};
var group = "email-reminders";
var job = JobBuilder.Create<EmailJob>()
.WithIdentity(
$"reminder-{Guid.NewGuid()}", group)
.SetJobData(jobData)
.Build();
var trigger = TriggerBuilder.Create()
.WithIdentity(
$"trigger-{Guid.NewGuid()}", group)
.StartAt(rem.ScheduleTime)
.Build();
await scheduler.ScheduleJob(job, trigger);
return Results.Ok(new
{
scheduled = true,
at = rem.ScheduleTime
});
})
.WithName("ScheduleReminder")
.WithOpenApi();
Конечная точка планирует одноразовые напоминания по email с помощью Quartz. Она создаёт задание с данными пользователя, устанавливает триггер на указанное время и планирует их. EmailJob получает уникальный идентификатор в группе "email-reminders".
Пример запроса:
POST /api/reminders/schedule
{
"userId": "user42",
"message": "Meeting!",
"scheduleTime": "2024-12-31T23:00:00"
}
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/scheduling-background-jobs-with-quartz-in-dotnet-advanced-concepts