dotnet csharp hangfire backend web-development

ASP.NET Core’da Arka Plan İşlerini Hangfire ve Recurring Jobs ile Ustaca Yönetin

Projenizi kilitlenmelerden kurtarın: Hangfire kurulumu, arka plan iş türleri ve tekrarlayan görevler (Recurring Jobs) üzerine pratik bir rehber.

ASP.NET Core’da Arka Plan İşlerini Hangfire ve Recurring Jobs ile Ustaca Yönetin

Harika bir web uygulaması geliştirdiniz. Her şey tıkır tıkır çalışıyor. Derken patronunuz ya da müşteriniz geldi ve dedi ki: "Her gece saat 00:00'da günün özet raporunu PDF yapıp yönetime e-posta atalım. Bir de her saat başı pasif kullanıcıları kontrol edip hatırlatma gönderelim."

İlk refleks olarak hemen System.Threading.Timer veya Task.Run ile bir şeyler yapmayı düşünebilirsiniz. Ya da Controller içinde uzun süren bir işlemi tetikleyip kullanıcının dakikalarca beklemesine sebep olabilirsiniz. Aman dikkat! ASP.NET Core uygulamanız yeniden başladığında (IIS AppPool recycle, Docker container restart vb.) hafızadaki timer'lar uçar, yarıda kalan işler kaybolur.

İşte bu noktada imdadımıza Hangfire yetişiyor. Bu yazıda, Hangfire’ın ne olduğunu, projenize nasıl entegre edeceğinizi ve özellikle Recurring Jobs (Tekrarlayan Görevler) yapısını pratik örneklerle inceleyeceğiz.


Hangfire Nedir ve Bize Ne Sağlar?

Hangfire, .NET dünyasında arka plan işlerini (background jobs) kolayca oluşturmanızı, yönetmenizi ve takip etmenizi sağlayan açık kaynaklı harika bir kütüphanedir.

Öne çıkan en büyük avantajları:

  • Kalıcılık (Persistence): İşlerinizi hafızada değil, SQL Server, PostgreSQL veya Redis gibi bir veri tabanında tutar. Uygulama çökse bile kaldığı yerden devam eder.
  • Dahili Dashboard: Kod yazmadan arka plan işlerinin durumunu izleyebileceğiniz görsel bir arayüz sunar.
  • Otomatik Retry: Başarısız olan bir iş olursa belirlediğiniz kurallara göre otomatik olarak tekrar dener.
  • Kolay Kurulum: Birkaç NuGet paketi ve birkaç satır konfigürasyon ile kullanıma hazırdır.

1. Kurulum ve Yapılandırma

Gelin sıfırdan küçük bir ASP.NET Core Web API projesine Hangfire ekleyelim. İlk olarak gerekli NuGet paketlerini projemize yüklüyoruz:

bash

dotnet add package Hangfire.AspNetCore

dotnet add package Hangfire.SqlServer

(Not: Öğrenme aşamasında SQL yerine bellek içi depolama için Hangfire.MemoryStorage paketini de tercih edebilirsiniz.)

Şimdi Program.cs dosyamıza girip Hangfire servislerini ve arayüzünü (Dashboard) tanımlayalım:

C# / .NET KOD PARÇACIĞIKOD
using Hangfire;
using Hangfire.SqlServer;

var builder = WebApplication.CreateBuilder(args);

// 1. Hangfire Servislerini Ekleme
string connectionString = builder.Configuration.GetConnectionString("DefaultConnection") 
                          ?? "Server=.;Database=HangfireDb;Trusted_Connection=True;TrustServerCertificate=True;";

builder.Services.AddHangfire(config => config
    .SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
    .UseSimpleAssemblyNameTypeSerializer()
    .UseRecommendedSerializerSettings()
    .UseSqlServerStorage(connectionString, new SqlServerStorageOptions
    {
        CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
        SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
        QueuePollInterval = TimeSpan.Zero,
        UseRecommendedIsolationLevel = true,
        DisableGlobalLocks = true
    }));

// 2. Hangfire Sunucusunu Ekleme (İşleri arka planda işleyen motor)
builder.Services.AddHangfireServer();

builder.Services.AddControllers();

var app = builder.Build();

// 3. Hangfire Dashboard Arayüzünü Etkinleştirme
app.UseHangfireDashboard("/hangfire");

app.MapControllers();

app.Run();


Uygulamayı çalıştırıp tarayıcınızdan `https://localhost:xxxx/hangfire` adresine gittiğinizde sizi harika bir yönetim paneli karşılayacak!

2. Hangfire İş Türleri (Kısaca)

Hangfire temel olarak 4 farklı iş modelini destekler:

1. Fire-and-Forget: Tek seferlik hemen çalışan işler.

2. Delayed Jobs: Belirli bir süre sonra çalışacak işler.

3. Continuation Jobs: Bir iş bittikten hemen sonra onu takip eden işler.

4. Recurring Jobs: Belirli zaman aralıklarıyla sürekli tekrarlanan CRON görevleri.

