Dama12 commited on
Commit
f91f9b0
·
1 Parent(s): ace0a81

fix: database connection string normalization and improved error logging for cloud deployment

Browse files
Files changed (3) hide show
  1. app/api/routes/users.py +19 -4
  2. app/core/settings.py +9 -0
  3. app/main.py +5 -2
app/api/routes/users.py CHANGED
@@ -116,11 +116,21 @@ async def register_and_login(user: UserCreate, db: Session = Depends(get_db)):
116
  )
117
  return {"access_token": token, "token_type": "bearer", "user": {"id": str(new_user.id), "name": new_user.name, "email": new_user.email}}
118
  except Exception as e:
119
- if isinstance(e, ValueError):
120
- raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=str(e))
 
 
 
 
 
 
 
 
 
121
 
122
  # Fallback to Demo Mode if DB is down (Dev only)
123
- if ("OperationalError" in str(type(e)) or "connection" in str(e).lower()) and settings.ENVIRONMENT == "development":
 
124
  mock_id = str(uuid.uuid4())
125
  token = create_access_token(
126
  data={"sub": mock_id, "demo": True},
@@ -132,7 +142,12 @@ async def register_and_login(user: UserCreate, db: Session = Depends(get_db)):
132
  "user": {"id": mock_id, "name": user.name, "email": user.email},
133
  "mode": "demo"
134
  }
135
- raise e
 
 
 
 
 
136
 
137
 
138
  @router.get("/me", response_model=UserResponse)
 
116
  )
117
  return {"access_token": token, "token_type": "bearer", "user": {"id": str(new_user.id), "name": new_user.name, "email": new_user.email}}
118
  except Exception as e:
119
+ logger.error(f"Registration error: {str(e)}")
120
+
121
+ # Capture conflict errors (user already exists)
122
+ if isinstance(e, ValueError) or "unique constraint" in str(e).lower() or "already exists" in str(e).lower():
123
+ raise HTTPException(
124
+ status_code=status.HTTP_409_CONFLICT,
125
+ detail="User with this email already exists."
126
+ )
127
+
128
+ # Determine if it's a database-related error
129
+ is_db_error = any(term in str(e).lower() for term in ["operationalerror", "connection", "refused", "psycopg2", "target machine actively refused"])
130
 
131
  # Fallback to Demo Mode if DB is down (Dev only)
132
+ if is_db_error and settings.ENVIRONMENT == "development":
133
+ logger.warning("Database unavailable. Falling back to Demo Mode for registration.")
134
  mock_id = str(uuid.uuid4())
135
  token = create_access_token(
136
  data={"sub": mock_id, "demo": True},
 
142
  "user": {"id": mock_id, "name": user.name, "email": user.email},
143
  "mode": "demo"
144
  }
145
+
146
+ logger.exception("Unexpected error during registration")
147
+ raise HTTPException(
148
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
149
+ detail=f"Registration failed: {str(e)}"
150
+ )
151
 
152
 
153
  @router.get("/me", response_model=UserResponse)
app/core/settings.py CHANGED
@@ -1,6 +1,7 @@
1
  """
2
  Core Settings & Configuration
3
  """
 
4
  from pydantic_settings import BaseSettings, SettingsConfigDict
5
  from typing import List, Optional
6
 
@@ -19,6 +20,14 @@ class Settings(BaseSettings):
19
 
20
  # Database — REQUIRED: must be set in .env
21
  DATABASE_URL: str = "postgresql://user:onion123@localhost:5432/scoinvestigator"
 
 
 
 
 
 
 
 
22
  DB_ECHO: bool = False
23
 
24
  # Security — REQUIRED: must be set in .env
 
1
  """
2
  Core Settings & Configuration
3
  """
4
+ from pydantic import field_validator
5
  from pydantic_settings import BaseSettings, SettingsConfigDict
6
  from typing import List, Optional
7
 
 
20
 
21
  # Database — REQUIRED: must be set in .env
22
  DATABASE_URL: str = "postgresql://user:onion123@localhost:5432/scoinvestigator"
23
+
24
+ @field_validator("DATABASE_URL", mode="before")
25
+ @classmethod
26
+ def validate_database_url(cls, v: str) -> str:
27
+ if v and v.startswith("postgres://"):
28
+ return v.replace("postgres://", "postgresql://", 1)
29
+ return v
30
+
31
  DB_ECHO: bool = False
32
 
33
  # Security — REQUIRED: must be set in .env
app/main.py CHANGED
@@ -36,8 +36,11 @@ async def lifespan(app: FastAPI):
36
  Base.metadata.create_all(bind=engine)
37
  logger.info("Database tables created / verified successfully")
38
  except Exception as e:
39
- logger.error(f"Could not connect to database: {e}")
40
- logger.error("Make sure PostgreSQL is running on localhost:5432")
 
 
 
41
  logger.info("Application startup")
42
  yield
43
  logger.info("Application shutdown")
 
36
  Base.metadata.create_all(bind=engine)
37
  logger.info("Database tables created / verified successfully")
38
  except Exception as e:
39
+ logger.error(f"CRITICAL: Could not connect to database or create tables: {str(e)}")
40
+ logger.error(f"Error type: {type(e).__name__}")
41
+ logger.error(f"Check your DATABASE_URL and ensure the database is reachable.")
42
+ if "ssl" in str(e).lower():
43
+ logger.error("SSL Error detected. Try adding ?sslmode=require to your DATABASE_URL.")
44
  logger.info("Application startup")
45
  yield
46
  logger.info("Application shutdown")