yenilemede ihale detay onbelleğini tazele
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Resmî ihale detayları için süreli, sınırlı bellek önbelleği.
|
||||
*
|
||||
* Liste yenilense bile detay metni ayrı bir kaynaktan geldiği için sınırsız
|
||||
* süre saklanamaz; zeyilname veya tarih değişikliği eski ayrıntıyı geçersiz
|
||||
* kılmalıdır. Saat bağımlılığını test edebilmek için now parametresi açıktır.
|
||||
*/
|
||||
export function createDetailCache({ maxEntries = 500, ttlMs = 10 * 60 * 1000 } = {}) {
|
||||
if (!Number.isInteger(maxEntries) || maxEntries < 1) throw new Error('Detay önbelleği sınırı geçersiz.');
|
||||
if (!Number.isFinite(ttlMs) || ttlMs <= 0) throw new Error('Detay önbelleği süresi geçersiz.');
|
||||
const entries = new Map();
|
||||
return {
|
||||
get(key, now = Date.now()) {
|
||||
const entry = entries.get(key);
|
||||
if (!entry) return undefined;
|
||||
if (now - entry.fetchedAt >= ttlMs) {
|
||||
entries.delete(key);
|
||||
return undefined;
|
||||
}
|
||||
return entry.value;
|
||||
},
|
||||
set(key, value, now = Date.now()) {
|
||||
entries.delete(key);
|
||||
entries.set(key, { value, fetchedAt: now });
|
||||
while (entries.size > maxEntries) entries.delete(entries.keys().next().value);
|
||||
},
|
||||
clear() { entries.clear(); },
|
||||
get size() { return entries.size; },
|
||||
};
|
||||
}
|
||||
+8
-4
@@ -64,6 +64,7 @@ import { belgeyeSor, teklifDenetle, teklifTaslak, ihaleMetni, gereklilikMetni }
|
||||
import { subscribe, list as listSubs, remove as removeSub, deliveryQueue, resolveDelivery, available as notifyAvailable } from './notify-store.mjs';
|
||||
import { bildirimleriIsle } from './notifier.mjs';
|
||||
import { scanSite } from './site-scan.mjs';
|
||||
import { createDetailCache } from './detail-cache.mjs';
|
||||
|
||||
// ilan.gov.tr sunucusu ara sertifikayı (GeoTrust TLS RSA CA G1) göndermiyor;
|
||||
// zinciri tamamlamak için PEM'i yerelden ekliyoruz.
|
||||
@@ -336,7 +337,7 @@ function htmlToText(htmlStr) {
|
||||
.trim();
|
||||
}
|
||||
|
||||
const cache = { tenders: null, fetchedAt: 0, totalCount: 0, todayCount: 0, detail: new Map() };
|
||||
const cache = { tenders: null, fetchedAt: 0, totalCount: 0, todayCount: 0, detail: createDetailCache() };
|
||||
|
||||
let arkaPlanDoluyor = false;
|
||||
|
||||
@@ -596,6 +597,9 @@ async function getTenders(force = false) {
|
||||
if (fresh && !force) return cache;
|
||||
|
||||
const ilk = await ilanSayfalari(0, ILK_PARTI);
|
||||
// Listeyi zorla yenileyen kullanıcı güncel kaynak ayrıntısını da görmeli;
|
||||
// eski detay metni yeni kartla birleştirilmemeli.
|
||||
if (force) cache.detail.clear();
|
||||
const numFound = ilk.find((r) => r.numFound)?.numFound || 0;
|
||||
const ads = ilk.flatMap((r) => r.ads || []);
|
||||
|
||||
@@ -624,17 +628,17 @@ async function getTenders(force = false) {
|
||||
}
|
||||
|
||||
async function getDetail(ilanId) {
|
||||
if (cache.detail.has(ilanId)) return cache.detail.get(ilanId);
|
||||
const cached = cache.detail.get(ilanId);
|
||||
if (cached) return cached;
|
||||
const raw = await ilanDetail(ilanId);
|
||||
const text = htmlToText(raw.content || '');
|
||||
const detail = { ...announcementFields(text), adNo: raw.adNo || null };
|
||||
const sourceTender=cache.tenders.find(t=>t.id===`ilan-${ilanId}`);
|
||||
const sourceTender=(cache.tenders || []).find(t=>t.id===`ilan-${ilanId}`);
|
||||
if(sourceTender) {
|
||||
try { observeTenders([{...sourceTender,...detail,id:`ilan-${ilanId}:detail`}]); }
|
||||
catch { detail.sourceWarning='İlan alındı ancak kaynak geçmişi kaydedilemedi.'; }
|
||||
}
|
||||
cache.detail.set(ilanId, detail);
|
||||
if (cache.detail.size > 500) cache.detail.delete(cache.detail.keys().next().value);
|
||||
return detail;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user