v5.2.0: waitress вместо app.run() — production WSGI, 8 потоков, исправляет ERR_TIMED_OUT
Deploy drhider / validate (push) Waiting to run
Deploy drhider / validate (push) Waiting to run
This commit is contained in:
@@ -0,0 +1,32 @@
|
|||||||
|
# Запрос к Соннету — ERR_TIMED_OUT при открытии нового окна (2026-07-12)
|
||||||
|
|
||||||
|
## Симптом
|
||||||
|
|
||||||
|
DrHider на Managed Flask (Штурвал/pythonk8s). При открытии страницы в НОВОМ окне браузера — ERR_TIMED_OUT (20+ секунд). Старые вкладки работают нормально.
|
||||||
|
|
||||||
|
## Факты
|
||||||
|
|
||||||
|
- Изнутри кластера (kubectl exec → curl): HTTP 200 за 2.1 секунды
|
||||||
|
- Снаружи (браузер, curl с локальной машины): таймаут 10+ секунд
|
||||||
|
- v1 работало с gunicorn (CMD: `gunicorn --bind :5000 --worker-class gevent`)
|
||||||
|
- Сейчас: `app.run(host="0.0.0.0", port=5000)` — Flask dev server (Werkzeug)
|
||||||
|
- Страница: 12 KB HTML, 2 статических файла (logo.svg, favicon.svg — оба 2.8 KB)
|
||||||
|
- Ноль внешних зависимостей (никаких CDN, шрифтов, JS-библиотек)
|
||||||
|
- HTTP-заголовки: Cache-Control: no-cache, no-store, must-revalidate
|
||||||
|
- Штурвал запускает: cd site && python app.py
|
||||||
|
|
||||||
|
## Вопросы
|
||||||
|
|
||||||
|
1. Может ли Flask dev server (Werkzeug) быть причиной ERR_TIMED_OUT на новых соединениях, в то время как gunicorn работал нормально?
|
||||||
|
2. Если да — какой механизм? (keep-alive, thread pool, socket backlog?)
|
||||||
|
3. Если нет — что ещё может вызывать таймаут именно на НОВЫХ окнах при работающих старых?
|
||||||
|
4. Нужно ли вернуть gunicorn или есть другой способ заставить app.run() работать стабильно?
|
||||||
|
5. Может ли `Cache-Control: no-store` заставлять браузер делать лишние запросы при открытии нового окна?
|
||||||
|
|
||||||
|
## Контекст платформы
|
||||||
|
|
||||||
|
Штурвал — Managed Flask на Kubernetes:
|
||||||
|
- Запускает: `cd /var/www && pip install -r requirements.txt && cd site && python app.py`
|
||||||
|
- Readiness probe: `tcp-socket :5000`
|
||||||
|
- Нет Dockerfile, нет nginx перед приложением
|
||||||
|
- Ingress: внешний LoadBalancer → ClusterIP сервис → под
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Ответ Соннета — ERR_TIMED_OUT (2026-07-12)
|
||||||
|
|
||||||
|
## Причина
|
||||||
|
|
||||||
|
Werkzeug dev server: **один поток на TCP-соединение**. Браузер держит 6 keep-alive соединений на вкладку. 6 потоков заняты idle-соединениями → backlog (5) переполнен → новое окно получает SYN-дроп → таймаут.
|
||||||
|
|
||||||
|
gunicorn+gevent: async I/O, idle-соединения не занимают ресурсы.
|
||||||
|
|
||||||
|
## Решение
|
||||||
|
|
||||||
|
Три варианта:
|
||||||
|
|
||||||
|
| Вариант | Что | Изменения |
|
||||||
|
|---|---|---|
|
||||||
|
| A (waitress) | Pure Python WSGI | `requirements.txt` + 2 строки в `app.py` |
|
||||||
|
| B (gevent) | Async, как gunicorn | `requirements.txt` + 2 строки в `app.py` |
|
||||||
|
| C (gunicorn) | Точно как v1 | `requirements.txt` + смена CMD в Штурвале |
|
||||||
|
|
||||||
|
Соннет рекомендует: **A** если Штурвал не меняет CMD, **C** если меняет.
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
flask
|
flask
|
||||||
|
waitress
|
||||||
python-docx
|
python-docx
|
||||||
pdfplumber
|
pdfplumber
|
||||||
httpx
|
httpx
|
||||||
|
|||||||
+3
-2
@@ -20,7 +20,7 @@ if _sys_path_root not in sys.path:
|
|||||||
sys.path.insert(0, _sys_path_root)
|
sys.path.insert(0, _sys_path_root)
|
||||||
|
|
||||||
# Версия приложения (меняется при изменениях)
|
# Версия приложения (меняется при изменениях)
|
||||||
VERSION = "5.1.0"
|
VERSION = "5.2.0"
|
||||||
|
|
||||||
|
|
||||||
def create_app():
|
def create_app():
|
||||||
@@ -61,7 +61,8 @@ app = create_app()
|
|||||||
|
|
||||||
# Штурвал запускает: cd site && python app.py
|
# Штурвал запускает: cd site && python app.py
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(host="0.0.0.0", port=5000)
|
from waitress import serve
|
||||||
|
serve(app, host="0.0.0.0", port=5000, threads=8)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user