Giriş
Modern web uygulamalarında kullanıcı deneyimi kritik öneme sahiptir. Uzun süren işlemler (e-posta gönderimi, rapor oluşturma, veri işleme) kullanıcıyı bekletmemeli ve HTTP request timeout'larına sebep olmamalıdır. Bu noktada background job processing devreye girer.
Hangfire, .NET ekosisteminde en popüler açık kaynak background job processing kütüphanesidir. Bu kapsamlı rehberde, Hangfire'ın özelliklerini, kullanım senaryolarını ve production'a hazır implementasyon detaylarını inceleyeceğiz.
Hangfire Nedir?
Hangfire, ASP.NET uygulamalarında background job'ları yönetmek için kullanılan açık kaynak bir kütüphanedir. En önemli özelliği, herhangi bir Windows Service veya ayrı process gerektirmeden, mevcut web uygulamanız içinde çalışabilmesidir.
Fire-and-Forget
Bir metodu arka planda çalıştır ve unut
Delayed Jobs
Belirli bir süre sonra çalıştırılacak job'lar
Recurring Jobs
Cron ifadeleri ile periyodik job'lar
Continuation
Bir job bittikten sonra çalışacak job'lar
Dashboard
Job'ları izlemek için web arayüzü
Auto Retry
Başarısız job'ları otomatik yeniden deneme
Neden Hangfire?
Hangfire'ın Avantajları
- Kolay kurulum ve kullanım (5 dakikada başlayabilirsiniz)
- Built-in dashboard ile görselleştirme
- Kod değişikliği gerektirmeden mevcut metotları background job yapabilme
- SQL Server, PostgreSQL, MySQL, Redis gibi birden fazla storage desteği
- Otomatik retry ve error handling mekanizması
- Açık kaynak ve aktif topluluk desteği
Kurulum
1. NuGet Paket Yükleme
Install-Package Hangfire Install-Package Hangfire.SqlServer // veya PostgreSQL için Install-Package Hangfire.PostgreSql
2. Startup Configuration
using Hangfire;
using Hangfire.SqlServer;
// Service Registration
builder.Services.AddHangfire(configuration => configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage("ConnectionString"));
builder.Services.AddHangfireServer();
// Pipeline Configuration
app.UseHangfireDashboard("/hangfire");
Job Türleri
1. Fire-and-Forget Jobs
Bir metodu arka planda bir kez çalıştırır ve sonucu beklemez.
Kullanım Senaryoları
- E-posta gönderimi
- SMS bildirim gönderme
- Log kaydı oluşturma
- Dosya yükleme sonrası işleme
- Webhook çağrısı yapma
// E-posta servisini arka planda çalıştır
BackgroundJob.Enqueue<EmailService>(x =>
x.SendWelcomeEmail(user.Email, user.Name));
2. Delayed Jobs
Belirli bir süre sonra çalıştırılacak job'lar.
// 14 gün sonra hatırlatma gönder
BackgroundJob.Schedule<ReminderService>(
x => x.SendTrialExpirationReminder(user.Id),
TimeSpan.FromDays(14));
// Veya belirli bir tarihte
BackgroundJob.Schedule<ReminderService>(
x => x.SendTrialExpirationReminder(user.Id),
new DateTime(2024, 12, 31, 23, 59, 59));
3. Recurring Jobs
Belirli aralıklarla sürekli çalışan job'lar. Cron ifadeleri ile yapılandırılır.
RecurringJob.AddOrUpdate<ReportService>(
"daily-report",
x => x.GenerateDailyReport(),
Cron.Daily(3)); // Her gün saat 03:00'te
Cron Expression Örnekleri
Cron.Minutely()- Her dakikaCron.Hourly()- Her saat başıCron.Daily()- Her gün gece yarısıCron.Weekly()- Her haftaCron.Monthly()- Her ay"*/15 * * * *"- Her 15 dakikada bir"0 9-17 * * *"- 09:00 - 17:00 arası her saat
4. Continuation Jobs
Bir job bittikten sonra çalışacak job'lar. İş akışları (workflows) oluşturmak için kullanılır.
// 1. Video upload
var jobId = BackgroundJob.Enqueue<VideoProcessingService>(
x => x.UploadVideo(filePath));
// 2. Upload bittikten sonra encoding
var encodeJobId = BackgroundJob.ContinueJobWith<VideoProcessingService>(
jobId,
x => x.EncodeVideo(null));
// 3. Encoding bittikten sonra thumbnail
BackgroundJob.ContinueJobWith<VideoProcessingService>(
encodeJobId,
x => x.GenerateThumbnail(null));
Dashboard ve Monitoring
Hangfire Dashboard, job'larınızı yönetmek ve izlemek için güçlü bir web arayüzü sunar.
Dashboard Bölümleri
- Enqueued: Sırada bekleyen job'lar
- Processing: Şu anda işlenen job'lar
- Scheduled: Zamanlanmış job'lar
- Succeeded: Başarılı tamamlanan job'lar
- Failed: Başarısız olan job'lar
- Recurring Jobs: Periyodik job'ların listesi
- Servers: Aktif Hangfire server'lar
Dashboard Güvenliği
Önemli!
Dashboard varsayılan olarak herkese açıktır. Production'da mutlaka güvenlik eklenmelidir.
public class HangfireAuthorizationFilter : IDashboardAuthorizationFilter
{
public bool Authorize(DashboardContext context)
{
var httpContext = context.GetHttpContext();
// Sadece Admin rolündeki kullanıcılar
return httpContext.User.IsInRole("Admin");
}
}
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
Authorization = new[] { new HangfireAuthorizationFilter() }
});
Error Handling ve Retry
Hangfire, başarısız job'ları otomatik olarak yeniden dener.
Varsayılan Retry Davranışı
- İlk retry: 15 dakika sonra
- İkinci retry: 1 saat sonra
- Üçüncü retry: 6 saat sonra
- Dördüncü retry: 12 saat sonra
- Beşinci retry: 24 saat sonra
- Toplam 10 kez denenir
Custom Retry Configuration
[AutomaticRetry(Attempts = 5, DelaysInSeconds = new[] { 60, 300, 900 })]
public void ProcessPayment(int orderId)
{
// Ödeme işleme mantığı
}
// Veya retry'ı devre dışı bırakma
[AutomaticRetry(Attempts = 0)]
public void SendSms(string phoneNumber, string message)
{
// SMS gönderme (retry'sız)
}
Performans Optimizasyonu
Worker Sayısı Yapılandırması
builder.Services.AddHangfireServer(options =>
{
options.WorkerCount = 20; // 20 paralel job işlenebilir
});
Best Practice
- CPU-intensive job'lar: Worker count = CPU core count
- I/O-intensive job'lar: Worker count = 2-5x CPU core count
Queue Önceliklendirme
builder.Services.AddHangfireServer(options =>
{
options.Queues = new[] { "critical", "default", "low" };
});
// Kritik job'ları öncelikli queue'ya atama
BackgroundJob.Enqueue<PaymentService>(
x => x.ProcessPayment(orderId),
new EnqueuedState("critical"));
Gerçek Dünya Senaryoları
E-Ticaret: Sipariş İşleme Pipeline
// 1. Validasyon
var validateJobId = BackgroundJob.Enqueue<OrderProcessingService>(
x => x.ValidateOrder(order.Id));
// 2. Ödeme işleme
var paymentJobId = BackgroundJob.ContinueJobWith<OrderProcessingService>(
validateJobId,
x => x.ProcessPayment(order.Id));
// 3. Stok güncelleme
var inventoryJobId = BackgroundJob.ContinueJobWith<OrderProcessingService>(
paymentJobId,
x => x.UpdateInventory(order.Id));
// 4. Paralel: Depo bildirimi ve e-posta
BackgroundJob.ContinueJobWith<OrderProcessingService>(
inventoryJobId,
x => x.NotifyWarehouse(order.Id));
SaaS: Kullanıcı Onboarding
// Hemen hoşgeldin e-postası
BackgroundJob.Enqueue<OnboardingService>(
x => x.SendWelcomeEmail(userId));
// 1 gün sonra: İlk adımlar
BackgroundJob.Schedule<OnboardingService>(
x => x.SendGettingStartedEmail(userId),
TimeSpan.FromDays(1));
// 28 gün sonra: Trial bitişi
BackgroundJob.Schedule<OnboardingService>(
x => x.ConvertToFreePlan(userId),
TimeSpan.FromDays(28));
Best Practices
Temel Prensipler
- Job'ları İdempotent Yapın: Aynı job iki kez çalışsa bile sorun çıkmamalı
- Küçük, Odaklanmış Job'lar: Her job tek bir sorumluluğa sahip olmalı
- Timeout Değerleri: Uzun süren işlemler için timeout belirleyin
- Structured Logging: Job ID ve parametreleri logla
- Queue Priority: Kritik job'ları öncelikli queue'lara atayın
İdempotency Örneği
// İyi: Idempotency check
public void SendEmail(int emailLogId)
{
var emailLog = _dbContext.EmailLogs.Find(emailLogId);
if (emailLog.IsSent)
{
_logger.LogInformation($"Email {emailLogId} already sent");
return;
}
_emailService.Send(emailLog.To, emailLog.Subject, emailLog.Body);
emailLog.IsSent = true;
_dbContext.SaveChanges();
}
Storage Seçenekleri
SQL Server
Avantajlar: ACID garantisi, transaction desteği
Kullanım: Orta ölçekli sistemler
PostgreSQL
Avantajlar: Açık kaynak, cross-platform
Kullanım: Maliyet-etkin çözümler
Redis
Avantajlar: Çok yüksek performans
Kullanım: Yüksek throughput gereken sistemler
Sonuç
Hangfire, .NET uygulamalarında background job processing için güvenilir, kullanımı kolay ve feature-rich bir çözümdür. Özellikle ASP.NET Core uygulamaları için doğal bir seçimdir.
Hangfire'ı Tercih Etmeniz Gereken Durumlar
- .NET / ASP.NET Core kullanıyorsunuz
- Hızlı başlamak istiyorsunuz (minimal configuration)
- Built-in dashboard istiyorsunuz
- Küçük-orta ölçekli job volume (saniyede 0-100 job)
- Ayrı infrastructure yönetmek istemiyorsunuz
Başlangıç Önerileri
- Basit Başlayın: Fire-and-forget job'larla başlayın
- Monitoring Kurun: İlk günden logging yapın
- İdempotency Düşünün: Job'ları idempotent tasarlayın
- Test Edin: Unit ve integration testleri yazın
- Dokümante Edin: Job'ların ne yaptığını belgelein
Background job processing, modern uygulamaların vazgeçilmez bir parçasıdır. Hangfire, bu ihtiyacı .NET ekosisteminde en kolay ve etkili şekilde karşılayan araçlardan biridir.
Küçük başlayın, öğrenin, ölçeklendirin. Background job processing yolculuğunuzda başarılar!