Bugün ana odağımız projelerin bel kemiği olan Recurring Jobs.


3. Recurring Jobs ile Çalışmak

Tekrarlayan işler (Recurring Jobs), Linux dünyasındaki Cron Job mantığıyla çalışır. Hangfire, Cron sınıfı sayesinde karmaşık Cron ifadelerini akılda tutmak zorunda kalmadan kullanmamızı sağlar.

Gelin senaryomuzu kodlayalım: Sistemimizde her sabah saat 08:00'de günlük rapor oluşturan ve her saat başı önbellek temizleyen bir servisimiz olsun.

Önce raporlama servisimizi yazalım:

C# / .NET KOD PARÇACIĞIKOD
public interface IReportService
{
    Task GenerateDailyReportAsync();
    Task ClearCacheAsync();
}

public class ReportService : IReportService
{
    private readonly ILogger<ReportService> _logger;

    public ReportService(ILogger<ReportService> logger)
    {
        _logger = logger;
    }

    public async Task GenerateDailyReportAsync()
    {
        _logger.LogInformation(" Günlük sistem raporu oluşturuluyor... Timestamp: {Time}", DateTime.UtcNow);
        
        // Uzun süren işlem simülasyonu
        await Task.Delay(2000);
        
        _logger.LogInformation(" Günlük sistem raporu başarıyla oluşturuldu ve e-posta atıldı.");
    }

    public async Task ClearCacheAsync()
    {
        _logger.LogInformation(" Önbellek temizleme işlemi başladı...");
        await Task.Delay(500);
        _logger.LogInformation(" Önbellek temizlendi.");
    }
}


Servisimizi Dependency Injection (DI) konteynerine kaydetmeyi unutmayalım:

csharp
builder.Services.AddScoped<IReportService, ReportService>();


Şimdi bu metotları **RecurringJob** olarak tanımlayalım! `Program.cs` içerisinde `app.Run()` satırından hemen önce şu kodları ekliyoruz:

csharp
// Dependency Injection kullanarak Recurring Job tanımlama
using (var scope = app.Services.CreateScope())
{
    var recurringJobManager = scope.ServiceProvider.GetRequiredService<IRecurringJobManager>();

    // 1. Her saat başı çalışacak önbellek temizleme görevi
    recurringJobManager.AddOrUpdate<IReportService>(
        "hourly-cache-clear", // İşin benzersiz ID'si
        service => service.ClearCacheAsync(),
        Cron.Hourly // Cron ifadesi
    );

    // 2. Her sabah 08:00'de çalışacak günlük rapor görevi
    recurringJobManager.AddOrUpdate<IReportService>(
        "daily-report-job",
        service => service.GenerateDailyReportAsync(),
        "0 8 * * *" // Özel Cron ifadesi (Her gün 08:00)
    );
}

Özel Cron İfadeleri Kullanmak

Hangfire bize Cron.Daily(), Cron.Hourly(), Cron.Monthly() gibi hazır metotlar sunar. Ancak özel bir zamanlama isterseniz (örneğin "Her hafta içi saat 14:30'da") standart Cron string ifadelerini de string olarak geçebilirsiniz: "30 14 1-5".


4. Dikkat Edilmesi Gereken İpuçları (Best Practices)

Arka plan işleri yazarken junior ve orta seviye geliştiricilerin sıkça gözden kaçırdığı birkaç altın kural:

1. İşleriniz Idempotent (Yinelenebilir) Olsun: Bir iş hataya düşüp Hangfire tarafından tekrar denendiğinde, sistemde mükerrer veri oluşmamalıdır. E-posta atılıyorsa "gönderildi" bayrağı veritabanında kontrol edilmelidir.

2. Parametre Seçimi: Hangfire metotlarına devasa nesneler (DTO/Entity) parametre olarak geçmeyin. Sadece Id (GUID veya int) geçin ve metot içinde veritabanından güncel halini çekin. Çünkü Hangfire parametreleri JSON olarak serialize edip DB'ye kaydeder.

3. CancellationToken Kullanımı: Uzun süren işlerde CancellationToken kabul edin. Uygulama kapanırken Hangfire işi güvenli bir şekilde durdurabilsin.

C# / .NET KOD PARÇACIĞIKOD
public async Task GenerateDailyReportAsync(CancellationToken cancellationToken)
{
    // Uzun döngü veya async işlemlerde cancellationToken.ThrowIfCancellationRequested(); kullanın.
}

Özet

Hangfire, .NET ekosisteminde arka plan işi yönetimi için adeta biçilmiş kaftandır. Bizi karmaşık konfigürasyonlardan, zamanlayıcı hatalarından ve verim kayıplarından kurtarır. RecurringJob.AddOrUpdate yöntemi ile zamanlanmış görevlerinizi güvenle çalıştırabilir, Dashboard üzerinden durumlarını anlık izleyebilirsiniz.

Bir sonraki projenizde uzun süren veya periyodik işleriniz varsa Task.Run yazmadan önce mutlaka Hangfire'a bir şans verin!

Kodla kalın! 🚀