aee0f09db8
- Datafabrik: Dockerfile fix, agentorkestrering fungerar - Vision: Identify-modell, FAISS, OCR alla testade - API: Alla 7 integrationstester passerade - Upplösare: Entitetsupplösning verifierad
150 lines
4.3 KiB
Python
150 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Reality Latency Audit
|
|
Spårar varje tidsstämpel i kedjan för att hitta flaskhalsar
|
|
"""
|
|
import sqlite3
|
|
import json
|
|
from datetime import datetime, timedelta
|
|
from pathlib import Path
|
|
|
|
DB_PATH = "/home/bernt/.openclaw/workspace/rivp-pilot-1/rivp.db"
|
|
AUDIT_FILE = "/home/bernt/.openclaw/workspace/life-weather/latency_audit.json"
|
|
|
|
def audit_latency():
|
|
"""Granska latency i hela kedjan"""
|
|
conn = sqlite3.connect(DB_PATH)
|
|
c = conn.cursor()
|
|
|
|
# Hämta senaste observation med alla tidsstämplar
|
|
c.execute("""
|
|
SELECT
|
|
id,
|
|
road_id,
|
|
observation_type,
|
|
value,
|
|
timestamp,
|
|
created_at,
|
|
source
|
|
FROM weather_observations
|
|
ORDER BY id DESC
|
|
LIMIT 1
|
|
""")
|
|
|
|
row = c.fetchone()
|
|
if not row:
|
|
print("Inga observationer att granska")
|
|
return
|
|
|
|
obs_id, road_id, obs_type, value, timestamp, created_at, source = row
|
|
|
|
# Konvertera tidsstämplar
|
|
now = datetime.now()
|
|
|
|
# Source timestamp (när SMHI mätte)
|
|
source_time = datetime.fromisoformat(timestamp.replace('Z', '+00:00').replace('+00:00', ''))
|
|
|
|
# Created timestamp (när vi sparade)
|
|
created_time = datetime.fromisoformat(created_at)
|
|
|
|
# Beräkna latencies
|
|
source_to_fetch = (created_time - source_time).total_seconds() / 60
|
|
fetch_to_now = (now - created_time).total_seconds() / 60
|
|
total_latency = (now - source_time).total_seconds() / 60
|
|
|
|
audit = {
|
|
"observation_id": obs_id,
|
|
"road_id": road_id,
|
|
"type": obs_type,
|
|
"timestamps": {
|
|
"source": timestamp,
|
|
"fetched": created_at,
|
|
"audited": now.isoformat()
|
|
},
|
|
"latencies_min": {
|
|
"source_to_fetch": round(source_to_fetch, 2),
|
|
"fetch_to_now": round(fetch_to_now, 2),
|
|
"total": round(total_latency, 2)
|
|
},
|
|
"bottleneck": "fetch_to_now" if fetch_to_now > source_to_fetch else "source_to_fetch"
|
|
}
|
|
|
|
# Spara audit
|
|
audits = []
|
|
if Path(AUDIT_FILE).exists():
|
|
with open(AUDIT_FILE) as f:
|
|
audits = json.load(f)
|
|
|
|
audits.append(audit)
|
|
|
|
with open(AUDIT_FILE, 'w') as f:
|
|
json.dump(audits[-100:], f, indent=2)
|
|
|
|
print(f"Latency Audit för observation {obs_id}:")
|
|
print(f" Source → Fetch: {source_to_fetch:.1f} min")
|
|
print(f" Fetch → Now: {fetch_to_now:.1f} min")
|
|
print(f" Total: {total_latency:.1f} min")
|
|
print(f" Bottleneck: {audit['bottleneck']}")
|
|
|
|
conn.close()
|
|
|
|
return audit
|
|
|
|
def analyze_latency_distribution():
|
|
"""Analysera latency-fördelning"""
|
|
if not Path(AUDIT_FILE).exists():
|
|
print("Ingen audit-data än")
|
|
return
|
|
|
|
with open(AUDIT_FILE) as f:
|
|
audits = json.load(f)
|
|
|
|
if not audits:
|
|
print("Ingen audit-data än")
|
|
return
|
|
|
|
total_latencies = [a["latencies_min"]["total"] for a in audits]
|
|
|
|
total_latencies.sort()
|
|
|
|
p50 = total_latencies[len(total_latencies) // 2]
|
|
p95 = total_latencies[int(len(total_latencies) * 0.95)]
|
|
p99 = total_latencies[int(len(total_latencies) * 0.99)] if len(total_latencies) > 100 else p95
|
|
|
|
print(f"\nLatency Distribution (n={len(total_latencies)}):")
|
|
print(f" P50: {p50:.1f} min")
|
|
print(f" P95: {p95:.1f} min")
|
|
print(f" P99: {p99:.1f} min")
|
|
print(f" Min: {min(total_latencies):.1f} min")
|
|
print(f" Max: {max(total_latencies):.1f} min")
|
|
|
|
return {
|
|
"p50": p50,
|
|
"p95": p95,
|
|
"p99": p99,
|
|
"min": min(total_latencies),
|
|
"max": max(total_latencies)
|
|
}
|
|
|
|
if __name__ == "__main__":
|
|
print("="*60)
|
|
print("REALITY LATENCY AUDIT")
|
|
print("="*60)
|
|
|
|
audit = audit_latency()
|
|
distribution = analyze_latency_distribution()
|
|
|
|
print("\n" + "="*60)
|
|
print("REKOMMENDATION:")
|
|
print("="*60)
|
|
|
|
if audit and audit["latencies_min"]["fetch_to_now"] > 60:
|
|
print("⚠️ Fetch-to-now latency är för hög (>60 min)")
|
|
print(" Åtgärd: Kör pipelinen oftare (var 15 min istället för varje timme)")
|
|
|
|
if distribution and distribution["p95"] > 60:
|
|
print("⚠️ P95 latency överstiger 60 min")
|
|
print(" Åtgärd: Optimera pipeline-körtid eller öka frekvens")
|
|
|
|
print("="*60)
|