Причина воспроизведена. Открытая вкладка держит SSE-поток /api/events, и сервер его сам не закрывает. При любой правке .pyuvicorn --reload останавливает старый процесс, а тот в graceful shutdown ждёт закрытия всех соединений — без лимита вечно. Новый процесс не стартует, сокет остаётся у reloader'а, соединения принимаются, но не обслуживаются. /api/users/me висит, RequireAuth крутит спиннер, в логе только Reloading....
Теперь uvicorn запускается с --timeout-graceful-shutdown: в run.ps1/run.sh — 2 с, в backend/entrypoint.sh — 10 с. В контейнере тот же механизм держал остановку до SIGKILL по stop_grace_period: 30s. Ручные команды запуска в README.md и раздел SSE в deploy/README.md дополнены. Код приложения не менялся.
Коммиты
b466379 uvicorn: ограничить graceful shutdown, чтобы SSE не вешал reload
Проверки
Воспроизведение «до»: uvicorn в отдельном окне, как в run.ps1, + vite; curl -N /api/events с dev-сессией; тронут events.py → /api/health не отвечает 10+ с (TCP connect за 12 мс), сервер оживает ровно при закрытии SSE.
«После», командой ровно из обновлённого run.ps1: процесс сервера сменился, /api/health → 200 через ~4,3 с после правки, /api/users/me через :5173 → 200.
run.ps1: 0 не-ASCII байт, 0 ошибок Parser::ParseFile в Windows PowerShell 5.1.
bash -n run.sh, bash -n backend/entrypoint.sh — ок.
python -m pytest — 95 passed.
Прод-путь (entrypoint.sh) вживую в Docker не запускался — только статическая проверка.
Отклонения от плана
В плане была правка CLAUDE.md (флаг в командах и пометка у SSE). Она сделана, но файл в .gitignore, поэтому осталась локальной и в PR не вошла.
Найдена смежная dev-проблема вне рамок задачи: vite-прокси не передаёт клиенту обрыв SSE со стороны бэкенда. Напрямую на :8000 поток после reload обрывается, и EventSource переподключится; через :5173 клиент висит без событий. Заведена отдельной задачей.
## Что сделано
Причина воспроизведена. Открытая вкладка держит SSE-поток `/api/events`, и сервер его сам не закрывает. При любой правке `.py` `uvicorn --reload` останавливает старый процесс, а тот в graceful shutdown ждёт закрытия всех соединений — без лимита вечно. Новый процесс не стартует, сокет остаётся у reloader'а, соединения принимаются, но не обслуживаются. `/api/users/me` висит, `RequireAuth` крутит спиннер, в логе только `Reloading...`.
Теперь uvicorn запускается с `--timeout-graceful-shutdown`: в `run.ps1`/`run.sh` — 2 с, в `backend/entrypoint.sh` — 10 с. В контейнере тот же механизм держал остановку до SIGKILL по `stop_grace_period: 30s`. Ручные команды запуска в `README.md` и раздел SSE в `deploy/README.md` дополнены. Код приложения не менялся.
## Коммиты
- `b466379` uvicorn: ограничить graceful shutdown, чтобы SSE не вешал reload
## Проверки
- Воспроизведение «до»: uvicorn в отдельном окне, как в `run.ps1`, + vite; `curl -N /api/events` с dev-сессией; тронут `events.py` → `/api/health` не отвечает 10+ с (TCP connect за 12 мс), сервер оживает ровно при закрытии SSE.
- «После», командой ровно из обновлённого `run.ps1`: процесс сервера сменился, `/api/health` → 200 через ~4,3 с после правки, `/api/users/me` через :5173 → 200.
- `run.ps1`: 0 не-ASCII байт, 0 ошибок `Parser::ParseFile` в Windows PowerShell 5.1.
- `bash -n run.sh`, `bash -n backend/entrypoint.sh` — ок.
- `python -m pytest` — 95 passed.
- Прод-путь (`entrypoint.sh`) вживую в Docker не запускался — только статическая проверка.
## Отклонения от плана
- В плане была правка `CLAUDE.md` (флаг в командах и пометка у SSE). Она сделана, но файл в `.gitignore`, поэтому осталась локальной и в PR не вошла.
- Найдена смежная dev-проблема вне рамок задачи: vite-прокси не передаёт клиенту обрыв SSE со стороны бэкенда. Напрямую на :8000 поток после reload обрывается, и EventSource переподключится; через :5173 клиент висит без событий. Заведена отдельной задачей.
Closes #47
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01XfTsytzT6TojfmprRDKiV6
После запуска dev сайт уходил в вечную загрузку без единой ошибки в логе. Открытая
вкладка держит SSE-поток /api/events, и сервер его сам не закрывает. При любой правке
.py (pull, переключение ветки, мёрж) uvicorn --reload останавливает старый процесс,
а тот в graceful shutdown ждёт закрытия всех соединений. Лимита по умолчанию нет,
поэтому ожидание длится вечно: новый процесс не стартует, слушающий сокет остаётся
у reloader'а, соединения принимаются в backlog и никем не обслуживаются. Запрос
/api/users/me висит, RequireAuth крутит спиннер, в логе только "Reloading...".
Воспроизведено тем же способом, каким запускает run.ps1 (uvicorn в отдельном окне):
при открытом SSE и тронутом .py /api/health не отвечал, хотя TCP-соединение
устанавливалось за 12 мс. Сервер ожил ровно в момент закрытия SSE.
Теперь uvicorn запускается с --timeout-graceful-shutdown: по истечении лимита он
отменяет висящие задачи запросов и доводит перезапуск до конца. В dev лимит 2 с, и
тот же сценарий отвечает 200 примерно через 4 с после правки файла. В entrypoint
лимит 10 с: в контейнере тот же механизм держал остановку до SIGKILL по
stop_grace_period (30 с), и lifespan-shutdown не выполнялся. Команды ручного запуска
в README дополнены тем же флагом.
#47
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfTsytzT6TojfmprRDKiV6
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Что сделано
Причина воспроизведена. Открытая вкладка держит SSE-поток
/api/events, и сервер его сам не закрывает. При любой правке.pyuvicorn --reloadостанавливает старый процесс, а тот в graceful shutdown ждёт закрытия всех соединений — без лимита вечно. Новый процесс не стартует, сокет остаётся у reloader'а, соединения принимаются, но не обслуживаются./api/users/meвисит,RequireAuthкрутит спиннер, в логе толькоReloading....Теперь uvicorn запускается с
--timeout-graceful-shutdown: вrun.ps1/run.sh— 2 с, вbackend/entrypoint.sh— 10 с. В контейнере тот же механизм держал остановку до SIGKILL поstop_grace_period: 30s. Ручные команды запуска вREADME.mdи раздел SSE вdeploy/README.mdдополнены. Код приложения не менялся.Коммиты
b466379uvicorn: ограничить graceful shutdown, чтобы SSE не вешал reloadПроверки
run.ps1, + vite;curl -N /api/eventsс dev-сессией; тронутevents.py→/api/healthне отвечает 10+ с (TCP connect за 12 мс), сервер оживает ровно при закрытии SSE.run.ps1: процесс сервера сменился,/api/health→ 200 через ~4,3 с после правки,/api/users/meчерез :5173 → 200.run.ps1: 0 не-ASCII байт, 0 ошибокParser::ParseFileв Windows PowerShell 5.1.bash -n run.sh,bash -n backend/entrypoint.sh— ок.python -m pytest— 95 passed.entrypoint.sh) вживую в Docker не запускался — только статическая проверка.Отклонения от плана
CLAUDE.md(флаг в командах и пометка у SSE). Она сделана, но файл в.gitignore, поэтому осталась локальной и в PR не вошла.Closes #47
🤖 Generated with Claude Code
https://claude.ai/code/session_01XfTsytzT6TojfmprRDKiV6