3.6 KiB
Запрос на анализ: XHR onerror («Сеть») при POST /upload с телом > 100KB
Дата: 2026-06-17 Версия: v1.41 ТОЛЬКО АНАЛИЗ. КОД НЕ ПРАВИТЬ.
Что поменялось в понимании
После просмотра текущего кода причина выглядит уже не как request.get_data() сама по себе.
Ветка /upload сейчас делает так:
- читает всё тело через
request.get_data(as_text=True) - выдёргивает
filename,data,cidregex-ом - если
cidпустой, синхронно создаёт контракт в PostgreSQL - затем синхронно вызывает
redis_client.push(...) - только после этого возвращает
jsonify({"contract_id": ...})
Самое подозрительное место — именно синхронный Redis push в запросе, а не чтение тела. Если Redis/DNS/сеть внутри кластера тормозит или подвисает, клиент уже видит xhr.onerror как «Сеть», хотя тело запроса успело уйти целиком.
Текущий код
# app.py
raw = request.get_data(as_text=True)
...
redis_client.push({"filename": filename, "b64": b64, "mime": mime, "cid": str(cid)})
return jsonify({"contract_id": str(cid)})
# redis_client.py
_r = redis.Redis(
host=os.getenv("REDIS_HOST", "redisk8s....svc.cluster.local"),
port=int(os.getenv("REDIS_PORT", "6379")),
password=os.getenv("REDIS_PASS", "..."),
decode_responses=True,
socket_connect_timeout=5,
)
def push(task: dict):
_get().rpush(UPLOAD_QUEUE, json.dumps(task, ensure_ascii=False))
Локальная гипотеза
request.get_data() не ломает соединение на 200KB. Запрос уже дошёл.
Соединение рвётся или уходит в таймаут на этапе синхронного rpush() в Redis, либо на первом обращении к Redis-клиенту, если DNS/соединение внутри кластера нестабильны. Это объясняет, почему:
- маленькие тела проходят чаще;
- сервер иногда успевает обработать и записать лог;
xhr.uploadпоказывает 100%, а затем приходитonerror;curlдаёт плавающийHTTP:000/ReadTimeout.
Что надо проверить первым
Самый дешёвый дискриминирующий тест — замерить время именно вокруг redis_client.push() и временно обойти его для /upload.
Если ответ сразу стабилизируется, проблема подтверждается.
Если нет, следующая точка проверки — внешний таймаут/обрыв на ingress или gunicorn, но по текущему коду Redis выглядит ближе всего к критическому узлу.
Вывод
В v1.40 сместили фокус с парсинга тела на более поздний синхронный шаг. Сам get_data() теперь выглядит не как корень проблемы, а как просто первая стадия запроса. Корневой кандидат — блокирующий redis_client.push() в обработчике /upload.