#!/usr/bin/env bash # diagnose-han-chat.sh — запускать из /opt/han-chat/backend set -euo pipefail cd /opt/han-chat/backend echo "=== 1. Статус сервисов ===" docker compose --env-file .env ps api-backend keycloak redis message-safety echo echo "=== 2. Healthcheck api-backend (что именно падает) ===" docker compose --env-file .env exec -T api-backend \ python -c " import json, urllib.request try: r = urllib.request.urlopen('http://127.0.0.1:8000/health/ready', timeout=5) print('HTTP', r.status) print(json.dumps(json.loads(r.read()), indent=2, ensure_ascii=False)) except urllib.error.HTTPError as e: print('HTTP', e.code) print(json.dumps(json.loads(e.read()), indent=2, ensure_ascii=False)) " echo echo "=== 3. Keycloak health (management port 9000) ===" docker compose --env-file .env exec -T keycloak bash -c \ "exec 3<>/dev/tcp/127.0.0.1/9000 && printf 'GET /auth/health/ready HTTP/1.0\r\n\r\n' >&3 && cat <&3" \ 2>/dev/null | head -20 || echo "Keycloak health FAILED" echo echo "=== 4. api-backend -> Keycloak (JWKS) ===" docker compose --env-file .env exec -T api-backend \ python -c " import os, urllib.request, json base = os.environ.get('KEYCLOAK_INTERNAL_URL','http://keycloak:8080/auth').rstrip('/') realm = os.environ.get('KEYCLOAK_REALM','han-chat') url = f'{base}/realms/{realm}/.well-known/openid-configuration' try: d = json.loads(urllib.request.urlopen(url, timeout=5).read()) print('discovery OK, jwks_uri:', d.get('jwks_uri')) except Exception as e: print('discovery FAILED:', e) " echo echo "=== 5. Счётчик рестартов ===" docker inspect --format '{{.Name}} restarts={{.RestartCount}} started={{.State.StartedAt}} health={{if .State.Health}}{{.State.Health.Status}}{{else}}n/a{{end}}' \ han-chat-api-backend-1 han-chat-keycloak-1 echo echo "=== 6. Последние ошибки в логах ===" echo "--- api-backend ---" docker logs --tail 80 han-chat-api-backend-1 2>&1 | grep -iE 'error|failed|exception|jwks|settings|postgres' || echo "(нет совпадений)" echo "--- keycloak ---" docker logs --tail 80 han-chat-keycloak-1 2>&1 | grep -iE 'error|failed|exception|FATAL|OutOfMemory' || echo "(нет совпадений)" echo echo "=== 7. Память (Keycloak часто падает от OOM) ===" free -h docker stats --no-stream --format 'table {{.Name}}\t{{.MemUsage}}\t{{.CPUPerc}}' \ han-chat-keycloak-1 han-chat-api-backend-1 2>/dev/null || true echo echo "=== 8. Exited контейнеры (в метриках было exited=2) ===" docker ps -a --filter status=exited --format 'table {{.Names}}\t{{.Status}}\t{{.Image}}'