From 1a667891ad5f899521b0a6c06f7755818bbea551 Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Thu, 12 Mar 2026 11:06:41 +0100 Subject: [PATCH 1/2] Adds metric for disconnects during upload catch exception raised and keep track of this metric --- ooniapi/services/ooniprobe/src/ooniprobe/metrics.py | 4 ++++ .../ooniprobe/src/ooniprobe/routers/reports.py | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ooniapi/services/ooniprobe/src/ooniprobe/metrics.py b/ooniapi/services/ooniprobe/src/ooniprobe/metrics.py index 324b5e116..e03d1dc0d 100644 --- a/ooniapi/services/ooniprobe/src/ooniprobe/metrics.py +++ b/ooniapi/services/ooniprobe/src/ooniprobe/metrics.py @@ -79,3 +79,7 @@ class Metrics: ) TEST_LIST_URLS_COUNT = Gauge("test_list_urls_count", "Size of reported test list") + + CLIENT_DISCONNECT = Counter( + "client_upload_disconnect", "Client disconnected while awaiting report" + ) diff --git a/ooniapi/services/ooniprobe/src/ooniprobe/routers/reports.py b/ooniapi/services/ooniprobe/src/ooniprobe/routers/reports.py index bdcbb9439..0b7e9dd31 100644 --- a/ooniapi/services/ooniprobe/src/ooniprobe/routers/reports.py +++ b/ooniapi/services/ooniprobe/src/ooniprobe/routers/reports.py @@ -8,6 +8,7 @@ import httpx from fastapi import Request, Response, APIRouter, Header +from starlette.requests import ClientDisconnect from pydantic import Field import zstd @@ -142,7 +143,16 @@ async def receive_measurement( Metrics.MSMNT_DISCARD_CC_ZZ.inc() return empty_measurement - data = await request.body() + try: + data = await request.body() + except ClientDisconnect: + log.info(f"Client disconnected mid-upload") + Metrics.CLIENT_DISCONNECT.inc() + return empty_measurement + except Exception as e: + log.error(f"Uncaught exception {e}") + return empty_measurement + if content_encoding == "zstd": try: compressed_len = len(data) From d123d8c06fd6329f6a19d9793f67222d5ea2ba54 Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Tue, 24 Mar 2026 16:06:43 +0100 Subject: [PATCH 2/2] use error() util to raise HTTPException on ClientDisconnect this won't be returned, but will suppress a noisy traceback in logs. --- ooniapi/services/ooniprobe/src/ooniprobe/routers/reports.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ooniapi/services/ooniprobe/src/ooniprobe/routers/reports.py b/ooniapi/services/ooniprobe/src/ooniprobe/routers/reports.py index 7843a4c0d..3a6f4b45e 100644 --- a/ooniapi/services/ooniprobe/src/ooniprobe/routers/reports.py +++ b/ooniapi/services/ooniprobe/src/ooniprobe/routers/reports.py @@ -146,10 +146,10 @@ async def receive_measurement( except ClientDisconnect: log.info(f"Client disconnected mid-upload") Metrics.CLIENT_DISCONNECT.inc() - return empty_measurement + error("Client disconnect") except Exception as e: log.error(f"Uncaught exception {e}") - return empty_measurement + error("Server error", status_code=500) if content_encoding == "zstd": try: