Ap03 #4
|
|
@ -1,6 +1,9 @@
|
|||
"""PostgreSQL connection helpers."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
import psycopg2
|
||||
from psycopg2.extensions import connection
|
||||
|
|
@ -27,6 +30,40 @@ def get_connection() -> connection:
|
|||
)
|
||||
|
||||
|
||||
def is_retryable_db_error(exc: Exception) -> bool:
|
||||
"""Nur temporäre Verbindungsprobleme erneut versuchen (nicht Auth/Config)."""
|
||||
msg = str(exc).lower()
|
||||
if "password authentication failed" in msg:
|
||||
return False
|
||||
if "does not exist" in msg and any(token in msg for token in ("role", "database")):
|
||||
return False
|
||||
if "no pg_hba.conf entry" in msg:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def connect_with_retry(max_retries: int = 30, sleep_seconds: float = 2.0) -> connection:
|
||||
p = db_params()
|
||||
last_exc: Exception | None = None
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
conn = get_connection()
|
||||
conn.autocommit = False
|
||||
print(f"[OK] Connected to database: {p['dbname']}")
|
||||
return conn
|
||||
except psycopg2.OperationalError as exc:
|
||||
last_exc = exc
|
||||
if not is_retryable_db_error(exc):
|
||||
raise
|
||||
if attempt >= max_retries - 1:
|
||||
raise
|
||||
print(f"Waiting for database... ({attempt + 1}/{max_retries})")
|
||||
time.sleep(sleep_seconds)
|
||||
if last_exc:
|
||||
raise last_exc
|
||||
raise RuntimeError("database connection failed")
|
||||
|
||||
|
||||
def check_db() -> bool:
|
||||
conn = get_connection()
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -8,13 +8,12 @@ import re
|
|||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from typing import List, Tuple
|
||||
|
||||
import psycopg2
|
||||
import sqlparse
|
||||
|
||||
from db import db_params, get_connection
|
||||
from db import check_db, connect_with_retry, db_params, get_connection
|
||||
|
||||
_LEADING_DIGITS = re.compile(r"^(\d+)")
|
||||
|
||||
|
|
@ -135,21 +134,6 @@ def run_migration(conn, migration_name: str, filepath: str) -> bool:
|
|||
return False
|
||||
|
||||
|
||||
def connect_with_retry(max_retries: int = 30):
|
||||
p = db_params()
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
conn = get_connection()
|
||||
conn.autocommit = False
|
||||
print(f"[OK] Connected to database: {p['dbname']}")
|
||||
return conn
|
||||
except psycopg2.OperationalError:
|
||||
if attempt >= max_retries - 1:
|
||||
raise
|
||||
print(f"Waiting for database... ({attempt + 1}/{max_retries})")
|
||||
time.sleep(2)
|
||||
|
||||
|
||||
def migrations_directory() -> str:
|
||||
docker_path = "/app/migrations"
|
||||
if os.path.isdir(docker_path):
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ from typing import Callable, List, Optional, Tuple
|
|||
import psycopg2
|
||||
import sqlparse
|
||||
|
||||
from db import db_params, get_connection
|
||||
from db import connect_with_retry, db_params, get_connection
|
||||
|
||||
_SEED_PREFIX = re.compile(r"^seed_(\d+)_(.+)$")
|
||||
_DEV_MARKER = ".dev."
|
||||
|
|
@ -152,21 +152,6 @@ def run_python_seed(filepath: str) -> None:
|
|||
run_fn()
|
||||
|
||||
|
||||
def connect_with_retry(max_retries: int = 30):
|
||||
p = db_params()
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
conn = get_connection()
|
||||
conn.autocommit = False
|
||||
print(f"[OK] Connected to database: {p['dbname']}")
|
||||
return conn
|
||||
except psycopg2.OperationalError:
|
||||
if attempt >= max_retries - 1:
|
||||
raise
|
||||
print(f"Waiting for database... ({attempt + 1}/{max_retries})")
|
||||
time.sleep(2)
|
||||
|
||||
|
||||
def run_seed(conn, seed_name: str, filepath: str, kind: str) -> tuple[bool, object]:
|
||||
print(f"Running seed: {seed_name}")
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -75,6 +75,22 @@ Aktuell keine Medien-Speicherung. Bei Bedarf: NAS-Mount + `docker-compose.overri
|
|||
|
||||
---
|
||||
|
||||
## Dev-Datenbank wechseln
|
||||
|
||||
PostgreSQL im Compose-Stack initialisiert User/Passwort **nur beim ersten Start** des Volumes (`dev-kairo-db-data`).
|
||||
Wenn du `DB_NAME`, `DB_USER` oder `DB_PASSWORD` in `.env` änderst, muss das Volume neu angelegt werden:
|
||||
|
||||
```bash
|
||||
cd /home/lars/docker/kairo-dev
|
||||
docker compose -f docker-compose.dev-env.yml down -v
|
||||
docker compose -f docker-compose.dev-env.yml up -d --wait
|
||||
curl -sf http://localhost:8097/api/health
|
||||
```
|
||||
|
||||
Danach laufen Migrationen und Dev-Seeds automatisch (u. a. `lars@stommer.com`).
|
||||
|
||||
---
|
||||
|
||||
## Manuelles Deploy
|
||||
|
||||
```bash
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user