This is a sudden error, whose root cause I haven't been able to figure out. I successfully built 2 Docker images that are connected over the same network:
I am not able to use the SQLAlchemy dependency injection to connect to my DB. However, I was able to seed my DB successfully many times over. Only made one additional field addition to my SQLAlchemy model and then this failure occurred.
backend-web-1 | ERROR:services.utils:Health check failed in 0.00 seconds: 'NoneType' object has no attribute 'execute'
backend-web-1 | ERROR:services.utils:Traceback (most recent call last):
backend-web-1 | File "/app/main.py", line 27, in read_root
backend-web-1 | db.execute('SELECT 1')
backend-web-1 | ^^^^^^^^^^
backend-web-1 | AttributeError: 'NoneType' object has no attribute 'execute'
Code failure above happens here
from fastapi import FastAPI, Request, Depends, HTTPException
from sqlalchemy.orm import Session
import psutil
import threading
import time
import traceback
# Import your application modules
from database.database_config import get_db
from database.models import *
from database.crud import *
from api.interview import complete_interview
from api.chat_handling import *
from api.user_registration import register_user
from api.stripe import *
from services.utils import *
from config.env_var import *
app = FastAPI()
@app.get("/")
def read_root(db: Session = Depends(get_db)):
start_time = time.time()
try:
# Check database connectivity
db.execute('SELECT 1')
db_status = "Connected"
# Memory and Thread Count
memory_usage = psutil.virtual_memory().percent
thread_count = threading.active_count()
response_time = time.time() - start_time
logger.info(f"Health check passed in {response_time:.2f} seconds, Memory Usage: {memory_usage}%, Thread Count: {thread_count}, DB Status: {db_status}")
return {"message": "Hello, World!"}
except Exception as e:
response_time = time.time() - start_time
logger.error(f"Health check failed in {response_time:.2f} seconds: {e}")
logger.error(traceback.format_exc())
raise HTTPException(status_code=500, detail=str(e))
For reference, here's how I define my dependency injection:
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from services.utils import logger
import traceback
from config.env_var import *
DB_USER = os.getenv('DB_USER')
DB_PASSWORD = os.getenv('DB_PASSWORD')
DB_HOST = os.getenv('DB_HOST')
DB_NAME = os.getenv('DB_NAME')
Base = declarative_base()
db_url = f'postgresql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:5432/{DB_NAME}'
try:
engine = create_engine(db_url)
except Exception as e:
logger.info(f"Error creating database engine: {e}")
logger.info(traceback.format_exc())
raise
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
def get_db():
db = SessionLocal()
try:
yield db
except Exception as e:
logger.info(f"Database session error: {e}")
logger.info(traceback.format_exc())
raise
finally:
db.close()
I am able to successfully connect via my FastAPI Docker instance to my PostgreSQL instance via this script though:
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
import os
DB_USER = os.getenv('DB_USER')
DB_PASSWORD = os.getenv('DB_PASSWORD')
DB_HOST = os.getenv('DB_HOST')
DB_NAME = os.getenv('DB_NAME')
db_url = f'postgresql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:5432/{DB_NAME}'
engine = create_engine(db_url)
SessionLocal = sessionmaker(bind=engine)
def test_session_local():
session = SessionLocal()
print(f"Session: {session}")
session.close()
def test_db_connection():
try:
db = SessionLocal()
# Perform a simple query
result = db.execute('SELECT 1')
for row in result:
print(row)
db.close()
print("Connection successful.")
except Exception as e:
print(f"Connection failed: {e}")
if __name__ == "__main__":
test_session_local()
test_db_connection()
I don't see where I made a critical failure.
After a suggestion @MatsLindh I realized the error came from another endpoint
It's definition was:
import stripe
from datetime import datetime, timedelta
from sqlalchemy.orm import Session
from fastapi import Request, Depends, HTTPException
from typing import Callable, Dict
from config.env_var import STRIPE_WEBHOOK_SECRET
from database.crud import get_user_by_email, update_user_info
from database.enums import onboard_complete, two_chat, ten_chat, twenty_chat, monthly_subscription
from services.utils import logger
def stripe_api_client() -> stripe:
return stripe
def get_db() -> Session:
pass
async def extract_event(request: Request, stripe_api: stripe = Depends(stripe_api_client)):
payload = await request.body()
sig_header = request.headers.get('stripe-signature')
try:
return stripe_api.Webhook.construct_event(payload, sig_header, STRIPE_WEBHOOK_SECRET)
except ValueError as e:
logger.error(f"Invalid payload: {e}")
raise HTTPException(status_code=400, detail="Invalid payload")
except stripe.error.SignatureVerificationError as e:
logger.error(f"Invalid signature: {e}")
raise HTTPException(status_code=400, detail="Invalid signature")
Issue lies with this section, which passes effectively a None Type
object, which overwrote my get_db
from my database_config.py
:
def get_db() -> Session:
pass
So I removed that and imported my get_db and problem resolved!