Gereksinimler ve Ön Hazırlık
Quartz.net kullanmaya başlamadan önce, projenizin modern .NET standartlarına uygun olduğundan emin olmalısınız. Geliştirme ortamınızda .NET SDK 8.0 veya daha güncel bir sürümün kurulu olması gerekir.
- Visual Studio 2022 veya VS Code (C# Dev Kit eklentisi ile).
- NuGet paket yöneticisi erişimi.
- Temel asenkron programlama (async/await) bilgisi.
Öncelikle, projenize gerekli olan Quartz paketini NuGet üzerinden eklemelisiniz. Terminal üzerinden şu komutu çalıştırarak en güncel sürümü projenize dahil edebilirsiniz:
dotnet add package Quartz.Extensions.Hosting
Bu paket, Quartz'ın .NET'in yerleşik "Generic Host" yapısıyla entegre çalışmasını sağlar. Bu sayede uygulamanızın yaşam döngüsü içerisinde görevleriniz otomatik olarak başlatılır ve durdurulur.
Adım Adım Görev (Job) Sınıfı Oluşturma
Quartz.net içerisinde her bir görev, IJob arayüzünü (interface) uygulayan bir sınıf olarak tanımlanır. Bu sınıfın içindeki Execute metodu, zamanı geldiğinde tetiklenecek olan kod bloğunu barındırır.
using Quartz;
using System.Threading.Tasks;
public class RaporGorevi : IJob
{
public async Task Execute(IJobExecutionContext context)
{
// Görevin ana mantığı burada yer alır
await Task.Run(() => Console.WriteLine("Rapor oluşturma işlemi başlatıldı: " + DateTime.Now));
}
}
Yukarıdaki örnekte, IJob arayüzünü uygulayan basit bir sınıf tanımladık. Execute metodu asenkron olduğu için, veritabanı işlemleri veya API istekleri gibi uzun süren süreçleri await anahtar kelimesi ile güvenle yürütebilirsiniz.
Zamanlayıcı (Scheduler) Yapılandırması
Görevimizi tanımladıktan sonra, bu görevin ne zaman çalışacağını belirleyen bir "Trigger" (tetikleyici) oluşturmamız gerekir. Quartz.net, Program.cs içerisinde AddQuartz metodu ile kolayca yapılandırılabilir.
using Quartz;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddQuartz(q =>
{
var jobKey = new JobKey("RaporGorevi");
q.AddJob(opts => opts.WithIdentity(jobKey));
q.AddTrigger(opts => opts
.ForJob(jobKey)
.WithIdentity("RaporGorevi-trigger")
.WithSimpleSchedule(x => x.WithIntervalInMinutes(5).RepeatForever()));
});
builder.Services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);
Bu yapılandırma, RaporGorevi sınıfını her 5 dakikada bir çalışacak şekilde ayarlar. AddQuartzHostedService kullanımı, uygulamanız kapandığında görevlerin güvenli bir şekilde tamamlanmasını sağlar.
Cron İfadeleri ile Karmaşık Zamanlama
Basit aralıklar yerine "her ayın ilk pazartesi günü saat 08:00'de" gibi karmaşık zamanlamalar için Cron ifadeleri kullanılır. Quartz.net, Cron formatını tam destekler.
q.AddTrigger(opts => opts
.ForJob(jobKey)
.WithIdentity("Cron-Trigger")
.WithCronSchedule("0 0 8 ? * MON")); // Her Pazartesi saat 08:00
Cron ifadeleri, sisteminizin esnekliğini artırır. Ancak, hatalı bir Cron ifadesi görevin hiç çalışmamasına neden olabilir. Bu nedenle ifadelerinizi test etmek için çevrimiçi Cron editörlerini kullanmanız önerilir.
Quartz.net Özellik Karşılaştırması
| Özellik | Simple Schedule | Cron Schedule |
|---|---|---|
| Kullanım Kolaylığı | Yüksek | Orta |
| Esneklik | Düşük | Çok Yüksek |
| Senaryo | Düzenli aralıklar | Takvim bazlı görevler |
Hata Yönetimi ve Logging (Günlükleme)
Arka plan görevlerinde hata yönetimi hayati önem taşır. Bir görev başarısız olduğunda uygulamanın çökmemesi için try-catch bloklarını Execute metodu içerisinde mutlaka kullanmalısınız.
public async Task Execute(IJobExecutionContext context)
{
try
{
// İş mantığı
}
catch (Exception ex)
{
// Hata durumunda loglama yapın
Console.WriteLine($"Görev başarısız: {ex.Message}");
throw new JobExecutionException(ex, refireImmediately: true);
}
}
JobExecutionException kullanarak Quartz'a görevin başarısız olduğunu ve gerekirse yeniden denenmesi gerektiğini bildirebilirsiniz.
Güvenlik Uyarısı: Arka plan görevleri içerisinde veritabanı bağlantı dizeleri veya API anahtarları gibi hassas bilgileri doğrudan kod içerisinde tutmayın. Her zaman
appsettings.jsonveya Azure Key Vault gibi güvenli konfigürasyon sağlayıcılarını kullanın.
Sıkça Sorulan Sorular
Quartz.net veritabanı üzerinde çalışabilir mi?
Evet, Quartz.net görev bilgilerini ve tetikleyicileri SQL Server, PostgreSQL veya MySQL gibi veritabanlarında saklayabilir. Bu, uygulamanız yeniden başlatıldığında görevlerin kaldığı yerden devam etmesini sağlar.
Aynı anda birden fazla görev çalıştırabilir miyim?
Quartz.net çok kanallı (multi-threaded) bir yapıdadır. Doğru yapılandırma ile aynı anda onlarca farklı görevi birbirini engellemeden çalıştırabilirsiniz.
Görevlerimin durumunu nasıl izlerim?
Quartz.net'in sunduğu ISchedulerListener arayüzünü uygulayarak görevlerin başlangıç, bitiş ve hata durumlarını yakalayabilir ve bir dashboard ekranına yansıtabilirsiniz.
Uygulama kapandığında görevler ne olur?
AddQuartzHostedService içerisinde WaitForJobsToComplete = true ayarını yaparak, uygulamanın kapanmadan önce devam eden görevlerin bitmesini beklemesini sağlayabilirsiniz.
Quartz.net'i Dependency Injection ile nasıl kullanırım?
Quartz.net, .NET'in yerleşik DI (Dependency Injection) yapısı ile tam uyumludur. Job sınıfınızın constructor'ına gerekli servisleri (DB Context, Logger vb.) ekleyerek doğrudan kullanabilirsiniz.
Quartz.net ile Performans Optimizasyonu ve Ölçeklendirme
Zamanlanmış görevleriniz arttıkça, sistem kaynaklarının verimli kullanılması kritik bir hale gelir. Quartz.net, varsayılan olarak görevleri kendi içindeki bir thread havuzunda çalıştırır. Yüksek trafikli uygulamalarda bu havuzun kapasitesini ve görevlerin çalışma stratejisini optimize etmek, uygulamanızın yanıt süresini doğrudan etkiler.
Thread Havuzu Yapılandırması
quartz.config dosyanızda veya kod üzerinden yapılandırma yaparken, threadCount değerini sunucunuzun işlemci çekirdek sayısına ve görevlerinizin yoğunluğuna göre ayarlamalısınız. Eğer çok sayıda kısa süreli görev çalıştırıyorsanız, thread sayısını artırmak performansı iyileştirebilir.
// Program.cs veya yapılandırma sınıfınızda
var props = new NameValueCollection
{
{ "quartz.threadPool.type", "Quartz.Simpl.DefaultThreadPool, Quartz" },
{ "quartz.threadPool.threadCount", "10" }, // Eşzamanlı görev sayısı
{ "quartz.threadPool.threadPriority", "Normal" }
};
ISchedulerFactory schedulerFactory = new StdSchedulerFactory(props);
Görev Çakışmalarını Önleme (DisallowConcurrentExecution)
Aynı görevin birden fazla örneğinin aynı anda çalışmasını engellemek, özellikle veritabanı güncellemeleri veya dosya işlemleri gibi kritik görevlerde veri tutarlılığı için zorunludur. [DisallowConcurrentExecution] özniteliğini (attribute) kullanarak Quartz'ın aynı görevi paralel çalıştırmasını engelleyebilirsiniz.
[DisallowConcurrentExecution]
public class KritikVeriGuncellemeJob : IJob
{
public async Task Execute(IJobExecutionContext context)
{
// Bu görev çalışırken, aynı JobKey'e sahip başka bir tetikleme
// bir önceki görev bitene kadar bekletilir.
await Task.Delay(5000);
}
}
Quartz.net ile Birim ve Entegrasyon Testleri
Zamanlanmış görevlerin test edilmesi, geleneksel metot testlerinden farklıdır çünkü zaman faktörü işin içine girer. Görevlerinizin mantığını test etmek için IJobExecutionContext nesnesini mock'layabilir veya görevi doğrudan bir metot gibi çağırarak iş mantığını doğrulayabilirsiniz.
Görev Mantığını İzole Etme
Test edilebilirliği artırmak için, IJob sınıfınızın içine iş mantığını yazmak yerine, bu mantığı ayrı bir Service sınıfına taşıyın. Böylece görevi tetiklemek zorunda kalmadan, ilgili servisi birim testlerinizde kolayca test edebilirsiniz.
// Örnek: Test edilebilir yapı
public class RaporGorevi : IJob
{
private readonly IRaporService _raporService;
public RaporGorevi(IRaporService raporService)
{
_raporService = raporService;
}
public async Task Execute(IJobExecutionContext context)
{
await _raporService.RaporOlusturAsync();
}
}
// Test sınıfı örneği (Moq kütüphanesi ile)
[Fact]
public async Task RaporGorevi_Calistiginda_Servis_Cagrilmalidir()
{
var mockService = new Mock();
var job = new RaporGorevi(mockService.Object);
await job.Execute(null);
mockService.Verify(x => x.RaporOlusturAsync(), Times.Once);
}
İleri Düzey İpuçları
- Misfire Handling: Sistem kapalıyken kaçırılan görevlerin ne zaman çalışacağını belirlemek için
WithMisfireHandlingInstructionFireNow()gibi talimatları kullanın. - Job Data Map: Görevlerinize dinamik parametreler göndermek için
JobDataMapkullanın, ancak buraya çok büyük nesneler yerine sadece ID veya referanslar ekleyin. - Monitoring: Görevlerin başarı durumunu izlemek için
IJobListenerarayüzünü kullanarak merkezi bir izleme mekanizması kurun.
Sonuç
Quartz.net, C# projelerinde zamanlanmış görev yönetimi için endüstri standardı haline gelmiş, güçlü ve esnek bir kütüphanedir. Bu rehberde, temel kurulumdan gelişmiş Cron zamanlamasına ve hata yönetimine kadar izlemeniz gereken yolları inceledik. Bir sonraki adım olarak, görevlerinizi kalıcı hale getirmek için Quartz'ın veritabanı entegrasyonu (JobStore) özelliklerini araştırmanızı ve görevlerinizi bir veritabanı üzerinden yönetmeyi denemenizi öneririm.
Sorumluluk Reddi: Bu makalede paylaşılan kod örnekleri eğitim amaçlıdır. Üretim ortamında (Production) kullanmadan önce, görevlerin güvenlik açıklarına karşı test edildiğinden ve hata loglarının merkezi bir sistemde (ELK, Application Insights vb.) toplandığından emin olunuz.


Yorumlar (0)
Yorum Yaz