From dd714762dc3dd5a534be8078b236461d2c16e46b Mon Sep 17 00:00:00 2001 From: irrlicht Date: Wed, 17 Jun 2026 23:57:33 +0200 Subject: [PATCH] Statistik: Impression-Erfassung asynchron (nicht im Request-Pfad) Der Seitenaufruf wartete bisher synchron auf den DB-Upsert. Mit synchronous=FULL (WAL) macht SQLite pro Commit ein fsync -> spuerbare Latenz pro Seitenaufruf. Die Erfassung laeuft jetzt in einer Goroutine, die Auslieferung blockiert nicht mehr darauf. Der GeoIP-Lookup war nie das Problem (mmap, einmal beim Start geoeffnet). Co-Authored-By: Claude Opus 4.8 --- stats.go | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/stats.go b/stats.go index 3d756c2..4d8e958 100644 --- a/stats.go +++ b/stats.go @@ -92,14 +92,22 @@ func lookupASN(ip net.IP) string { // und vermerkt das autonome System. Die IP wird zuerst maskiert; sowohl die // Speicherung als auch die ASN-Auflösung arbeiten nur auf dem anonymisierten // Netz. Gezielt nur auf den HTML-Seiten-Routen, nicht auf API oder Assets. +// +// Die Erfassung läuft asynchron: der Seitenaufruf darf nicht auf den DB-Schreib +// warten (SQLite serialisiert Schreiber, synchronous=FULL macht pro Commit ein +// fsync). r ist nach Rückkehr des Handlers nicht mehr sicher nutzbar -> wir +// kopieren die zwei Werte vorher heraus. func trackImpression(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - netw := maskIP(clientIP(r.RemoteAddr)) - anon := "" - if netw != nil { - anon = netw.String() - } - recordImpression(r.URL.Path, anon, lookupASN(netw)) + remote, path := r.RemoteAddr, r.URL.Path + go func() { + netw := maskIP(clientIP(remote)) + anon := "" + if netw != nil { + anon = netw.String() + } + recordImpression(path, anon, lookupASN(netw)) + }() next.ServeHTTP(w, r) }) }