ASP.NET Core'da BackgroundService ve IHostedService ile Arka Plan İşleri
ASP.NET Core uygulamalarında kullanıcı isteğini bekletmeden arka planda çalışan periyodik görevleri ve kuyruk tüketicilerini BackgroundService ile nasıl kurduğumu anlatıyorum.
- ASP.NET Core
- .NET
- BackgroundService
- Backend
- Otomasyon
Web uygulamalarında her işlemi kullanıcının başlattığı HTTP isteği süresi içinde tamamlamak zorunda değiliz. E-posta bildirimlerinin gönderilmesi, harici bir API'den periyodik veri senkronizasyonu yapılması veya süresi dolan kayıtların temizlenmesi gibi işleri arka plan servislerine (Background Tasks) devretmek, API yanıt sürelerini ciddi ölçüde iyileştirir. ASP.NET Core, herhangi bir harici pakete ihtiyaç duymadan BackgroundService sınıfıyla bu altyapıyı yerleşik olarak sunuyor.
1. BackgroundService ve PeriodicTimer Kullanımı
Periyodik çalışan bir arka plan görevi yazarken eski Task.Delay döngüleri yerine modern .NET'teki PeriodicTimer yapısını kullanmak hem bellek açısından verimlidir hem de iptal belirteçlerini (CancellationToken) çok temiz yönetir:
public class DataSyncWorker : BackgroundService
{
private readonly IServiceScopeFactory _scopeFactory;
private readonly ILogger<DataSyncWorker> _logger;
public DataSyncWorker(
IServiceScopeFactory scopeFactory,
ILogger<DataSyncWorker> logger)
{
_scopeFactory = scopeFactory;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
using var timer = new PeriodicTimer(TimeSpan.FromMinutes(15));
while (await timer.WaitForNextTickAsync(stoppingToken))
{
try
{
using var scope = _scopeFactory.CreateScope();
var syncService = scope.ServiceProvider.GetRequiredService<ISyncService>();
await syncService.RunSyncAsync(stoppingToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Periyodik veri senkronizasyonu sırasında hata oluştu.");
}
}
}
}
2. En Sık Yapılan Hata: Scoped Servisleri Doğrudan Enjekte Etmek
BackgroundService uygulama boyunca tekil (Singleton) olarak yaşar. Ancak DbContext veya repository sınıfları genellikle istek bazlı (Scoped) olarak kaydedilir. Eğer DbContext'i doğrudan BackgroundService constructor'ına enjekte ederseniz yaşam döngüsü çakışması (captive dependency) yaşanır. Bu yüzden yukarıdaki örnekte olduğu gibi IServiceScopeFactory enjekte edip her döngü adımında yeni bir scope oluşturmak en doğru pratiktir.
3. Döngü İçinde Hata Yakalama (Try-Catch) Zorunluluğu
ExecuteAsync içindeki while döngüsünde yakalanmayan bir istisna (exception) fırlatılırsa arka plan servisi sessizce durabilir veya tüm host'u kapatabilir. Bu nedenle döngünün her adımını bir try-catch bloğu içine alarak hatayı loglamak ve bir sonraki periyotta servisin çalışmaya devam etmesini sağlamak kritik önem taşır.
Sonuç
Doğru scope yönetimi ve hata yakalama disipliniyle kurgulanan BackgroundService sınıfları, otomasyon ve veri senkronizasyonu işlerini ekstra altyapı maliyeti olmadan güvenle yürütmenizi sağlar.
Bu yazıyı faydalı buldunuz mu? LinkedIn'de takip ederek yeni yazılardan haberdar olabilirsiniz.Found this article helpful? Follow me on LinkedIn to stay updated on new posts.
LinkedIn'de Takip EtFollow on LinkedIn