amaye15 commited on
Commit
1cff830
·
1 Parent(s): 0193258

Debug - Change DB

Browse files
Files changed (2) hide show
  1. Dockerfile +3 -2
  2. app/database.py +56 -20
Dockerfile CHANGED
@@ -18,8 +18,9 @@ COPY ./app /code/app
18
  # Make port 7860 available to the world outside this container (Gradio default)
19
  EXPOSE 7860
20
 
21
- # Ensure the database directory exists if using SQLite relative paths implicitly
22
- # RUN mkdir -p /code/app
 
23
 
24
  # Command to run the application using uvicorn
25
  # It will run the FastAPI app instance created in app/main.py
 
18
  # Make port 7860 available to the world outside this container (Gradio default)
19
  EXPOSE 7860
20
 
21
+ # Explicitly create the /data directory where the SQLite DB will live
22
+ # Running as root by default, so permissions should be okay initially
23
+ RUN mkdir -p /data
24
 
25
  # Command to run the application using uvicorn
26
  # It will run the FastAPI app instance created in app/main.py
app/database.py CHANGED
@@ -1,19 +1,24 @@
 
1
  import os
2
  from databases import Database
3
  from dotenv import load_dotenv
4
  from sqlalchemy import create_engine, MetaData, Table, Column, Integer, String, text
 
5
 
6
  load_dotenv()
 
7
 
8
- DATABASE_URL = os.getenv("DATABASE_URL", "sqlite+aiosqlite:///./app/app.db")
 
 
 
9
 
10
- # Use 'check_same_thread': False only for SQLite, it's generally not needed for server DBs
11
  connect_args = {"check_same_thread": False} if DATABASE_URL.startswith("sqlite") else {}
12
 
13
  database = Database(DATABASE_URL, connect_args=connect_args)
14
  metadata = MetaData()
15
 
16
- # Define Users table using SQLAlchemy Core (needed for initial setup)
17
  users = Table(
18
  "users",
19
  metadata,
@@ -22,26 +27,57 @@ users = Table(
22
  Column("hashed_password", String, nullable=False),
23
  )
24
 
25
- # Create the database and table if they don't exist
26
- # This synchronous part runs once at startup usually
27
- engine = create_engine(DATABASE_URL.replace("+aiosqlite", ""), connect_args=connect_args)
 
 
28
 
29
- # Check if table exists before creating
30
- # Using a try-except block for robustness across DB engines if needed later
 
 
 
 
 
 
 
 
 
 
 
 
31
  try:
 
32
  with engine.connect() as connection:
33
- connection.execute(text("SELECT 1 FROM users LIMIT 1"))
34
- print("Users table already exists.")
35
- except Exception:
36
- print("Users table not found, creating...")
37
- metadata.create_all(engine)
38
- print("Users table created.")
39
-
40
- # Async connect/disconnect functions for FastAPI lifespan events
 
 
 
 
 
 
 
 
 
41
  async def connect_db():
42
- await database.connect()
43
- print("Database connection established.")
 
 
 
 
44
 
45
  async def disconnect_db():
46
- await database.disconnect()
47
- print("Database connection closed.")
 
 
 
 
1
+ # app/database.py
2
  import os
3
  from databases import Database
4
  from dotenv import load_dotenv
5
  from sqlalchemy import create_engine, MetaData, Table, Column, Integer, String, text
6
+ import logging # Add logging
7
 
8
  load_dotenv()
9
+ logger = logging.getLogger(__name__) # Add logger
10
 
11
+ # --- CHANGE THIS LINE ---
12
+ # Use an absolute path in a known writable directory like /data
13
+ DATABASE_URL = os.getenv("DATABASE_URL", "sqlite+aiosqlite:////data/app.db")
14
+ # Note the four slashes for an absolute path: sqlite+aiosqlite:////path/to/db
15
 
16
+ # Use 'check_same_thread': False only for SQLite
17
  connect_args = {"check_same_thread": False} if DATABASE_URL.startswith("sqlite") else {}
18
 
19
  database = Database(DATABASE_URL, connect_args=connect_args)
20
  metadata = MetaData()
21
 
 
22
  users = Table(
23
  "users",
24
  metadata,
 
27
  Column("hashed_password", String, nullable=False),
28
  )
29
 
30
+ # Create the database and table if they don't exist (synchronous part)
31
+ # Derive the synchronous URL correctly from the potentially absolute DATABASE_URL
32
+ sync_db_url = DATABASE_URL.replace("+aiosqlite", "")
33
+ logger.info(f"Using synchronous DB URL for initial check/create: {sync_db_url}")
34
+ engine = create_engine(sync_db_url, connect_args=connect_args)
35
 
36
+ # Extract the directory path to ensure it exists
37
+ db_file_path = sync_db_url.split("sqlite:///")[-1] # Gets /data/app.db
38
+ if db_file_path: # Ensure we got a path
39
+ db_dir = os.path.dirname(db_file_path)
40
+ logger.info(f"Ensuring database directory exists: {db_dir}")
41
+ try:
42
+ if db_dir and not os.path.exists(db_dir):
43
+ os.makedirs(db_dir, exist_ok=True)
44
+ logger.info(f"Created database directory: {db_dir}")
45
+ except OSError as e:
46
+ logger.error(f"Error creating database directory {db_dir}: {e}")
47
+ # Proceed anyway, maybe permissions allow file creation but not dir listing/creation
48
+
49
+ # Now try connecting and creating the table
50
  try:
51
+ logger.info("Attempting to connect with sync engine to check/create table...")
52
  with engine.connect() as connection:
53
+ # Try a simple query to see if the table exists
54
+ try:
55
+ connection.execute(text("SELECT 1 FROM users LIMIT 1"))
56
+ logger.info("Users table already exists.")
57
+ except Exception: # Catch specific DB exceptions if possible, e.g., sqlalchemy.exc.ProgrammingError
58
+ logger.info("Users table not found or error checking, attempting creation...")
59
+ metadata.create_all(engine) # Create tables if check fails
60
+ logger.info("Users table created (or creation attempted).")
61
+
62
+ except Exception as e:
63
+ logger.exception(f"CRITICAL: Failed to connect/create database tables using sync engine: {e}")
64
+ # Application might fail to start properly here. Depending on requirements,
65
+ # you might raise the exception or just log it and hope the async part works.
66
+ # For now, just log it, as the async connection might still succeed later.
67
+
68
+
69
+ # Async connect/disconnect functions
70
  async def connect_db():
71
+ try:
72
+ await database.connect()
73
+ logger.info(f"Database connection established (async): {DATABASE_URL}")
74
+ except Exception as e:
75
+ logger.exception(f"Failed to establish async database connection: {e}")
76
+ raise # Reraise critical error during startup lifespan
77
 
78
  async def disconnect_db():
79
+ try:
80
+ await database.disconnect()
81
+ logger.info("Database connection closed (async).")
82
+ except Exception as e:
83
+ logger.exception(f"Error closing async database connection: {e}")