Mert Özen Her Satırda Daha İleri

Blog

Mert Özen'in yazılım geliştirme, backend, frontend ve DevOps üzerine blog yazıları.

Seriler
204 yazı bulundu
Background Job'larda Sürüm Geçişleri: .NET 6→10 BackgroundService Değişiklikleri, .NET 11 ve Quartz 3→4
Backend SERİ 11

Background Job'larda Sürüm Geçişleri: .NET 6→10 BackgroundService Değişiklikleri, .NET 11 ve Quartz 3→4

.NET 6 BackgroundService hatasında host'u durdurmaya başladı, ShutdownTimeout .NET 7'de 5'ten 30 saniyeye çıktı, .NET 8 lifecycle hook'larını getirdi, .NET 10 ExecuteAsync'in tamamını arka plana aldı: ilk await'ten önce fırlayan hata .NET 8'de process'i 134 koduyla düşürürken .NET 10'da loglanıp 0 koduyla çıkıyor. Quartz 3→4'te basit bir job tek bir CS0535 hatası verdi; asıl iş paketler, şema migration'ı ve değişen varsayılanlar.

8 Kas 2026 10 dk 5
Job Dashboard, Monitoring ve Alerting: Hangfire Dashboard, Quartz 4 Dashboard ve OpenTelemetry
Backend SERİ 10

Job Dashboard, Monitoring ve Alerting: Hangfire Dashboard, Quartz 4 Dashboard ve OpenTelemetry

Hangfire Dashboard varsayılan olarak yalnız local isteklere açık, ama aynı makinedeki bir proxy'den gelen istek de local sayılıyor: Docker üzerinden gelen istek 200 aldı. Production'da dashboard'u bir authorization policy'ye ve read-only moda bağla; Quartz 4 dashboard'u yetkilendirme olmadan hiç başlamıyor. "Son başarılı çalışma 26 saatten eski" health check'i, Quartz 4'ün OpenTelemetry span ve metric'leri ve JobId taşıyan structured log'lar görünürlüğü tamamlar.

8 Kas 2026 10 dk 5
Uzun Süren ve Batch Job'lar: Chunking, Checkpoint ve Deploy Sırasında Kesilmeye Dayanmak
Backend SERİ 09

Uzun Süren ve Batch Job'lar: Chunking, Checkpoint ve Deploy Sırasında Kesilmeye Dayanmak

2 milyon satırlık fiyat güncellemesini tek UPDATE ile yapmak, o sırada aynı satırı güncellemek isteyen bir isteği 1,9 saniye bekletti; 20.000'lik chunk'larla 4 ms. Her chunk'ı checkpoint satırıyla aynı transaction'da commit eden job, deploy'da 800.000. satırda durdu ve yeniden başlayınca oradan devam etti. Hangfire uzun job'ları sliding invisibility ile korur; process ölürse job bu süre dolunca başka bir worker'a geçer.

8 Kas 2026 11 dk 6
Çok Instance'lı Ortamda Job'lar: Distributed Lock, Leader Election ve Aynı İşin İki Kez Çalışması
Backend SERİ 08

Çok Instance'lı Ortamda Job'lar: Distributed Lock, Leader Election ve Aynı İşin İki Kez Çalışması

Üç replica'daki BackgroundService gece raporunu üç kez üretir; DistributedLock ile SQL Server sp_getapplock, PostgreSQL advisory lock ya da Redis üzerinden alınan bir lock bunu bire indirir. Lock'un sahibi kill -9 ile ölünce Redis'te lock 30 saniyelik lease bitene kadar kimsede kalmaz; PostgreSQL'de ise sunucu bağlantının koptuğunu fark edene kadar, denememde yaklaşık bir dakika, ölü process'te kaldı. Lock bir garanti değil, bir lease'tir.

8 Kas 2026 12 dk 5
Background Job'larda Retry ve Idempotency: At-Least-Once Gerçeğiyle Yaşamak
Backend SERİ 07

Background Job'larda Retry ve Idempotency: At-Least-Once Gerçeğiyle Yaşamak

Background job en az bir kez, bazen iki kez çalışır; retry bunu daha da olası kılar. Hangfire varsayılan olarak 10 kez artan aralıklarla dener, kalıcı hatalar ExceptOn ile retry'dan çıkarılır; Quartz 4'te retry policy açıkça tanımlanır. "Önce kontrol et, sonra gönder" iki eşzamanlı çalışmada iki e-posta üretir; unique key ile önce sahiplenmek tek e-postaya indirir, dış API'ye Idempotency-Key başlığı aynı işi uçtan uca yapar.

8 Kas 2026 12 dk 4
Quartz.NET 4 ile Scheduling: Job, Trigger, Persistent JobStore ve Clustering
Backend SERİ 06

Quartz.NET 4 ile Scheduling: Job, Trigger, Persistent JobStore ve Clustering

Quartz.NET 4'te job ve trigger ayrı nesnelerdir, IJob ValueTask döner ve CancellationToken alır; DI ve hosting çekirdek Quartz paketinde. Aynı PostgreSQL veritabanını paylaşan iki node bir cluster olur: çalışan node kill -9 ile ölünce diğeri yaklaşık 15 saniye sonra durumu fark eder ve RequestRecovery işaretli job'u recovering=true ile yeniden çalıştırır. Açılışta kod tanımı veritabanındaki JobDataMap'in üzerine yazar; IgnoreDuplicates bunu önler.

