زمانبندی Background Jobها با Quartz.NET ⏱️
اگر در حال ساخت یک اپلیکیشن مقیاسپذیر هستید، یک نیازمندی رایج این است که برخی از کارها را در اپلیکیشن خود به یک background job منتقل کنید.
در اینجا چند مثال از آن آمده است:
📧 ارسال نوتیفیکیشنهای ایمیل
📊 تولید گزارشها
🔄 بهروزرسانی یک کش
🖼 پردازش تصویر
🤔چگونه میتوانید یک background job تکرارشونده در NET. ایجاد کنید؟
Quartz.NET
یک سیستم زمانبندی job کامل و متنباز است که میتواند از کوچکترین اپلیکیشنها تا سیستمهای بزرگ سازمانی استفاده شود.
سه مفهوم وجود دارد که باید در Quartz.NET درک کنید:
Job 📝
تسک پسزمینهای واقعی که میخواهید اجرا کنید.
Trigger ⏰
تریگری که زمان اجرای یک job را کنترل میکند.
Scheduler 🧠
مسئول هماهنگی jobها و تریگرها.
بیایید ببینیم چگونه میتوانیم از Quartz.NET برای ایجاد و زمانبندی background jobها استفاده کنیم.
افزودن سرویس میزبانی شده Quartz.NET 🔧
اولین کاری که باید انجام دهیم، نصب پکیج NuGet Quartz.NET است.
Install-Package Quartz.Extensions.Hosting
دلیل استفاده ما از این کتابخانه این است که به خوبی با NET. با استفاده از یک نمونه IHostedService یکپارچه میشود.
برای راهاندازی سرویس میزبانی شده Quartz.NET، به دو چیز نیاز داریم:
افزودن سرویسهای مورد نیاز به کانتینر DI.
services.AddQuartz(configure =>
{
configure.UseMicrosoftDependencyInjectionJobFactory();
});
services.AddQuartzHostedService(options =>
{
options.WaitForJobsToComplete = true;
});
Quartz.NET
با واکشی jobها از کانتینر DI، آنها را ایجاد میکند. این همچنین به این معنی است که شما میتوانید از سرویسهای scoped در jobهای خود استفاده کنید، نه فقط سرویسهای singleton یا transient.
تنظیم گزینه WaitForJobsToComplete روی true تضمین میکند که Quartz.NET قبل از خروج، منتظر بماند تا jobها به آرامی تکمیل شوند.
ایجاد Background Job با IJob 👨💻
برای ایجاد یک background job با Quartz.NET باید اینترفیس IJob را پیادهسازی کنید.
این اینترفیس فقط یک متد واحد - Execute - را ارائه میدهد که میتوانید کد background job خود را در آن قرار دهید.
💡چند نکته قابل توجه در اینجا:
ما از DI برای تزریق سرویسهای ApplicationDbContext و IPublisher استفاده میکنیم.
Job
با DisallowConcurrentExecution دکوریت شده تا از اجرای همزمان همان job جلوگیری شود.
[DisallowConcurrentExecution]
public class ProcessOutboxMessagesJob : IJob
{
private readonly ApplicationDbContext _dbContext;
private readonly IPublisher _publisher;
public ProcessOutboxMessagesJob(
ApplicationDbContext dbContext,
IPublisher publisher)
{
_dbContext = dbContext;
_publisher = publisher;
}
public async Task Execute(IJobExecutionContext context)
{
List<OutboxMessage> messages = await _dbContext
.Set<OutboxMessage>()
.Where(m => m.ProcessedOnUtc == null)
.Take(20)
.ToListAsync(context.CancellationToken);
foreach (OutboxMessage outboxMessage in messages)
{
IDomainEvent? domainEvent = JsonConvert
.DeserializeObject<IDomainEvent>(
outboxMessage.Content,
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
});
if (domainEvent is null)
{
continue;
}
await _publisher.Publish(domainEvent, context.CancellationToken);
outboxMessage.ProcessedOnUtc = DateTime.UtcNow;
await _dbContext.SaveChangesAsync();
}
}
}
حالا که background job آماده است، باید آن را در کانتینر DI ثبت کرده و یک تریگر اضافه کنیم که job را اجرا کند.