Yürürlükteki her hayat ve emeklilik poliçesinin bir yıldönümü tarihi vardır. O tarihte sözleşme, bazı işlerin yapılmasını gerektirir: aktüeryal değerleme, bonus veya kar payı tahsisi, prim gecikmesi durumunda iptal değerlendirmesi, mevzuat raporlama bayrakları, bazen vergi yeniden hesaplaması, bazen poliçe sahibine bildirim, neredeyse her zaman bir yevmiye kaydı. Bunların hiçbiri isteğe bağlı değildir. Hem sözleşme hem de düzenleyici, bunun o gün gerçekleşmesini bekler.
Bunu birkaç milyon yürürlükteki poliçeyle çarpın, 365 takvim gününe aşağı yukarı eşit dağıtın ve elinizde her gün on binlerce sözleşmeye dokunan ve yasal olarak bağlayıcı çıktı üreten bir batch olur. Bu pipeline'ı yıllarca çalıştırdıktan sonra rahatlıkla şunu söyleyebilirim: hesaplama mantığı, işlerin bozulduğu yer nadiren olur. Asıl bozulan, zamanlama katmanıdır.
Naif Model ve Neden Başarısız Oluyor
Herhangi bir yıldönümü motorunun ilk versiyonu şöyle görünür:
- Bugünün tarihini al.
MOD(today - inception_date, 365) = 0veya eşdeğeri olan her aktif poliçeyi bul.- Her biri için yıldönümü prosedürünü çalıştır.
- Commit et.
UAT'de çalışır. Üretimde ilk yılı atlatır. Sonra başarısız olmaya başlar ve bu hatalar aktüeryal koddaki bug'lara hiç benzemez. Bir tarihin ne olduğu konusundaki felsefi anlaşmazlıklara benzer.
Bir Sözleşme İçin "Bugün" Gerçekte Ne Demektir?
Batch sigorta işlemlerinde, "bugün" en az dört farklı şeydir ve zamanlayıcı bunlardan birini seçip savunmak zorundadır:
- Takvim bugünü — iş başladığında duvar saatinin gösterdiği zaman.
- Muhasebe bugünü — açık olan kayıt dönemi; ay sonu kapanışı henüz çalıştırılmadıysa bu hâlâ dün olabilir.
- Efektif bugün — poliçenin yıldönümü olarak değerlendirdiği tarih; bu bir zaman damgası değil, hukuki bir kurgudur.
- Recovery bugünü — iki gün önceki başarısız bir çalıştırmadan sonra, bir yeniden çalıştırmanın taklit ettiği tarih.
Zamanlayıcınız bunların aynı olduğunu varsayarsa, eninde sonunda kapalı bir döneme bonus tahsisi kaydedeceksiniz veya sözleşmesindeki ödemesiz süresi yarın ama sistem saatinde bugün biten bir poliçe üzerinde iptal kontrolü çalıştıracaksınız. Her ikisi de raporlanması gereken olaylardır.
29 Şubat ve Diğer Takvim Düşmanlıkları
29 Şubat 2016'da düzenlenen bir poliçenin yıldönümü tam olarak ne zaman? Aynı portföydeki farklı ürünler buna farklı cevaplar veriyor. Bazıları artık olmayan yıllarda 28 Şubat'ı yıldönümü olarak değerlendirir. Bazıları 1 Mart'ı kullanır. Bazıları bir sonraki iş gününe öteler. Bazılarının ürün şartları kimse bunu düşünmeden önce yazılmıştır ve cevap, hukuk biriminin bu sabah ne karar vereceğine bağlıdır.
Zamanlayıcı bunu ürün bazında, yargı yetkisi bazında ve ideal olarak poliçe nesli bazında bilmek zorundadır, çünkü şartlar değişir ve eski poliçeler orijinal kurallarını korur. Artık yıllar için tek bir global kural, gelecekteki bir bug demektir.
Aynı durum şunlar için de geçerlidir:
- Ay sonu yıldönümleri (31 Ocak'ta düzenlenen bir poliçe — Şubat'ta yıldönümü nedir?).
- Hafta sonu ve tatil yönetimi; iş günü kaymaları ürün hattına göre farklılık gösterir.
- Yaz saati geçişleri; cutoff'unuz gece yarısı ve sunucularınız düzenleyicinizden farklı bir saat diliminde olduğunda, insanların düşündüğünden çok daha önemlidir.
Kimsenin Belgelemediği Sıralama Problemi
Yıldönümü işleme tek bir iş değildir. Bir zincirdir: değerleme bonus tahsisinden önce, bonus tahsisi vergiden önce, vergi GL kaydından önce, GL kaydı müşteri mektubu üretiminden önce çalışmalıdır. Her adımın kendi hata modu ve kendi idempotency sözleşmesi vardır.
İlginç hatalar şu durumlarda gerçekleşir:
- Değerleme 47.000 poliçe için başarılı olur, 12'si için başarısız olur ve birileri bonus işini bir tamamlanma sinyaline değil de zaman tetikleyicisine bağladığı için yine de başlar.
- Bir poliçe çalışma ortasında zeyilnamelendirilir. 1. adımdaki durumu artık 4. adımdaki durumuyla eşleşmez.
- Aynı takvim gününde bir reasürans devri çalışır ve aynı poliçe satırları üzerinde lock'lar için rekabete girer.
Çözüm daha iyi hata yönetimi değildir. Çözüm, yıldönümü çalışmasını adım başına değil, poliçe başına işlemsel bir birim olarak ele almaktır. Her poliçe ya tüm zincirden geçer ya da hiçbirinden geçmez ve orkestratör durumu iş başına değil, sözleşme başına takip eder.
Mimari Asıl Recovery'de Ortaya Çıkar
Batch'in başarısız olduğu gün — ve olacaktır — zamanlayıcınızın tasarlanmış mı yoksa derlenmiş mi olduğunu öğrendiğiniz gündür.
Olay sırasında değil, öncesinde cevaplanması gereken sorular:
- Dünkü çalışma yarıda kaldıysa, bugünkü çalışma dünden kalan poliçeleri alır mı, yoksa ayrı bir recovery işi mi onlarla ilgilenir? Buna kim karar verir?
- Bir poliçeyi yeniden çalıştırdığınızda, aşağı akıştaki sistemler mükerrer kaydı tespit eder mi, yoksa bonus'u keyifle iki kez mi defterleştirir?
- Bir poliçe dün yanlışlıkla iptal edildi ve bu sabah eski haline getirildiyse, bugünkü yıldönümü mantığı onu sürekli yürürlükte mi yoksa yeni bir sözleşme olarak mı görür?
- Zamanlayıcı, denetim izini kirletmeden belirli bir efektif tarih için tek bir poliçeyi talep üzerine çalıştırabilir mi?
Çalıştığım bir portföyde recovery, bir kontrol tablosunu manuel olarak düzenleyip işi yeniden başlatarak yönetiliyordu. Yıllarca işe yaradı. Aynı zamanda recovery yolunun her kullanıldığında test edilmemiş olduğu anlamına da geliyordu, yani her zaman.
Gerçekten İşe Yarayan
Birden fazla üretim döngüsünde ayakta kalan örüntüler:
- Takvimi yürütmeden ayırın. Zamanlayıcı, bir takvim servisine "X tarihinde efektif yıldönümü olan poliçeler hangileri?" diye sorar ve takvim servisi tüm artık yıl, ay sonu, tatil ve ürün kuralı mantığına sahiptir. Batch hiçbir zaman kendisi tarih aritmetiği yapmaz.
- Efektif tarihi bir varsayım değil, bir parametre yapın. Her iş
effective_date'i açıkça kabul eder. Üretim çalışmaları bugünü geçer. Recovery çalışmaları orijinal başarısız tarihi geçer. Yeniden çalıştırmalar, ilk çalıştırmalardan ayırt edilemez. - Poliçe başına efektif tarih başına idempotency anahtarları. Aşağı akıştaki sistemler mükerrerleri sezgilerle değil, anahtarla reddeder.
- İş başına değil, poliçe başına durum. Orkestratör, poliçe 12345'in 2024-06-14 efektif tarihi için 7 adımın 3.'sinde olduğunu bilir. Hatalar tüm çalışmaya değil, poliçelere izole olur.
- Commit'ler hariç her çıktıyı üreten bir dry-run modu. Her çeyrek sonu ve her ürün lansmanından önce kullanılır.
Gerçek Ders
Bir hayat sigortası batch'indeki hesaplama motoru, herkesin incelediği, test ettiği ve güvendiği parçadır. Aynı zamanda sabah 7'deki telefon görüşmesine neden olan parça nadiren odur. Zamanlama katmanı — bugün hangi poliçelerin, hangi sırayla, hangi efektif tarihle işleneceğine ve başarısız olduğunda ne olacağına karar veren şey — kurumsal riskin yaşadığı yerdir.
Ona olduğu mimari yüzey gibi davranın. Cron gibi değil.