205 lines
6.7 KiB
Python

import sys
import os
from pathlib import Path
# Add project root to Python path for imports in alembic migrations
project_root = Path(__file__).parent.absolute()
sys.path.insert(0, str(project_root))
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from app.api.routers import api_router
from app.core.config import settings
from app.db import init_db
# Initialize the database on startup
print("Starting database initialization...")
try:
# Get absolute path of the database file
from pathlib import Path
db_path = Path("/app/storage/db/db.sqlite").absolute()
print(f"Database path: {db_path}")
# Check directory permissions
db_dir = Path("/app/storage/db")
print(f"Database directory exists: {db_dir.exists()}")
print(f"Database directory is writable: {os.access(db_dir, os.W_OK)}")
# Initialize the database and create test task
init_db.init_db()
# Try to create a test task
try:
init_db.create_test_task()
except Exception as e:
print(f"Error creating test task: {e}")
# Continue anyway
except Exception as e:
print(f"Error initializing database: {e}")
import traceback
print(f"Detailed error: {traceback.format_exc()}")
# Continue with app startup even if DB init fails, to allow debugging
app = FastAPI(title=settings.PROJECT_NAME)
# Set all CORS enabled origins - Allow all origins
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Add exception handlers for better error reporting
@app.exception_handler(Exception)
async def validation_exception_handler(request: Request, exc: Exception):
import traceback
error_detail = {
"detail": f"Internal Server Error: {str(exc)}",
"type": str(type(exc).__name__),
"traceback": traceback.format_exc().split("\n")
}
print(f"Error processing request: {error_detail}")
return JSONResponse(
status_code=500,
content=error_detail,
)
# Include the API router directly (no version prefix)
app.include_router(api_router)
@app.get("/", tags=["info"])
def api_info():
"""
API information endpoint with links to documentation and endpoints
"""
return {
"name": settings.PROJECT_NAME,
"version": "1.0.0",
"description": "A RESTful API for managing tasks",
"endpoints": {
"tasks": "/tasks",
"docs": "/docs",
"redoc": "/redoc",
"health": "/health",
"db_test": "/db-test"
}
}
@app.get("/health", tags=["health"])
def health_check():
"""
Health check endpoint to verify the application is running correctly
"""
return {"status": "ok"}
@app.get("/db-test", tags=["health"])
def test_db_connection():
"""
Test database connection and table creation
"""
from sqlalchemy import text, inspect
from app.db.session import engine
import traceback, os, subprocess
from app.core.config import DB_DIR
try:
# Check directory structure and permissions
storage_info = {
"app_dir_exists": os.path.exists("/app"),
"app_dir_writable": os.access("/app", os.W_OK),
"storage_dir_exists": os.path.exists("/app/storage"),
"storage_dir_writable": os.access("/app/storage", os.W_OK) if os.path.exists("/app/storage") else False,
"db_dir_exists": os.path.exists(str(DB_DIR)),
"db_dir_writable": os.access(str(DB_DIR), os.W_OK) if os.path.exists(str(DB_DIR)) else False,
}
# Get disk usage information
disk_usage = {}
try:
df_output = subprocess.check_output(["df", "-h", "/app/storage"]).decode()
disk_usage["df_output"] = df_output.strip().split('\n')
except Exception as e:
disk_usage["error"] = str(e)
# Try database connection
connection_info = {}
inspector = None
try:
with engine.connect() as conn:
connection_info["connection"] = "successful"
connection_info["test_query"] = conn.execute(text("SELECT 1")).scalar()
inspector = inspect(engine)
except Exception as e:
connection_info["connection"] = "failed"
connection_info["error"] = str(e)
# Get table information if connection successful
table_info = {}
if inspector:
tables = inspector.get_table_names()
connection_info["tables"] = tables
for table in tables:
columns = inspector.get_columns(table)
table_info[table] = [col['name'] for col in columns]
# Try to query task table if it exists
if 'task' in tables:
with engine.connect() as conn:
try:
task_count = conn.execute(text("SELECT COUNT(*) FROM task")).scalar()
connection_info["task_count"] = task_count
except Exception as e:
connection_info["task_query_error"] = str(e)
# Database file information
db_file = f"{DB_DIR}/db.sqlite"
db_file_info = {
"path": db_file,
"exists": os.path.exists(db_file),
"size_bytes": os.path.getsize(db_file) if os.path.exists(db_file) else 0,
"writable": os.access(db_file, os.W_OK) if os.path.exists(db_file) else False,
}
# SQLAlchemy configuration
from app.core.config import settings
db_config = {
"sqlalchemy_url": settings.SQLALCHEMY_DATABASE_URL,
"connect_args": {"check_same_thread": False}
}
# Test file creation
write_test = {}
try:
test_file = f"{DB_DIR}/test_db.txt"
with open(test_file, 'w') as f:
f.write("Test write access")
write_test["success"] = True
write_test["path"] = test_file
os.remove(test_file) # Clean up
except Exception as e:
write_test["success"] = False
write_test["error"] = str(e)
return {
"status": "ok",
"storage_info": storage_info,
"disk_usage": disk_usage,
"connection_info": connection_info,
"table_info": table_info,
"db_file_info": db_file_info,
"db_config": db_config,
"write_test": write_test
}
except Exception as e:
return {
"status": "error",
"global_error": str(e),
"traceback": traceback.format_exc()
}