HHangfire Handbook

TEMEL

Recurring Jobs (Cron)

Recurring job'lar CRON ifadelerine göre periyodik olarak çalıştırılan görevlerdir.

CRON Scheduler "0 9 * * *" (her gün 09:00) Enqueue Yeni instance Processing Worker çalıştırır Succeeded sonraki schedule

Karar Rehberi

Durum Öneri Örnek veya gerekçe
Günlük rapor Uygun Her gün 08:00 satış özeti
DB temizliği Uygun Haftalık soft-delete purge
Health check ping Uygun Her 5 dk uptime monitor
Event-driven tetikleme Uygun değil: Mesaj kuyruğu kullan Sipariş gelince stok düş
Gerçek zamanlı stream Uygun değil: Cron uygun değil WebSocket push

CRON İfadeleri

İfade Anlamı Hangfire Helper
* * * * * Her dakika Cron.Minutely
0 * * * * Her saat başı Cron.Hourly
0 9 * * * Her gün 09:00 Cron.Daily(9)
0 9 * * 1-5 Hafta içi 09:00 Cron.Daily(9) + custom
0 0 * * 0 Her Pazar gece yarısı Cron.Weekly
0 0 1 * * Ayın 1'i gece yarısı Cron.Monthly

Kullanım

// Program.cs veya Startup'ta
RecurringJob.AddOrUpdate<IDailyReportService>(
    "daily-sales-report",           // Unique job ID
    svc => svc.GenerateAsync(),
    Cron.Daily(9),                  // Her gün 09:00 UTC
    new RecurringJobOptions
    {
        TimeZone = TimeZoneInfo.FindSystemTimeZoneById("Turkey Standard Time")
    });

RecurringJob.AddOrUpdate<IDbMaintenanceService>(
    "weekly-purge-deleted",
    svc => svc.PurgeSoftDeletedAsync(TimeSpan.FromDays(30)),
    "0 3 * * 0",                   // Her Pazar 03:00
    new RecurringJobOptions
    {
        TimeZone = TimeZoneInfo.FindSystemTimeZoneById("Turkey Standard Time"),
        MisfireHandling = MisfireHandlingMode.Ignorable
    });

// Job'ı kaldır
RecurringJob.RemoveIfExists("daily-sales-report");

// Hemen tetikle (bir sonraki schedule'ı beklemeden)
RecurringJob.TriggerJob("daily-sales-report");

MisfireHandling

Uygulama kapalıyken bir recurring job'ın zamanı geçerse ne olur?

Mod Davranış Kullanım
Relaxed (varsayılan) Kaçırılan job çalıştırılır Rapor, bildirim — "geç de olsa çalışsın"
Ignorable Kaçırılan job atlanır Monitoring ping — eski veri anlamsız
Strict Kaçırılan her instance çalıştırılır Fatura kesilmesi — hiçbiri atlanmamalı

TimeZone uyarısı: Varsayılan UTC'dir. Türkiye'de sabah 9'da çalışmasını istiyorsanız mutlaka TimeZone parametresi verin. Aksi halde UTC 09:00 = Türkiye 12:00 olur.

Eş zamanlı çalışma riski: Recurring job'un bir önceki instance'ı henüz bitmeden yeni instance tetiklenebilir (uzun süren job + kısa cron aralığı). Önlemek için [DisableConcurrentExecution(timeoutInSeconds: 300)] attribute'ü ekleyin — bu, aynı job'ın aynı anda birden fazla instance'ının çalışmasını engeller. (Core — ücretsiz)

Ace alternatifi: Daha gelişmiş concurrency control istiyorsanız (dinamik resource-based locking, semaphore ile N-concurrent limit, rate limiting): Hangfire.Throttling paketi (Ace lisansı) → [Mutex("job-key")], [Semaphore("pool", limit: 5)]. Fark: DisableConcurrentExecution distributed lock tutar (timeout'a kadar bloklar), [Mutex] ise job'u reschedule eder (worker'ı bloklamaz).

Örnek: Bir SaaS uygulamasında her tenant için ayrı recurring job tanımlanır: daily-report-tenant-{tenantId}. Böylece her müşterinin raporu kendi timezone'unda doğru saatte oluşturulur. Tenant silindiğinde RemoveIfExists ile job da temizlenir.