auto-sync: 2026-04-20 02:10:01

This commit is contained in:
Stream
2026-04-20 02:10:01 +03:00
parent 8e37569b31
commit d340784762
3 changed files with 51 additions and 4 deletions

View File

@@ -355,7 +355,26 @@ def monitoring_status():
LIMIT 20
"""
)
return ok({"latest": latest, "history": history})
# live unprocessed count
unprocessed = query_one(
"""
SELECT
(SELECT COALESCE((state_value->>'last_raw_packet_id')::bigint, 0)
FROM fr24.processing_state WHERE state_key = 'preprocess_cursor') AS cursor_id,
(SELECT MAX(raw_packet_id) FROM fr24.raw_packets) AS max_id,
(SELECT COUNT(*) FROM fr24.raw_packets) AS total
"""
)
if unprocessed:
cursor_id = unprocessed["cursor_id"] or 0
max_id = unprocessed["max_id"] or 0
total = unprocessed["total"] or 0
pending = max(0, max_id - cursor_id)
pending_pct = round(pending / total * 100, 1) if total else 0
unprocessed_info = {"pending": pending, "pending_pct": pending_pct, "total": total}
else:
unprocessed_info = None
return ok({"latest": latest, "history": history, "unprocessed": unprocessed_info})
except Exception as e:
return err(str(e))

View File

@@ -165,6 +165,11 @@
<div class="value neutral" id="m-tput"></div>
<div class="unit">пакетов / 5 мин</div>
</div>
<div class="card">
<div class="label">Обработано</div>
<div class="value neutral" id="m-pending"></div>
<div class="unit" id="m-pending-unit">пакетов</div>
</div>
</div>
<h2>История (последние 20)</h2>
@@ -209,13 +214,20 @@
el.className = 'value ' + (colorClass || 'neutral');
}
function renderLatest(d) {
function renderLatest(d, unprocessed) {
setMetric('m-disk', d.disk_pct, diskColor(d.disk_pct));
const [dbVal, dbUnit] = fmtDb(d.db_size_mb);
setMetric('m-db', dbVal);
document.getElementById('m-db-unit').textContent = dbUnit;
setMetric('m-lag', d.capture_lag_sec, lagColor(d.capture_lag_sec));
setMetric('m-tput', d.throughput_5min.toLocaleString());
if (unprocessed) {
const pct = 100 - unprocessed.pending_pct;
const color = pct >= 95 ? 'green' : pct >= 80 ? 'yellow' : 'red';
setMetric('m-pending', pct.toFixed(1) + '%', color);
document.getElementById('m-pending-unit').textContent =
`обработано (${(unprocessed.total - unprocessed.pending).toLocaleString()} из ${unprocessed.total.toLocaleString()})`;
}
}
function renderHistory(rows) {
@@ -243,7 +255,7 @@
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
banner.style.display = 'none';
if (data.latest) renderLatest(data.latest);
if (data.latest) renderLatest(data.latest, data.unprocessed);
if (data.history) renderHistory(data.history);
document.getElementById('last-updated').textContent =
'Обновлено: ' + new Date().toLocaleTimeString('ru-RU');

View File

@@ -87,6 +87,21 @@ def run_checks():
)
throughput = cur.fetchone()[0]
# Unprocessed packets (cursor lag)
cur.execute(
"""
SELECT
(SELECT COALESCE((state_value->>'last_raw_packet_id')::bigint, 0)
FROM fr24.processing_state WHERE state_key = 'preprocess_cursor') AS cursor_id,
(SELECT MAX(raw_packet_id) FROM fr24.raw_packets) AS max_id,
(SELECT COUNT(*) FROM fr24.raw_packets) AS total
"""
)
row = cur.fetchone()
cursor_id, max_id, total_packets = row if row else (0, 0, 0)
unprocessed = max(0, (max_id or 0) - (cursor_id or 0))
unprocessed_pct = round(unprocessed / total_packets * 100, 1) if total_packets else 0
# Write metrics row
disk_pct_int = int(disk_pct_str) if disk_pct_str not in ("?",) else None
db_size_mb = db_bytes / (1024 ** 2)
@@ -124,7 +139,8 @@ def run_checks():
disk_display = f"{disk_pct_str}%" if disk_pct_str != "?" else "?"
print(
f"[monitor] disk={disk_display} db_size={db_size_str} "
f"capture_lag={lag_str} throughput={throughput}pkt/5min",
f"capture_lag={lag_str} throughput={throughput}pkt/5min "
f"unprocessed={unprocessed}({unprocessed_pct}%)",
flush=True,
)