""" Buggy FastAPI server for the incident1 scenario. Serves three endpoints and runs a background job worker thread. The worker crash-loops because it hits a poisoned DB record. """ import json import logging import os import sqlite3 import sys import threading import time import uvicorn from fastapi import FastAPI from fastapi.responses import JSONResponse logging.basicConfig( level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s", stream=sys.stdout, ) logger = logging.getLogger("buggy_server") app = FastAPI() _DB_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "app.db") def _get_conn() -> sqlite3.Connection: conn = sqlite3.connect(_DB_PATH) conn.row_factory = sqlite3.Row return conn # ── Endpoints ────────────────────────────────────────────────────────────── @app.get("/health") def health(): return {"status": "ok"} @app.get("/jobs") def list_jobs(): conn = _get_conn() rows = conn.execute( "SELECT id, payload, status FROM jobs ORDER BY id" ).fetchall() conn.close() return {"jobs": [dict(r) for r in rows]} @app.post("/checkout") def checkout(): """Process the next pending job. Returns 500 if the payload is malformed.""" conn = _get_conn() row = conn.execute( "SELECT * FROM jobs WHERE status='pending' ORDER BY id LIMIT 1" ).fetchone() if not row: conn.close() return {"status": "no_pending_jobs"} try: data = json.loads(row["payload"]) conn.execute( "UPDATE jobs SET status='completed' WHERE id=?", (row["id"],) ) conn.commit() conn.close() return {"status": "ok", "job_id": row["id"], "data": data} except Exception as exc: conn.close() return JSONResponse( status_code=500, content={"error": f"Serialization Error: {exc}", "job_id": row["id"]}, ) # ── Worker loop ──────────────────────────────────────────────────────────── def _worker_loop() -> None: """Run worker.process_jobs() in a tight restart loop (crash-loop visible in logs).""" # Ensure the workdir (where worker.py lives) is importable workdir = os.path.dirname(os.path.abspath(__file__)) if workdir not in sys.path: sys.path.insert(0, workdir) import worker while True: try: worker.process_jobs() except Exception as exc: logger.error("[WORKER CRASH] %s: %s", type(exc).__name__, exc) time.sleep(0.5) @app.on_event("startup") def _start_worker() -> None: t = threading.Thread(target=_worker_loop, daemon=True, name="worker-loop") t.start() logger.info("Worker thread started") if __name__ == "__main__": port = int(os.environ.get("BUGGY_SERVER_PORT", 9000)) uvicorn.run(app, host="0.0.0.0", port=port, log_config=None)