8 Kas 2026 11 dk 5
Hangfire ile Kalıcı Job'lar: Fire-and-Forget, Delayed, Recurring ve Continuation
Backend SERİ 05

Hangfire ile Kalıcı Job'lar: Fire-and-Forget, Delayed, Recurring ve Continuation

Hangfire bir method çağrısını tip adı, method adı, parametre tipleri ve JSON'a serialize edilmiş argümanlarla veritabanına yazar; restart'ta kaybolmaz ve varsayılan olarak 10 kez yeniden denenir. Bu yüzden argüman olarak yalnız id geçilir: DbContext serialize edilemez, entity ise bayat bir kopya olarak saklanır. Method'u yeniden adlandırınca kuyrukta bekleyen eski job'lar bulunamayan method hatasıyla retry'a düşer.

8 Kas 2026 10 dk 5
Cron İfadeleri: Unix 5 Alan, Saniyeli 6 Alan, Quartz Formatı ve Time Zone/DST Tuzakları
Backend SERİ 04

Cron İfadeleri: Unix 5 Alan, Saniyeli 6 Alan, Quartz Formatı ve Time Zone/DST Tuzakları

Unix cron 5 alanlıdır, Quartz saniyeyle başlayan 6–7 alan ister ve haftanın günlerini 1=pazar diye sayar; Quartz 4 "0 0 * * *"i varsayılan parser'la reddeder, CronFormat.Unix ile kabul eder. DST geçişinde 02:30'a kurulu günlük iş ilkbaharda 03:00'te bir kez, sonbaharda yalnız bir kez çalışır; aralıklı işler tekrarlanan saatte iki kez çalışır. Kendi cron scheduler'ını TimeProvider ile yazıp FakeTimeProvider ile test edebilirsin.

8 Kas 2026 13 dk 6
Worker Service ve In-Process Job Queue: Channel, PeriodicTimer ve Windows Service/systemd
Backend SERİ 03

Worker Service ve In-Process Job Queue: Channel, PeriodicTimer ve Windows Service/systemd

Bounded Channel ile kurulan in-process job queue, dolduğunda TryWrite false döner; endpoint bunu Retry-After başlıklı bir 503'e çevirerek backpressure uygular. Periyodik iş için PeriodicTimer kaçırılan tick'leri biriktirmez, uzun süren bir turdan sonra en fazla bir kez hemen tetiklenir. AddWindowsService ve AddSystemd yalnız ilgili ortamda devreye girer; queue ise restart'ta boşalır.

8 Kas 2026 10 dk 4
.NET'te IHostedService ve BackgroundService: Yaşam Döngüsü, Graceful Shutdown ve .NET 10 Davranış Değişikliği
Backend SERİ 02

.NET'te IHostedService ve BackgroundService: Yaşam Döngüsü, Graceful Shutdown ve .NET 10 Davranış Değişikliği

.NET 10'da BackgroundService.ExecuteAsync'in tamamı arka planda çalışır; ilk await'ten önceki kod artık startup'ı bloklamaz, erken çalışması gereken kod StartAsync'e ya da IHostedLifecycleService'e taşınır. Host kapanırken stoppingToken iptal edilir ve tüm durdurma işine varsayılan 30 saniyelik ShutdownTimeout verilir; token'ı taşımayan iş bu sürenin sonunda log bile bırakmadan kesilir.

8 Kas 2026 11 dk 5
Request Dışında İş Yapmak: Fire-and-Forget, BackgroundService, Hangfire ve Quartz.NET Arasında Seçim
Backend SERİ 01

Request Dışında İş Yapmak: Fire-and-Forget, BackgroundService, Hangfire ve Quartz.NET Arasında Seçim

Controller içinde Task.Run ile başlatılan iş, request scope'u kapanınca DbContext'i kaybeder, exception'ı sessizce yutar ve deploy'da yarıda kalır; işi host'un yönettiği bir yere devretmek gerekir. Seçimi beş soru belirler: iş restart'ta kaybolabilir mi, zamanlı mı, retry ve dashboard gerekir mi, kaç instance var; cevaplara göre BackgroundService, Hangfire, Quartz.NET ya da platform scheduler.

8 Kas 2026 10 dk 5
Client Sürüm Geçişleri: RabbitMQ.Client 6→7 (IModel'dan IChannel'a) ve MassTransit 8→9
Backend SERİ 14

Client Sürüm Geçişleri: RabbitMQ.Client 6→7 (IModel'dan IChannel'a) ve MassTransit 8→9

RabbitMQ.Client 7'ye geçiş ilk derlemede 5, ikinci dalgada 10 hata verdi; asıl riskler derleyicinin göstermediği body ömrü, timeout'un iptale dönmesi ve eşzamanlılık. RabbitMQ 4.x'te mirroring policy'sinin reddi, queue tipi uyuşmazlığı, AMQP 1.0 client'ı, MassTransit 9'un lisanssız açılmaması ve v8 desteğinin 31 Aralık 2026'da bitmesi, eski Service Bus SDK'sının karşılıkları.

8 Kas 2026 13 dk 7
Blog Haritası