8 dk okuma
Giriş
.NET Worker Service kontrollü kapanış tasarımı, bir container yeniden başlatılırken veya servis dağıtım sırasında durdurulurken devam eden işin ne olacağını belirler. Yalnızca CancellationToken yakalayıp döngüden çıkmak yeterli değildir: yeni iş alımını kesmek, sürmekte olan işi tanımlı bir sınıra kadar tamamlamak ve bitmeyen işi tekrar denenebilir halde bırakmak gerekir.
Bu yazıda .NET 8 BackgroundService tabanlı bir tüketicinin kapanış akışını; host sinyali, kuyruk tüketimi, aktif iş, zaman bütçesi ve teslim garantisi açısından ele alıyorum. Örnek, belirli bir broker veya müşteri akışına bağlı değildir. Temel sonuç şudur: kontrollü kapanış kesintiyi azaltır, fakat tek başına mesajın kaybolmayacağını veya yalnızca bir kez işleneceğini garanti etmez.
Kapanış sinyali, iş kuyruğunu boşaltma, zaman aşımı ve yeniden deneme davranışını çalıştırılabilir .NET örneğiyle inceleyin.
GitHub Projesini İncele →İçindekiler
- .NET Worker Service kontrollü kapanışın sınırı
- Host sinyalini ve süre bütçesini yönetme
- Önce yeni işi durdurma
- Aktif işi iptal sinyaline bağlama
- Süre sınırı dolduğunda güvenli davranma
- Tekrar başlatma, yinelenen teslim ve gözlemlenebilirlik
- Dağıtım ortamında doğrulama
1. .NET Worker Service kontrollü kapanışın sınırı
Generic Host, uygulama kapanırken hosted service bileşenlerine StopAsync çağrısı yapar. BackgroundService.ExecuteAsync metoduna verilen durdurma token'ı bu yaşam döngüsüyle ilişkilidir; işin tamamını temsil eden görev sona ermeden host da kapanışı tamamlamaya çalışır. Microsoft dokümantasyonu, StopAsync için varsayılan süre sınırının 30 saniye olduğunu ve ani süreç çökmesinde StopAsync çağrısının gerçekleşmeyebileceğini belirtir.
Bu yüzden kapanış mantığı iki ayrı durumu tanımalıdır: host'un nazikçe durma isteği ve sürecin aniden sonlanması. İlkinde uygulama iş alımını kesebilir ve aktif işlemi bekleyebilir. İkincisinde uygulama kodunun son temizlik adımlarına güvenilemez. Her işin kalıcı bir kuyrukta tutulması ve tekrar teslim edildiğinde güvenli işlenmesi gerekir.
2. Host sinyalini ve süre bütçesini yönetme
Container platformu çoğunlukla önce sürece durdurma sinyali gönderir, belirlenen bekleme süresi bitince süreci sonlandırabilir. Bu iki zaman bütçesi birbiriyle uyumlu olmalıdır: uygulamanın HostOptions.ShutdownTimeout değeri, orkestratörün termination grace period değerinden küçük kalmalı; aradaki fark logların ve kaynakların kapanmasına zaman bırakmalıdır.
Host sınırını yapılandırırken süreyi körlemesine artırmak yerine gerçek iş süresi dağılımını ölçün. Örneğin uygulama shutdown süresini 45 saniyeye çıkarıyorsa container'a da bundan daha uzun bir kapanış penceresi verin. İşin dış bağımlılığa yaptığı çağrılar ayrıca timeout taşımalı; aksi halde tek bir takılmış HTTP veya veritabanı isteği bütün kapanışı tüketebilir.
3. Önce yeni işi durdurma
Kuyruk tüketimi ile aktif iş yürütmesini aynı işlem gibi düşünmeyin. Kapanış başladığında ilk hedef yeni teslimatların yerel işleyiciye alınmasını önlemektir. Broker kullanılıyorsa consumer'ı iptal etmek veya pause etmek, uygulama içi Channel kullanılıyorsa writer tarafını tamamlamak uygun olabilir. Bu adım devam eden işlerin süresini görünür ve sınırlı hale getirir.
Çoklu consumer senaryosunda yalnızca bir worker'ın token'ını iptal edip diğer consumer'ları açık bırakmak kapanışın tamamlandığı anlamına gelmez. Kapanış koordinatörü tüketicileri durdurduktan sonra aktif görevlerin tamamlanmasını beklemeli; servis kayıtları ve Dispose sırası da kullanılan istemci kütüphanesinin yaşam döngüsüyle uyumlu olmalıdır.
4. Aktif işi iptal sinyaline bağlama
ExecuteAsync içindeki bekleme, kuyruk okuma ve işleme metotlarına stoppingToken aktarılmalıdır. Token, işi sihirli biçimde durdurmaz; her bağımlılık bu sinyali gözlemlemeli ve kendi kaynaklarını bırakmalıdır. CancellationToken işbirliğine dayalı iptal modelidir. Senkron, uzun süre bloklayan veya token kabul etmeyen kod kapanışı geciktirir.
Örnek bir iş döngüsü şu fikri uygular: önce consumer teslimatı alır, sonra işi işler ve başarıdan sonra ack verir. Kapanış sinyali aktif işin ortasında gelirse işlem sınırları işin doğasına göre belirlenmelidir. Güvenle tamamlanabilecek kısa bir iş bitirilebilir; uzun bir işte iptal, ara durum kaydı veya yeniden deneme gerekebilir. Dış çağrılar için ayrı timeout ve CancellationTokenSource.CreateLinkedTokenSource ile ortak iptal sınırı tanımlamak, kapanış davranışını test etmeyi kolaylaştırır.
Kritik ayrım şudur: iptal token'ı teslimatı otomatik olarak kuyruğa geri koymaz. Ack öncesi process ölürse broker redelivery yapabilir; ack erken verilirse fakat iş tamamlanmazsa veri kaybı riski oluşur. Bu nedenle ack, kalıcı iş etkisinin başarıyla tamamlandığı noktaya bağlanmalıdır.
5. Süre sınırı dolduğunda güvenli davranma
Kapanış süresinin sonuna gelindiğinde uygulama iki kötü uçtan kaçınmalıdır: sınırsız beklemek ve işi başarıyla bitmiş gibi işaretlemek. Bekleme iptal edildiyse consumer kanalını kapatın, kaynakları dispose edin ve tamamlanmayan işin tekrar teslim edilebileceği düzeni koruyun. Bu davranışın broker'a göre değiştiğini adapter arkasında açıkça tanımlayın.
Bir shutdown timeout, işlem garantisi değildir; yalnızca host'un ne kadar bekleyeceğini belirler. İşlem tamamlama penceresi, container'ın sert kill süresinden önce bitmelidir. Ortalama süre yerine p95/p99 işlem sürelerini ve dış bağımlılık gecikmesini ölçerek güvenli pencere seçin.
6. Tekrar başlatma, yinelenen teslim ve gözlemlenebilirlik
Kapanışta tekrar kuyruğa dönen bir mesaj yeni süreçte yeniden işlenebilir. Bu nedenle işleyici idempotent olmalı; aynı iş anahtarı ikinci kez geldiğinde önceki tamamlanmanın etkisini tekrarlamamalıdır. Bu konu, sitedeki ASP.NET Core API’lerde idempotency yazısıyla yakından ilişkilidir. Bir entegrasyon akışında kayıt ile mesaj yayımını tutarlı hale getirmek için Transactional Outbox makalesi da tamamlayıcı okumadır.
Kapanış için en azından durdurma başlangıç zamanı, consumer cancel sonucu, aktif iş sayısı, tamamlanan işler, iptal edilen işler ve kapanış süresini kaydedin. Loglarda hassas yükleri taşımadan bir correlation veya iş kimliği kullanın. Metriklerde 'kapanışta bekleyen iş', 'kapanış zaman aşımı', 'yeniden teslim' ve 'işleme süresi' ayrımı, deploy sonrasında problemin uygulamadan mı yoksa kuyruk ayarından mı geldiğini gösterir.
Örnek olay çalışması olarak pazaryeri iade entegrasyonu projesi farklı sistemler arasında veri senkronizasyonu ihtiyacını gösterir. Buradaki makale genel tasarım ilkeleriyle sınırlıdır; müşteri alan eşlemelerini, özel servis ayrıntılarını veya ticari akışları açıklamaz.
7. Dağıtım ortamında doğrulama
Sadece Ctrl+C ile test etmek yeterli değildir. Container'ı normal durdurma komutuyla kapatın, aktif iş sırasında durdurun, kuyruk boşken kapatın ve dış bağımlılığın geciktiği bir senaryo deneyin. Her senaryoda yeni işlerin durduğunu, aktif işin politikasına göre tamamlandığını veya yeniden teslim edilebilir kaldığını doğrulayın.
Uygulama ve platform zaman aşımı değerlerini birlikte gözden geçirin. Linux servis yöneticisi, container runtime ve orchestrator farklı sinyaller veya bekleme sınırları uygulayabilir. Son doğrulama üretimde kullanılan aynı image, aynı sağlık kontrolü ve aynı process entrypoint ile yapılmalıdır. Örnek repository bu sınırları küçük bir Worker Service ve sahte kuyruk adapter'ı ile yeniden üretilebilir hale getirir.
Sonuç
.NET Worker Service kontrollü kapanış için sağlam sıra basittir: durdurma sinyalini al, yeni teslimatı kes, aktif işi sınırlandırılmış süreyle bekle, tamamlanmayan işi yeniden denenebilir bırak ve kaynakları kapat. Bu sıra mesaj kaybı riskini azaltır; fakat gerçek teslimat garantisi için kalıcı kuyruk, ack politikası ve idempotent işleyici birlikte tasarlanmalıdır.
Kapanışı bir kod satırı değil, uygulama ile dağıtım platformu arasındaki sözleşme olarak ele alın. Ölçülen iş süresiyle uyumlu bir zaman penceresi belirleyin, kesinti senaryolarını düzenli test edin ve tekrar teslim durumunu görünür kılın.
Güvenilir Araştırma Kaynakları
Microsoft Learn — Background tasks with hosted services in ASP.NET Core: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-10.0
Microsoft Learn — Worker Services in .NET: https://learn.microsoft.com/en-us/dotnet/core/extensions/workers
Microsoft Learn — Generic Host: https://learn.microsoft.com/en-us/dotnet/core/extensions/generic-host
Microsoft Learn — CancellationToken: https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken?view=net-10.0

