Рефакторинг инфраструктуры и конфигурации проекта
Some checks failed
CI/CD Pipeline / Code Quality Checks (push) Successful in 1m52s
CI/CD Pipeline / Run Tests (push) Failing after 2m2s
CI/CD Pipeline / Build & Push Images (push) Has been skipped

- Перенесена структура Django-конфига в src/core и src/settings

- Унифицирована Docker-сборка и docker-compose для dev/prod

- Добавлены startup-checks (DB/Redis) и обновлены env-шаблоны

- Расширена OpenAPI-документация и ответы API

- Удалены устаревшие deploy/requirements/служебные скрипты

- Обновлены CI/CD, README и тесты
This commit is contained in:
2026-02-18 13:25:01 +01:00
parent 0f4af561de
commit d5d184537f
71 changed files with 1253 additions and 2318 deletions

View File

@@ -0,0 +1,91 @@
"""
Startup dependency checks for DB and Redis.
Fail-fast checks used by long-running entrypoints (web/celery) to avoid
silent hangs on connection issues.
"""
from __future__ import annotations
import sys
from urllib.parse import urlparse
import psycopg2
import redis
from django.conf import settings
def _log(message: str) -> None:
"""Log to stderr to be visible early in startup."""
print(message, file=sys.stderr)
def _check_db(timeout_seconds: int) -> tuple[bool, str]:
db = settings.DATABASES["default"]
params = {
"dbname": db.get("NAME"),
"user": db.get("USER"),
"password": db.get("PASSWORD"),
"host": db.get("HOST"),
"port": db.get("PORT"),
"connect_timeout": timeout_seconds,
}
options = db.get("OPTIONS", {})
if options.get("sslmode"):
params["sslmode"] = options["sslmode"]
conn = None
try:
conn = psycopg2.connect(**params)
with conn.cursor() as cursor:
cursor.execute("SELECT 1")
cursor.fetchone()
return True, "OK"
except Exception as exc: # noqa: BLE001
target = f"{params['host']}:{params['port']}/{params['dbname']}"
return False, f"{target} ({exc})"
finally:
if conn is not None:
conn.close()
def _check_redis(timeout_seconds: int) -> tuple[bool, str]:
redis_url = settings.CACHES["default"]["LOCATION"]
try:
client = redis.Redis.from_url(
redis_url,
socket_connect_timeout=timeout_seconds,
socket_timeout=timeout_seconds,
)
client.ping()
return True, "OK"
except Exception as exc: # noqa: BLE001
parsed = urlparse(redis_url)
target = f"{parsed.hostname}:{parsed.port}{parsed.path or ''}"
return False, f"{target} ({exc})"
def run_startup_checks(*, component: str = "app") -> None:
"""Run startup checks and exit process on failure."""
if not getattr(settings, "STARTUP_CHECKS_ENABLED", True):
return
db_timeout = int(getattr(settings, "STARTUP_DB_TIMEOUT_SECONDS", 3))
redis_timeout = int(getattr(settings, "STARTUP_REDIS_TIMEOUT_SECONDS", 3))
db_ok, db_message = _check_db(db_timeout)
if not db_ok:
_log(
f"[startup:{component}] DB check failed "
f"(timeout={db_timeout}s): {db_message}"
)
raise SystemExit(1)
redis_ok, redis_message = _check_redis(redis_timeout)
if not redis_ok:
_log(
f"[startup:{component}] Redis check failed "
f"(timeout={redis_timeout}s): {redis_message}"
)
raise SystemExit(1)