feat: havuz izleme — ölçüm geçmişi, ani düşüş/eksik yükleme uyarısı, /api/health/havuz
This commit is contained in:
@@ -49,6 +49,17 @@ CREATE INDEX IF NOT EXISTS idx_idare ON sonuclar(idare_adi);
|
||||
CREATE INDEX IF NOT EXISTS idx_il ON sonuclar(il);
|
||||
CREATE INDEX IF NOT EXISTS idx_tarih ON sonuclar(ihale_tarihi);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS havuz_olcum (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
zaman TEXT NOT NULL,
|
||||
kaynak_toplam INTEGER, -- ilan.gov.tr'nin bildirdiği numFound
|
||||
yuklenen INTEGER, -- bizim havuzumuza giren kayıt
|
||||
eksik INTEGER, -- kaynak_toplam - yuklenen
|
||||
dt INTEGER, -- doğrudan temin kaydı
|
||||
arsiv INTEGER -- geçmiş sonuç arşivi
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_havuz_zaman ON havuz_olcum(zaman);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tarama_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
baslangic TEXT, bitis TEXT,
|
||||
@@ -224,3 +235,75 @@ export function logScan(db, row) {
|
||||
VALUES (?,?,?,?,?,?,?,?)`)
|
||||
.run(row.baslangic, row.bitis, row.aralikBas, row.aralikSon, row.taranan, row.eklenen, row.hata, row.not || null);
|
||||
}
|
||||
|
||||
|
||||
// --- Havuz izleme ----------------------------------------------------------
|
||||
// Havuz büyüklüğü kaynağa (ilan.gov.tr) bağlı ve gün içinde ciddi dalgalanıyor.
|
||||
// Ölçümleri saklarız ki "veri mi kayboldu, kaynak mı düştü" sorusu bir daha
|
||||
// tahmine kalmasın.
|
||||
|
||||
/** Bir ölçüm kaydeder ve önceki ölçüme göre ani düşüş olup olmadığını döndürür. */
|
||||
export function havuzOlc({ kaynakToplam, yuklenen, dt = null, arsiv = null }) {
|
||||
const db = openDb({ create: true });
|
||||
if (!db) return null;
|
||||
try {
|
||||
const onceki = db
|
||||
.prepare('SELECT zaman, kaynak_toplam, yuklenen FROM havuz_olcum ORDER BY id DESC LIMIT 1')
|
||||
.get() || null;
|
||||
|
||||
db.prepare(
|
||||
`INSERT INTO havuz_olcum (zaman, kaynak_toplam, yuklenen, eksik, dt, arsiv)
|
||||
VALUES (?,?,?,?,?,?)`
|
||||
).run(
|
||||
new Date().toISOString(),
|
||||
kaynakToplam ?? null,
|
||||
yuklenen ?? null,
|
||||
kaynakToplam != null && yuklenen != null ? kaynakToplam - yuklenen : null,
|
||||
dt, arsiv
|
||||
);
|
||||
|
||||
// 90 günden eski ölçümleri at — bu tablo sınırsız büyümemeli.
|
||||
const sinir = new Date(Date.now() - 90 * 864e5).toISOString();
|
||||
db.prepare('DELETE FROM havuz_olcum WHERE zaman < ?').run(sinir);
|
||||
|
||||
return degerlendir(onceki, { kaynakToplam, yuklenen });
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
|
||||
/** Ölçümü önceki ölçümle karşılaştırır; uyarı gerekiyorsa açıklamasını döndürür. */
|
||||
function degerlendir(onceki, { kaynakToplam, yuklenen }) {
|
||||
const sonuc = { uyari: null, onceki: onceki?.kaynak_toplam ?? null, simdi: kaynakToplam ?? null };
|
||||
|
||||
// 1) Kaynak düştü mü? (bizim hatamız değil ama bilmek isteriz)
|
||||
if (onceki?.kaynak_toplam > 0 && kaynakToplam != null) {
|
||||
const oran = kaynakToplam / onceki.kaynak_toplam;
|
||||
if (oran < 0.5) {
|
||||
sonuc.uyari = `Kaynak havuzu %${Math.round((1 - oran) * 100)} düştü: ` +
|
||||
`${onceki.kaynak_toplam} → ${kaynakToplam} ilan (ilan.gov.tr tarafı).`;
|
||||
sonuc.tur = 'kaynak_dusus';
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Biz kaynağın gerisinde mi kaldık? (bu BİZİM hatamız olur)
|
||||
if (!sonuc.uyari && kaynakToplam > 0 && yuklenen != null && yuklenen < kaynakToplam * 0.9) {
|
||||
sonuc.uyari = `Havuz eksik yüklendi: kaynakta ${kaynakToplam}, bizde ${yuklenen} ilan.`;
|
||||
sonuc.tur = 'eksik_yukleme';
|
||||
}
|
||||
|
||||
return sonuc;
|
||||
}
|
||||
|
||||
/** Son ölçümler — /api/health/havuz ve arayüz için. */
|
||||
export function havuzGecmisi(limit = 60) {
|
||||
const db = openDb();
|
||||
if (!db) return [];
|
||||
try {
|
||||
return db
|
||||
.prepare('SELECT zaman, kaynak_toplam, yuklenen, eksik, dt, arsiv FROM havuz_olcum ORDER BY id DESC LIMIT ?')
|
||||
.all(Math.min(Number(limit) || 60, 500));
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user