Fix DB init - composite PK for hypertable + separate transactions
Build and push images / build-backend (push) Successful in 6s
Build and push images / build-worker (push) Successful in 6s
Build and push images / build-frontend (push) Successful in 7s

This commit is contained in:
2026-06-06 15:01:39 +01:00
parent ecc077f153
commit 264c27469b
2 changed files with 49 additions and 65 deletions
+31 -15
View File
@@ -2,33 +2,44 @@ from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager
from sqlalchemy import text
import asyncio
from app.core.database import engine, AsyncSessionLocal, Base
from app.core.config import settings
from app.api import auth, activities, routes, health, records, upload
@asynccontextmanager
async def lifespan(app: FastAPI):
# Create tables
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
# Try to enable TimescaleDB hypertable for data points
async def init_db():
"""Create tables then seed admin, with retries for slow DB startup."""
for attempt in range(10):
try:
# Step 1: create all tables (separate connection so it commits cleanly)
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
break
except Exception as e:
if attempt == 9:
raise
print(f"DB not ready yet (attempt {attempt + 1}/10): {e}")
await asyncio.sleep(3)
# Step 2: try to enable TimescaleDB hypertable (separate connection,
# failure here is non-fatal - falls back to plain Postgres)
try:
async with engine.begin() as conn:
await conn.execute(text(
"SELECT create_hypertable('activity_data_points', 'timestamp', "
"if_not_exists => TRUE, migrate_data => TRUE)"
))
except Exception:
pass # Already exists or TimescaleDB not available
except Exception as e:
print(f"TimescaleDB hypertable skipped: {e}")
# Step 3: seed admin user
from sqlalchemy import select
from app.models.user import User
from app.core.security import hash_password
# Seed admin user
async with AsyncSessionLocal() as db:
from sqlalchemy import select
from app.models.user import User
from app.core.security import hash_password
result = await db.execute(
select(User).where(User.username == settings.admin_username)
)
@@ -40,7 +51,12 @@ async def lifespan(app: FastAPI):
)
db.add(admin)
await db.commit()
print(f"Admin user '{settings.admin_username}' created")
@asynccontextmanager
async def lifespan(app: FastAPI):
await init_db()
yield
@@ -68,4 +84,4 @@ app.include_router(upload.router, prefix="/api/upload", tags=["upload"])
@app.get("/health")
async def healthcheck():
return {"status": "ok"}
return {"status": "ok"}