2026-04-04
Otomatik fiyat toplama sistemi
Manuel fiyat araması yapıyordum — analiz sayfasından otel seç, operatörleri seç, tarihleri seç, "Ara" düğmesine bas. Günde birkaç kez tekrarlaman lazım. Bunu otomatikleştirdim.
Temel fikir
Günde 3 kez (06:00, 14:00, 22:00) aktif otellerin fiyatlarını toplayan bir sistem. Bir turda eksik kalan veriler sonraki turda tamamlanıyor — %90 coverage'a ulaşana kadar retry yapıyor.
Cron tetikler → Her otel için paralel arama → Coverage hesapla
→ %90 altındaysa → Eksik slotları tekrar ara
→ %90 üstündeyse → Dur
Coverage nasıl hesaplanıyor
Unit: (AramaTarihi × Operatör) slot. Örnek: 5 tarih × 8 operatör = 40 slot. Her slotta en az bir HotelPrice kaydı varsa o slot dolu.
coverage = dolu slot / toplam slot × 100
Hedef %90. Neden %100 değil? Bazı operatörlerde bazı tarihlerde otel olmayabilir, o slotlar asla dolmaz. %90 gerçekçi bir hedef.
Retry'da sadece boş slotlar tekrar aranıyor. Zaten fiyatı olan slot'a tekrar istek atmak israf.
Paralel hotel dispatch
İlk versiyonda otelleri sırayla arıyordum. 10 otel × 8 operatör × ~30 saniye = çok uzun sürüyordu. Paralel hale getirdim:
scheduled-search:
max-concurrent-hotels: 5
5 otel aynı anda aranıyor. Dedicated thread pool: scheduledHotelExecutor — core ve max boyutu 5. Ana async executor'dan ayrı, birbirini bloklamasın diye.
Sonuç: ~35 dakikada tüm cycle tamamlanıyor. Ortalama %81 coverage, 13.000+ fiyat kaydı.
Operator throttling sorunu
5 otel paralel aranınca aynı operatöre aynı anda 5 istek gidebilir. SAMO sunucuları bunu sevmiyor — rate limit veya block riski var.
OperatorLaunchThrottleService yazdım. CAS-based (Compare-And-Swap), lock-free:
Operatör X'e son istek: 14:00:05
Yeni istek: 14:00:10 → 30 saniye geçmemiş → bekle
Yeni istek: 14:00:36 → 30 saniye geçmiş → geç
Her operatör için minimum 30 saniye aralık. AYAX ve AYAX_API bu throttle'dan muaf — kendi API'miz, rate limit yok.
İzolasyon
Her scheduled run'ın batch ID'si: sched-{runId}-d{searchDateId}. Manuel aramalarla karışmaması için prefix kullanıyorum. Analiz sayfasında "SCHEDULED" ve "DIRECT" olarak ayrı listeleniyor.
HikariCP pool boyutu
Paralel arama başlayınca DB connection pool tükendi. 5 otel × her biri birden fazla operatör × her biri transaction açıyor = default 10 connection yetmiyor.
hikari:
maximum-pool-size: 20
minimum-idle: 5
20'ye çıkardım. PostgreSQL tarafında da max_connections kontrol edilmeli.
Monitoring
Dashboard endpoint'i ekledim — her run'ın durumu, operatör bazında başarı/başarısızlık, coverage yüzdesi. Frontend'de tablo olarak gösteriliyor. Run history ile hangi run'da ne kadar veri toplandığını görebiliyorum.
GET /api/scheduled-search/dashboard → run listesi, operator detayları
POST /api/scheduled-search/trigger → manuel tetikleme
POST /api/scheduled-search/cancel-all → aktif run'ları iptal et
Manuel tetikleme de var — test ederken veya acil veri lazımsa düğmeye basıp cycle başlatabiliyorum.