Blog
Mert Özen'in yazılım geliştirme, backend, frontend ve DevOps üzerine blog yazıları.
Kubernetes'te Storage ve Stateful Uygulamalar: Volume, PersistentVolumeClaim, StatefulSet ve Veritabanı Kararı
Birden fazla replica'nın aynı dosyaya yazması gerekiyorsa çözüm PVC değil object storage'dır; ReadWriteOnce tek pod değil tek node demektir. emptyDir sizeLimit eviction'ını, StorageClass ve reclaim policy'yi, StatefulSet ile PostgreSQL 18'i (yeni PGDATA yolu dahil), managed DB ile operator kararını ve replica'lar arasında kırılan ASP.NET Core Data Protection key ring'ini gerçek çıktılarla görüyoruz.
Migration'ların Deploy'daki Yeri: Expand-Contract, EF Core Migration Bundle ve Geriye Uyumlu Şema
Bir kolonu iki sürüm yan yana çalışırken güvenle bölmek üç deploy ister: ekle ve çift yaz, yeni kolonlara geç, eskiyi kaldır. PostgreSQL'de 300.000 satırla gerçek koşular: v1 ve v2'nin aynı şemada birlikte çalışması, CONCURRENTLY index'in transaction hatası, Npgsql'in transaction'a bağlı migration kilidi yüzünden paralel bundle'larda deadlock, 8 sn kilitleyen UPDATE yerine 135 ms'lik batch'ler ve DROP COLUMN'u durduran review gate.
GitHub Actions'ta Job'lar: needs, matrix, concurrency, timeout ve Service Container'lar
Job'lar varsayılan olarak paralel koşar; needs ile bir DAG kurulur, kırılan job'a bağlı her şey skipped olur. Bookstore CI'ını format, unit-test (OS matrix), integration-test (PostgreSQL 16/17/18 service container), web-build ve publish job'larına bölüp act ile koşturuyor; include/exclude, fail-fast, max-parallel, concurrency, timeout-minutes, continue-on-error ve Nisan 2026'da gelen service command/entrypoint'i inceliyoruz.
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.
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.
.NET'te Transactional Outbox: EF Core, BackgroundService Relay ve MassTransit/Wolverine Outbox
Mesajı broker'a değil, iş verisiyle aynı transaction'da bir outbox tablosuna yaz; bir BackgroundService relay'i satırları FOR UPDATE SKIP LOCKED ile alıp confirm'le yayınlasın. İki instance'ın 200 mesajı tek kez yayınladığı, broker kapalıyken 201 dönüp sonradan gönderdiği gerçek koşu; relay'in at-least-once ve sırasız olması, MassTransit bus outbox, Wolverine ve CDC.
System Design Case Study: Flash Sale ve Bilet Satışı
Flash sale'de overselling'i önleyen şey stok kontrolü ile azaltmanın tek atomik adımda yapılmasıdır; ani trafiği CDN'den sunulan bir waiting room emer, ödeme süresini TTL'li hold'lar yönetir, süresi dolan hold stoğu aynı statement'ta geri verir. 2.000 eşzamanlı alıcıyla 100 bilete naif kodun 2.000 rezervasyonu, koşullu UPDATE ve optimistic concurrency'nin gerçek çıktıları, ödeme timeout'u ve bot savunması.
Event Store ile Çalışmak: Marten ve PostgreSQL'de Append, Optimistic Concurrency ve Stream'ler
Event store'un temel sözleşmesi, bir stream'e yalnızca beklenen version'dayken event eklemektir; Marten bunu PostgreSQL'de (stream_id, version) unique index'i ve FetchForWriting ile sağlar. Marten 9 kurulumu, StartStream/Append, decider'ı FetchForWriting'e bağlamak, iki yazarın yarışı, stream id stratejileri, KurrentDB ve kendi tablonu yazmanın bedeli ve Türkçe culture'da bozulan event adları.
Ayrı Read Model: Materialized View, Senkronizasyon ve Eventual Consistency ile Yaşamak
Ayrı read model, ekranın satırını domain event'lerinden önceden hesaplayıp saklamaktır; aynı transaction'da güncellenirse tutarlılık anlık kalır, ayrı bir veritabanında asenkron güncellenirse eventual consistency ile yaşamak gerekir. Inline projection, PostgreSQL materialized view, checkpoint'li asenkron projector, read-your-own-writes için position ile bekleme, idempotent update ve sıfırdan rebuild, gerçek çıktılarla.
Tek Veritabanında CQRS: Write Tarafında Aggregate, Read Tarafında Projection
Tek veritabanında CQRS, yazma tarafında aggregate'i EF Core'un change tracker'ıyla kaydedip okuma tarafında aynı tablolardan aggregate'e hiç dokunmadan projection yapmaktır. PlaceOrder ve CancelOrder command'larının ne döndürmesi gerektiği, ayrı ve düz bir read DbContext, SQL view üstünde Dapper ve query'nin state değiştirmediğini PostgreSQL'e read-only transaction ile söyletmek, gerçek SQL ve 25006 hatasıyla.
Dapper ile Stored Procedure: Output, Return Value ve 2.1.11'in Otomatik Algılama Tuzağı
SQLite'ta stored procedure olmadığı için docker'daki SQL Server'a geçiyoruz: CommandType.StoredProcedure, DynamicParameters ile output ve return value, SET NOCOUNT'un Execute'a etkisi, 2.1.11'den beri tek kelimelik command'ların procedure sanılması ve PostgreSQL'de function ile procedure farkı.