fix: replace psql with Python for DB checks (no apt-get needed!)
- 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:
parent
67b00b941e
commit
627eb8e265
|
|
@ -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
135
backend/db_init.py
Normal 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")
|
||||
|
|
@ -1,66 +1,12 @@
|
|||
#!/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 ──────────────────────────────────────────
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user