From d3407847628e9c14977379eac4e05e2e49bda22e Mon Sep 17 00:00:00 2001 From: Stream Date: Mon, 20 Apr 2026 02:10:01 +0300 Subject: [PATCH] auto-sync: 2026-04-20 02:10:01 --- tasks/flightradar24/frontend/main.py | 21 ++++++++++++++++++- .../frontend/static/monitoring.html | 16 ++++++++++++-- tasks/flightradar24/monitoring/main.py | 18 +++++++++++++++- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/tasks/flightradar24/frontend/main.py b/tasks/flightradar24/frontend/main.py index b4f4d22..514ab9d 100644 --- a/tasks/flightradar24/frontend/main.py +++ b/tasks/flightradar24/frontend/main.py @@ -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)) diff --git a/tasks/flightradar24/frontend/static/monitoring.html b/tasks/flightradar24/frontend/static/monitoring.html index a911768..e8d9f61 100644 --- a/tasks/flightradar24/frontend/static/monitoring.html +++ b/tasks/flightradar24/frontend/static/monitoring.html @@ -165,6 +165,11 @@
пакетов / 5 мин
+
+
Обработано
+
+
пакетов
+

История (последние 20)

@@ -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'); diff --git a/tasks/flightradar24/monitoring/main.py b/tasks/flightradar24/monitoring/main.py index 2f82fbe..1e98f67 100644 --- a/tasks/flightradar24/monitoring/main.py +++ b/tasks/flightradar24/monitoring/main.py @@ -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, )