I have a FastAPI application that I'm using AWS secrets manager to store things like connection strings. In main.py I have fastapi configured to load the secrets into environment variables on startup of the app. I have a file db.py where it uses these secrets to create a database engine. However it seems that the engine creation is happening in db.py is happening either at the same time or before load_secrets in @app.on_event("startup") because I get an error essentially saying that the environment variables needed to make the db connection string are None. How can I get it so it doesn't try to run the code in db.py to create the engine until after everything in @app.on_event("startup") finishes? I know I could wrap the code in db.py in a function and just create a new but it seems a little silly to create a new engine each time vs just creating the engine once and then spawning sessions off that 1 engine as needed. Thanks.
main.py below
# Package Imports
from fastapi import FastAPI, HTTPException
from mangum import Mangum
import uvicorn
import os
from dotenv import load_dotenv
import boto3
import json
# File Imports
from api.api_v1.api import router as api_router_v1
# Loads secrets from AWS Secrets Manager Into Environment Variables
def load_secrets():
try:
# Load environment variables from .env file
load_dotenv()
session = boto3.session.Session()
client = session.client(service_name='secretsmanager', region_name= os.getenv('AWS_REGION_NAME'), aws_access_key_id= os.getenv('AWS_ACCESS_KEY_ID'), aws_secret_access_key= os.getenv('AWS_SECRET_ACCESS_KEY'))
get_secret_value_response = client.get_secret_value(SecretId=os.getenv('AWS_SECRET_NAME'))
if 'SecretString' in get_secret_value_response:
secret = get_secret_value_response['SecretString']
json_secret = json.loads(secret)
for key, value in json_secret.items():
os.environ[key] = value
else:
raise HTTPException(status_code=503, detail="One or more secrets are missing. Unable to start the application.")
except Exception as ex:
raise HTTPException(status_code=503, detail=str(ex))
app = FastAPI(
docs_url="/",
title="API",
description="",
version="0.0.1"
)
# Define startup code.
@app.on_event("startup")
def startup_event():
load_secrets()
# Define the routes
app.include_router(api_router_v1, prefix="/api/v1")
# This is the handler for AWS
handler = Mangum(app)
# This runs the app for testing
if __name__ == '__main__':
uvicorn.run('main:app', host="localhost", port=8000, reload=True, timeout_keep_alive=3000)
db.py below
import os
from sqlmodel import create_engine, Session
from sqlalchemy.engine import URL
connection_string = 'DRIVER={};SERVER={};DATABASE={};UID={};PWD={}'.format(os.getenv('DRIVER'), os.getenv('SERVER'), os.getenv('DB'), os.getenv('USERNAME'), os.getenv('PASSWORD'))
connection_url = URL.create("mssql+pyodbc", query={"odbc_connect": connection_string})
engine = create_engine(connection_url)