Files
mesh-configs/skills/devops/web-hosting-deployment/references/gtfs-route-pdf-cache.md
T

2.6 KiB
Raw Blame History

GTFS-Verbindungs-PDF: Offline-Precompute statt Live-Routing (2026-08-19)

Bewährt für urlaub.perfekt-ohne-en.de (Flask + SQLite + GTFS-Zugdaten). Wenn eine Einzel-Verbindungs-PDF eine komplette Fahrplan-Verbindung inkl. Haltestellenliste zeigen soll, darf die Flask-Route den Router/RAPTOR/Dijkstra nicht bei jedem Request ausführen.

Symptom

wkhtmltopdf + RAPTOR auf großen Knoten (Köln, Berlin) lief 40–200 s je Aufruf → nginx 504 Gateway Timeout (Gateway-Zeitlimit überschritten). Nutzer meldete „Wenn ich die PDF anklicke … keine Haltestellenliste".

Fix: einmaliger Offline-Backfill → JSON-Cache → schneller Cache-Read

  1. Precompute-Skript (gtfs_pfade_cache.py): iteriert SELECT DISTINCT von,nach aus urlaub.db, ruft für jedes Paar router.path(von,nach) (liefert Segmentliste der Zwischenhalte), schreibt pfade_cache.json:
    {"<von>|<nach>": {"seg": [["Halt1","Halt2",...]], "dauer_h": 1.5}}
    
  2. Flask-Route liest NUR json.load(open('/opt/<app>/pfade_cache.json')) mit Key f"{start}|{ziel}" → Antwort < 1 s, kein Timeout. Nie den Router zur Laufzeit importieren/rechnen.
  3. Skript als Hintergrund-Job (background=true, notify_on_complete) laufen lassen, nicht foreground.

Teilmenge wählen, sonst quadratische Backfill-Zeit

Eindeutige von|nach über ALLE Ebenen waren 10 510 Paare → ~2,4 s/Paar = ~7 h. Auf die Ebenen 1+2 (WHERE ebene IN (1,2), ~1 979 Paare) beschränkt = ~35 min. Ebene-3 (Kleinstädte) = reine Verzweigung ohne eigene PDFs → weglassen.

  • Trefferquote ist KEINE 100 % (Radevormwald/Kleinstädte ohne Bahnhof im Feed). Template ehrlich auf „Keine GTFS-Haltestellenliste verfügbar" zurückfallen, nie erfinden.

Pfad-Rekonstruktion muss dasselbe Abfahrtsprofil wie die Dauer nutzen

Ein Precompute mit fester Abfahrtszeit (09:00) rekonstruierte nur ~34 % der Pfade, weil viele Verbindungen erst zu späteren Tageszeiten existieren. Die Dauer-Profile-Suche (06–22 Uhr) liefert mehr Treffer — die Pfad-Rekonstruktion muss dasselbe Profil durchlaufen statt fest 09:00, sonst bleibt die Trefferquote konsistent niedrig.

Verifikation

# Service nach Template-/Code-Änderung neu starten, dann:
curl -sk -o /dev/null -w "PDF: %{http_code} (%{time_total}s)\n" \
  "https://<sub>/pdf/<von>/<nach>"
# Erwartung: 200 in <1 s (nicht 504), Haltestellenliste enthalten sobald Cache da.

Flask läuft mit debug=False (systemd) → nach Änderung IMMER systemctl restart (wg. Template-/Code-Reload-Pitfall, siehe Haupt-SKILL).