Files
ppr-ng/backend/entrypoint.sh
2025-12-04 18:29:09 +00:00

185 lines
5.5 KiB
Bash

#!/bin/bash
# Docker entrypoint script for PPR API
# Handles database migrations and data seeding automatically
# Note: We don't use 'set -e' here because we need to handle specific exit codes from Python scripts
echo "========================================="
echo "PPR API Container Starting"
echo "========================================="
# Wait for database to be ready
echo "Waiting for database to be ready..."
python3 << EOF
import sys
import time
from sqlalchemy import create_engine, text
from app.core.config import settings
max_retries = 30
retry_interval = 2
for i in range(max_retries):
try:
engine = create_engine(settings.database_url)
with engine.connect() as conn:
conn.execute(text("SELECT 1"))
print("✓ Database is ready")
sys.exit(0)
except Exception as e:
if i < max_retries - 1:
print(f"Database not ready yet (attempt {i+1}/{max_retries}), waiting...")
time.sleep(retry_interval)
else:
print(f"✗ Database connection failed after {max_retries} attempts: {e}")
sys.exit(1)
EOF
if [ $? -ne 0 ]; then
echo "Failed to connect to database. Exiting."
exit 1
fi
# Check if this is a fresh database or needs migration
echo ""
echo "Checking database state..."
python3 << EOF
import sys
from sqlalchemy import create_engine, text, inspect
from app.core.config import settings
try:
engine = create_engine(settings.database_url)
inspector = inspect(engine)
# Check if any tables exist
tables = inspector.get_table_names()
if not tables:
print("✓ Fresh database detected - will initialize")
sys.exit(2) # Signal fresh database
elif 'alembic_version' not in tables:
print("✓ Existing database without migration tracking - will stamp")
sys.exit(3) # Signal existing database needs stamping
else:
print("✓ Database has migration tracking - will check for updates")
sys.exit(0) # Normal migration check
except Exception as e:
print(f"✗ Error checking database: {e}")
sys.exit(1)
EOF
DB_STATE=$?
if [ $DB_STATE -eq 2 ]; then
# Fresh database - run initial migration
echo ""
echo "Initializing fresh database..."
cd /app
alembic upgrade head
echo "✓ Database schema created"
# Seed reference data
echo ""
echo "Loading reference data..."
python3 /app/seed_data.py
echo "✓ Reference data loaded"
elif [ $DB_STATE -eq 3 ]; then
# Existing database without Alembic - stamp it
echo ""
echo "Stamping existing database with migration version..."
cd /app
alembic stamp head
echo "✓ Database stamped"
# Check if reference data exists
python3 << EOF
from sqlalchemy import create_engine, text
from app.core.config import settings
engine = create_engine(settings.database_url)
with engine.connect() as conn:
airport_count = conn.execute(text("SELECT COUNT(*) FROM airports")).fetchone()[0]
aircraft_count = conn.execute(text("SELECT COUNT(*) FROM aircraft")).fetchone()[0]
if airport_count == 0 or aircraft_count == 0:
print("Reference data missing - will load")
exit(10)
else:
print(f"Reference data exists (airports: {airport_count}, aircraft: {aircraft_count})")
exit(0)
EOF
if [ $? -eq 10 ]; then
echo "Loading reference data..."
python3 /app/seed_data.py
echo "✓ Reference data loaded"
fi
elif [ $DB_STATE -eq 0 ]; then
# Database with Alembic tracking - check for pending migrations
echo ""
echo "Checking for pending migrations..."
cd /app
# Get current and head revisions
CURRENT=$(alembic current 2>/dev/null | grep -o '[a-f0-9]\{12\}' | head -1 || echo "none")
HEAD=$(alembic heads 2>/dev/null | grep -o '[a-f0-9]\{12\}' | head -1 || echo "none")
if [ "$CURRENT" != "$HEAD" ] && [ "$HEAD" != "none" ]; then
echo "✓ Pending migrations detected"
echo " Current: $CURRENT"
echo " Target: $HEAD"
echo "Applying migrations..."
alembic upgrade head
echo "✓ Migrations applied"
else
echo "✓ Database is up to date"
fi
# Check if reference data needs to be loaded
python3 << EOF
from sqlalchemy import create_engine, text
from app.core.config import settings
engine = create_engine(settings.database_url)
with engine.connect() as conn:
airport_count = conn.execute(text("SELECT COUNT(*) FROM airports")).fetchone()[0]
aircraft_count = conn.execute(text("SELECT COUNT(*) FROM aircraft")).fetchone()[0]
if airport_count == 0 or aircraft_count == 0:
print("Reference data missing - will load")
exit(10)
else:
print(f"Reference data exists (airports: {airport_count}, aircraft: {aircraft_count})")
exit(0)
EOF
if [ $? -eq 10 ]; then
echo "Loading reference data..."
python3 /app/seed_data.py
echo "✓ Reference data loaded"
fi
else
echo "✗ Database check failed"
exit 1
fi
echo ""
echo "========================================="
echo "Starting Application Server"
echo "========================================="
echo ""
# Start the application with appropriate settings
if [ "${ENVIRONMENT}" = "production" ]; then
echo "Starting in PRODUCTION mode with multiple workers..."
exec uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers ${WORKERS:-4}
else
echo "Starting in DEVELOPMENT mode with auto-reload..."
exec uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
fi