@@ -49,7 +49,7 @@ pip install -e ".[dev]" # .[dev] — один аргумент (пак
|
|||||||
Copy-Item ..\.env.example ..\.env # ЕДИНЫЙ .env лежит в КОРНЕ репозитория
|
Copy-Item ..\.env.example ..\.env # ЕДИНЫЙ .env лежит в КОРНЕ репозитория
|
||||||
alembic upgrade head # применит миграции и сидинг
|
alembic upgrade head # применит миграции и сидинг
|
||||||
python -m app.bootstrap # создаст/синхронизирует администратора из .env
|
python -m app.bootstrap # создаст/синхронизирует администратора из .env
|
||||||
uvicorn app.main:app --reload # http://localhost:8000 (Swagger: /api/docs)
|
uvicorn app.main:app --reload --timeout-graceful-shutdown 2 # http://localhost:8000 (Swagger: /api/docs)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Windows cmd.exe** (здесь `&&` поддерживается):
|
**Windows cmd.exe** (здесь `&&` поддерживается):
|
||||||
@@ -61,7 +61,7 @@ pip install -e ".[dev]"
|
|||||||
copy ..\.env.example ..\.env
|
copy ..\.env.example ..\.env
|
||||||
alembic upgrade head
|
alembic upgrade head
|
||||||
python -m app.bootstrap
|
python -m app.bootstrap
|
||||||
uvicorn app.main:app --reload
|
uvicorn app.main:app --reload --timeout-graceful-shutdown 2
|
||||||
```
|
```
|
||||||
|
|
||||||
**Linux / macOS / Git Bash:**
|
**Linux / macOS / Git Bash:**
|
||||||
@@ -72,9 +72,13 @@ pip install -e ".[dev]"
|
|||||||
cp ../.env.example ../.env
|
cp ../.env.example ../.env
|
||||||
alembic upgrade head
|
alembic upgrade head
|
||||||
python -m app.bootstrap
|
python -m app.bootstrap
|
||||||
uvicorn app.main:app --reload
|
uvicorn app.main:app --reload --timeout-graceful-shutdown 2
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **`--timeout-graceful-shutdown` обязателен.** Открытая вкладка держит SSE-поток
|
||||||
|
> `/api/events`, и без лимита `--reload` ждёт его закрытия вечно — сайт висит на загрузке,
|
||||||
|
> а в логе только `Reloading...`.
|
||||||
|
|
||||||
> **Единый `.env` — в корне репозитория** (`ForbidenStarsApp/.env`), рядом с `.env.example`.
|
> **Единый `.env` — в корне репозитория** (`ForbidenStarsApp/.env`), рядом с `.env.example`.
|
||||||
> Его читают и бэкенд (через абсолютный путь, независимо от рабочей папки), и `docker compose`.
|
> Его читают и бэкенд (через абсолютный путь, независимо от рабочей папки), и `docker compose`.
|
||||||
> Файл — локальный, на каждой машине свой (dev/prod различаются строкой `APP_ENV`).
|
> Файл — локальный, на каждой машине свой (dev/prod различаются строкой `APP_ENV`).
|
||||||
|
|||||||
@@ -10,5 +10,7 @@ python -m app.bootstrap
|
|||||||
echo "[entrypoint] Запуск сервера…"
|
echo "[entrypoint] Запуск сервера…"
|
||||||
# --proxy-headers + доверие к X-Forwarded-* от реверс-прокси (Caddy на VPS):
|
# --proxy-headers + доверие к X-Forwarded-* от реверс-прокси (Caddy на VPS):
|
||||||
# чтобы приложение знало, что снаружи запрос пришёл по HTTPS.
|
# чтобы приложение знало, что снаружи запрос пришёл по HTTPS.
|
||||||
|
# --timeout-graceful-shutdown: SSE-потоки /api/events сами не закрываются, и без лимита
|
||||||
|
# остановка ждала бы их до SIGKILL по stop_grace_period (30 с) — без lifespan-shutdown.
|
||||||
exec uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 1 \
|
exec uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 1 \
|
||||||
--proxy-headers --forwarded-allow-ips="*"
|
--proxy-headers --forwarded-allow-ips="*" --timeout-graceful-shutdown 10
|
||||||
|
|||||||
@@ -57,3 +57,8 @@ HTTPS твоими сертификатами и проксирует трафи
|
|||||||
Шина событий — **in-memory**, рассчитана на один процесс (uvicorn `--workers 1`, как в
|
Шина событий — **in-memory**, рассчитана на один процесс (uvicorn `--workers 1`, как в
|
||||||
контейнере). Если когда-нибудь поднимешь несколько воркеров/реплик — шину нужно вынести во
|
контейнере). Если когда-нибудь поднимешь несколько воркеров/реплик — шину нужно вынести во
|
||||||
внешний брокер (Redis pub/sub), иначе события увидит только тот воркер, что принял мутацию.
|
внешний брокер (Redis pub/sub), иначе события увидит только тот воркер, что принял мутацию.
|
||||||
|
|
||||||
|
SSE-поток сам не закрывается, поэтому uvicorn запускается с `--timeout-graceful-shutdown`
|
||||||
|
(`entrypoint.sh`, `run.*`). Без него остановка ждёт закрытия всех соединений: в dev
|
||||||
|
`--reload` при открытой вкладке висит вечно, в контейнере остановку обрывает только SIGKILL
|
||||||
|
по `stop_grace_period`.
|
||||||
|
|||||||
@@ -112,9 +112,12 @@ switch ($appEnv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Write-Host "Starting backend (uvicorn --reload) and frontend (vite) in separate windows..." -ForegroundColor Green
|
Write-Host "Starting backend (uvicorn --reload) and frontend (vite) in separate windows..." -ForegroundColor Green
|
||||||
|
# --timeout-graceful-shutdown: an open tab keeps the SSE stream /api/events forever,
|
||||||
|
# and on reload the old process waits for ALL connections to close - with no limit
|
||||||
|
# the reload never finishes and the site hangs on loading with nothing in the log.
|
||||||
Start-Process powershell -ArgumentList @(
|
Start-Process powershell -ArgumentList @(
|
||||||
"-NoExit", "-Command",
|
"-NoExit", "-Command",
|
||||||
"Set-Location '$backend'; & '$py' -m uvicorn app.main:app --reload"
|
"Set-Location '$backend'; & '$py' -m uvicorn app.main:app --reload --timeout-graceful-shutdown 2"
|
||||||
)
|
)
|
||||||
Start-Process powershell -ArgumentList @(
|
Start-Process powershell -ArgumentList @(
|
||||||
"-NoExit", "-Command",
|
"-NoExit", "-Command",
|
||||||
|
|||||||
@@ -68,7 +68,10 @@ case "$app_env" in
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Запуск бэка (uvicorn --reload) и фронта (vite)… Ctrl+C — остановить всё."
|
echo "Запуск бэка (uvicorn --reload) и фронта (vite)… Ctrl+C — остановить всё."
|
||||||
( cd "$root/backend" && exec "$py" -m uvicorn app.main:app --reload ) &
|
# --timeout-graceful-shutdown: открытая вкладка держит SSE-поток /api/events вечно, а при
|
||||||
|
# reload старый процесс ждёт закрытия ВСЕХ соединений — без лимита перезапуск не
|
||||||
|
# завершается, и сайт висит на загрузке без единой ошибки в логе.
|
||||||
|
( cd "$root/backend" && exec "$py" -m uvicorn app.main:app --reload --timeout-graceful-shutdown 2 ) &
|
||||||
back=$!
|
back=$!
|
||||||
trap 'kill "$back" 2>/dev/null || true' EXIT INT TERM
|
trap 'kill "$back" 2>/dev/null || true' EXIT INT TERM
|
||||||
echo " Бэк: http://127.0.0.1:8000 (Swagger: /api/docs)"
|
echo " Бэк: http://127.0.0.1:8000 (Swagger: /api/docs)"
|
||||||
|
|||||||
Reference in New Issue
Block a user