fix: replace psql with Python for DB checks (no apt-get needed!)
Some checks failed
Deploy Development / deploy (push) Failing after 3s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 31s

- Remove postgresql-client installation (causes 150s+ hangs due to network)
- Add db_init.py: Pure Python PostgreSQL checks using psycopg2-binary
- Simplify startup.sh: Call Python script instead of psql commands
- Build should now complete in <30s instead of hanging

This fixes the deployment timeout issue by avoiding APT network problems entirely.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lars 2026-03-18 10:01:19 +01:00
parent 67b00b941e
commit 627eb8e265
3 changed files with 141 additions and 69 deletions

View File

@ -1,15 +1,6 @@
FROM python:3.12-slim
# Force IPv4 and use German mirror with aggressive retry/timeout settings
RUN echo "Acquire::ForceIPv4 \"true\";" > /etc/apt/apt.conf.d/99force-ipv4 && \
echo "Acquire::Retries \"5\";" > /etc/apt/apt.conf.d/80-retries && \
echo "Acquire::http::Timeout \"10\";" >> /etc/apt/apt.conf.d/80-retries && \
echo "Acquire::ftp::Timeout \"10\";" >> /etc/apt/apt.conf.d/80-retries && \
echo "deb http://ftp.de.debian.org/debian bookworm main" > /etc/apt/sources.list && \
echo "deb http://ftp.de.debian.org/debian bookworm-updates main" >> /etc/apt/sources.list
# Install PostgreSQL client for psql (needed for startup.sh)
RUN apt-get update && apt-get install -y postgresql-client && rm -rf /var/lib/apt/lists/*
# No system packages needed - we use Python (psycopg2-binary) for PostgreSQL checks
WORKDIR /app

135
backend/db_init.py Normal file
View File

@ -0,0 +1,135 @@
#!/usr/bin/env python3
"""
Database initialization script for PostgreSQL.
Replaces psql commands in startup.sh with pure Python.
"""
import os
import sys
import time
import psycopg2
from psycopg2 import OperationalError
DB_HOST = os.getenv("DB_HOST", "localhost")
DB_PORT = os.getenv("DB_PORT", "5432")
DB_NAME = os.getenv("DB_NAME", "mitai_dev")
DB_USER = os.getenv("DB_USER", "mitai_dev")
DB_PASSWORD = os.getenv("DB_PASSWORD", "")
def get_connection():
"""Get PostgreSQL connection."""
return psycopg2.connect(
host=DB_HOST,
port=DB_PORT,
database=DB_NAME,
user=DB_USER,
password=DB_PASSWORD
)
def wait_for_postgres(max_retries=30):
"""Wait for PostgreSQL to be ready."""
print("\nChecking PostgreSQL connection...")
for i in range(1, max_retries + 1):
try:
conn = get_connection()
conn.close()
print("✓ PostgreSQL ready")
return True
except OperationalError:
print(f" Waiting for PostgreSQL... (attempt {i}/{max_retries})")
time.sleep(2)
print(f"✗ PostgreSQL not ready after {max_retries} attempts")
return False
def check_table_exists(table_name="profiles"):
"""Check if a table exists."""
try:
conn = get_connection()
cur = conn.cursor()
cur.execute("""
SELECT COUNT(*)
FROM information_schema.tables
WHERE table_schema='public' AND table_name=%s
""", (table_name,))
count = cur.fetchone()[0]
cur.close()
conn.close()
return count > 0
except Exception as e:
print(f"Error checking table: {e}")
return False
def load_schema(schema_file="/app/schema.sql"):
"""Load schema from SQL file."""
try:
with open(schema_file, 'r') as f:
schema_sql = f.read()
conn = get_connection()
cur = conn.cursor()
cur.execute(schema_sql)
conn.commit()
cur.close()
conn.close()
print("✓ Schema loaded from schema.sql")
return True
except Exception as e:
print(f"✗ Error loading schema: {e}")
return False
def get_profile_count():
"""Get number of profiles in database."""
try:
conn = get_connection()
cur = conn.cursor()
cur.execute("SELECT COUNT(*) FROM profiles")
count = cur.fetchone()[0]
cur.close()
conn.close()
return count
except Exception as e:
print(f"Error getting profile count: {e}")
return -1
if __name__ == "__main__":
print("═══════════════════════════════════════════════════════════")
print("MITAI JINKENDO - Database Initialization (v9b)")
print("═══════════════════════════════════════════════════════════")
# Wait for PostgreSQL
if not wait_for_postgres():
sys.exit(1)
# Check schema
print("\nChecking database schema...")
if not check_table_exists("profiles"):
print(" Schema not found, initializing...")
if not load_schema():
sys.exit(1)
else:
print("✓ Schema already exists")
# Check for migration
print("\nChecking for SQLite data migration...")
sqlite_db = "/app/data/bodytrack.db"
profile_count = get_profile_count()
if os.path.exists(sqlite_db) and profile_count == 0:
print(" SQLite database found and PostgreSQL is empty")
print(" Starting automatic migration...")
# Import and run migration
try:
import migrate_to_postgres
print("✓ Migration completed")
except Exception as e:
print(f"✗ Migration failed: {e}")
sys.exit(1)
elif os.path.exists(sqlite_db) and profile_count > 0:
print(f"⚠ SQLite DB exists but PostgreSQL already has {profile_count} profiles")
print(" Skipping migration (already migrated)")
elif not os.path.exists(sqlite_db):
print("✓ No SQLite database found (fresh install or already migrated)")
else:
print("✓ No migration needed")
print("\n✓ Database initialization complete")

View File

@ -1,67 +1,13 @@
#!/bin/bash
set -e
echo "═══════════════════════════════════════════════════════════"
echo "MITAI JINKENDO - Backend Startup (v9b)"
echo "═══════════════════════════════════════════════════════════"
# Run database initialization with Python (no psql needed!)
python /app/db_init.py
# ── PostgreSQL Connection Check ───────────────────────────────
echo ""
echo "Checking PostgreSQL connection..."
MAX_RETRIES=30
RETRY_COUNT=0
until PGPASSWORD=$DB_PASSWORD psql -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" -c '\q' 2>/dev/null; do
RETRY_COUNT=$((RETRY_COUNT + 1))
if [ $RETRY_COUNT -ge $MAX_RETRIES ]; then
echo "✗ PostgreSQL not ready after ${MAX_RETRIES} attempts"
echo " Exiting..."
if [ $? -ne 0 ]; then
echo "✗ Database initialization failed"
exit 1
fi
echo " Waiting for PostgreSQL... (attempt $RETRY_COUNT/$MAX_RETRIES)"
sleep 2
done
echo "✓ PostgreSQL ready"
# ── Schema Initialization ──────────────────────────────────────
echo ""
echo "Checking database schema..."
# Check if profiles table exists
TABLE_EXISTS=$(PGPASSWORD=$DB_PASSWORD psql -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" -tAc \
"SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='public' AND table_name='profiles'")
if [ "$TABLE_EXISTS" = "0" ]; then
echo " Schema not found, initializing..."
PGPASSWORD=$DB_PASSWORD psql -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" -f /app/schema.sql
echo "✓ Schema loaded from schema.sql"
else
echo "✓ Schema already exists"
fi
# ── Auto-Migration (SQLite → PostgreSQL) ───────────────────────
echo ""
echo "Checking for SQLite data migration..."
SQLITE_DB="/app/data/bodytrack.db"
PROFILE_COUNT=$(PGPASSWORD=$DB_PASSWORD psql -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" -tAc \
"SELECT COUNT(*) FROM profiles")
if [ -f "$SQLITE_DB" ] && [ "$PROFILE_COUNT" = "0" ]; then
echo " SQLite database found and PostgreSQL is empty"
echo " Starting automatic migration..."
python /app/migrate_to_postgres.py
echo "✓ Migration completed"
elif [ -f "$SQLITE_DB" ] && [ "$PROFILE_COUNT" != "0" ]; then
echo "⚠ SQLite DB exists but PostgreSQL already has $PROFILE_COUNT profiles"
echo " Skipping migration (already migrated)"
elif [ ! -f "$SQLITE_DB" ]; then
echo "✓ No SQLite database found (fresh install or already migrated)"
else
echo "✓ No migration needed"
fi
# ── Start Application ──────────────────────────────────────────
echo ""