Kapitel 15: Fejlfindingsrunbook¶
Målgruppe: DevOps, platformingeniører
Login-loop¶
Symptomer: Brugeren rammer loginsiden, autentificerer sig, omdirigeres tilbage til loginsiden, og loopet gentager sig uendeligt.
Grundårsagsmønster: Enhver databasefejl forårsager, at _get_or_create_oauth2_user() fejler tavst. /auth/check returnerer {authenticated: false}. Frontenden omdirigerer til /oauth2/sign_in. Loop.
Typiske udløsere: - Cloud SQL Proxy-containeren døde eller blev genstartet uden at genstarte API'et - Netværkspartitionering mellem VM og Cloud SQL-instans - Cloud SQL-instansvedligeholdelse eller genstart
Detektion:
- Browser: omdirigeringstælleren udløses efter 2 omdirigeringer inden for 30 sekunder og viser en fejl/genprøv-brugerflade i stedet for at loope
- API: /auth/check returnerer HTTP 503 (ikke 200), når databasen er utilgængelig, med auth_error i svaret
- Logfiler: kig efter "connection refused" eller timeout-fejl i catscan-api-logfilerne
Løsning:
1. Tjek Cloud SQL Proxy: sudo docker ps | grep cloudsql
2. Hvis nede: sudo docker compose -f docker-compose.gcp.yml restart cloudsql-proxy
3. Vent 10 sekunder, genstart derefter API'et:
sudo docker compose -f docker-compose.gcp.yml restart api
4. Verificér: curl -sS http://localhost:8000/health
Forebyggelse: Trelagsrettelsen (implementeret feb. 2026):
1. Backend propagerer DB-fejl via request.state.auth_error
2. /auth/check returnerer 503, når DB er utilgængelig
3. Frontend har omdirigeringstæller (maks. 2 på 30 s) + fejl/genprøv-brugerflade
Datafriskheds-timeout¶
Symptomer: /uploads/data-freshness returnerer 500, timer ud, eller runtime-sundhedsgaten viser BLOCKED på datasundhed.
Grundårsagsmønster: Datafriskhedsforespørgslen scanner store tabeller (rtb_daily med 84M rækker, rtb_bidstream med 21M rækker). Hvis forespørgselsplanen degraderer til en sekventiel scanning i stedet for at bruge indekser, kan det tage 160+ sekunder.
Detektion: 1. Kald endpointet direkte fra VM'en:
curl -sS --max-time 60 -H 'X-Email: cat-scan@rtb.cat' \
'http://localhost:8000/uploads/data-freshness?days=14&buyer_id=<ID>'
sudo docker exec catscan-api python -c "
import os, psycopg
conn = psycopg.connect(os.environ['POSTGRES_DSN'])
for r in conn.execute('EXPLAIN (ANALYZE, BUFFERS) <query>').fetchall():
print(list(r.values())[0])
"
Parallel Seq Scan på store tabeller. Det er problemet.
Løsningsmønster:
- Omskriv GROUP BY-forespørgsler som generate_series + EXISTS for at tvinge indeksopslag. Se Databaseoperationer for mønsteret.
- Sørg for at SET LOCAL statement_timeout bruges (ikke SET + RESET).
- Kontrollér at indekserne (buyer_account_id, metric_date DESC) eksisterer på alle måltabeller.
Gmail-importfejl¶
Symptomer: Datafriskhedsgitteret viser "manglende" celler for nylige datoer. Importhistorikken har ingen nye poster.
Detektion:
curl -sS -H 'X-Email: cat-scan@rtb.cat' \
http://localhost:8000/gmail/status
Tjek: last_reason, unread-antal, latest_metric_date.
Typiske årsager:
- Gmail OAuth-token udløbet: genautoriser på /settings/accounts > Gmail-fanen
- Cloud SQL Proxy nede: Gmail-import skriver til Postgres, så DB skal være tilgængelig
- Stort unread-antal (30+): import kan sidde fast i behandling, eller postkassen har en efterslæb
Løsning:
1. Hvis last_reason viser en fejl: genstart importjobbet fra brugerfladen eller API'et
2. Hvis tokenet er udløbet: genautoriser Gmail-integrationen
3. Hvis Cloud SQL er nede: løs databaseforbindelsen først (se login-loop)
Container-genstartsrækkefølge¶
Symptom: API-logfiler viser "connection refused" til port 5432 ved opstart.
Årsag: API-containeren startede før Cloud SQL Proxy var klar.
Løsning: Genstart med korrekt rækkefølge:
sudo docker compose -f docker-compose.gcp.yml up -d cloudsql-proxy
sleep 10
sudo docker compose -f docker-compose.gcp.yml up -d api
Eller genstart alt (compose håndterer afhængigheder):
sudo docker compose -f docker-compose.gcp.yml up -d --force-recreate
SET statement_timeout-syntaksfejl¶
Symptom: Endpoint returnerer 500 med fejlen:
syntax error at or near "$1" LINE 1: SET statement_timeout = $1
Årsag: psycopg3 konverterer %s til $1 for server-side parameterbinding, men PostgreSQL's SET-kommando understøtter ikke parameterplaceholders.
Løsning: Brug f-string med valideret integer:
# Wrong:
conn.execute("SET statement_timeout = %s", (timeout_ms,))
# Right:
timeout_ms = max(int(statement_timeout_ms), 1) # validated int
conn.execute(f"SET LOCAL statement_timeout = {timeout_ms}")
Fejl i runtime-sundhedsgate¶
Symptom: Workflowet v1-runtime-health-strict.yml fejler.
Fejlsøgning:
1. Tjek workflowlogfilerne: gh run view <id> --log-failed
2. Kig efter FAIL vs. BLOCKED:
- FAIL = noget gik i stykker, undersøg det
- BLOCKED = afhængighed mangler (ingen data, intet endpoint), kan være forudeksisterende
3. Typiske forudeksisterende BLOCKED-årsager:
- "rtb_quality_freshness state is unavailable": ingen kvalitetsdata for denne køber/periode
- "proposal has no billing_id": dataopsætningsproblem
- "QPS page API rollup missing required paths": analyseendpoint ikke udfyldt endnu
4. Sammenlign med tidligere kørsler for at identificere regressioner vs. forudeksisterende problemer.
Relateret¶
- Sundhedsovervågning: overvågningsværktøjer
- Databaseoperationer: forespørgsels- og indeksdetaljer
- Udrulning: udrulning af rettelser