Files
contracts/History/upload-analysis-v41.md
T

77 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Запрос на анализ: XHR onerror («Сеть») при POST /upload с телом > 100KB
**Дата:** 2026-06-17
**Версия:** v1.41
**ТОЛЬКО АНАЛИЗ. КОД НЕ ПРАВИТЬ.**
---
## Что поменялось в понимании
После просмотра текущего кода причина выглядит уже не как `request.get_data()` сама по себе.
Ветка `/upload` сейчас делает так:
1. читает всё тело через `request.get_data(as_text=True)`
2. выдёргивает `filename`, `data`, `cid` regex-ом
3. если `cid` пустой, синхронно создаёт контракт в PostgreSQL
4. затем синхронно вызывает `redis_client.push(...)`
5. только после этого возвращает `jsonify({"contract_id": ...})`
Самое подозрительное место — именно синхронный Redis push в запросе, а не чтение тела. Если Redis/DNS/сеть внутри кластера тормозит или подвисает, клиент уже видит `xhr.onerror` как «Сеть», хотя тело запроса успело уйти целиком.
---
## Текущий код
```python
# 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)})
```
```python
# 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`.