fix: unclosed sessions (#1734)

* resolve session leak

* cleanup session management functions
This commit is contained in:
Hayden
2022-10-17 14:11:40 -08:00
committed by GitHub
parent a3904c45d8
commit e516a2e801
12 changed files with 132 additions and 90 deletions

View File

@@ -31,22 +31,31 @@ SessionLocal, engine = sql_global_init(settings.DB_URL) # type: ignore
@contextmanager
def with_session() -> Session:
def session_context() -> Session:
"""
session_context() provides a managed session to the database that is automatically
closed when the context is exited. This is the preferred method of accessing the
database.
Note: use `generate_session` when using the `Depends` function from FastAPI
"""
global SessionLocal
sess = SessionLocal()
try:
yield sess
finally:
sess.close()
def create_session() -> Session:
global SessionLocal
return SessionLocal()
def generate_session() -> Generator[Session, None, None]:
"""
WARNING: This function should _only_ be called when used with
using the `Depends` function from FastAPI. This function will leak
sessions if used outside of the context of a request.
Use `with_session` instead. That function will allow you to use the
session within a context manager
"""
global SessionLocal
db = SessionLocal()
try:

View File

@@ -9,7 +9,7 @@ from alembic.config import Config
from alembic.runtime import migration
from mealie.core import root_logger
from mealie.core.config import get_app_settings
from mealie.db.db_setup import create_session
from mealie.db.db_setup import session_context
from mealie.db.fixes.fix_slug_foods import fix_slug_food_names
from mealie.repos.all_repositories import get_repositories
from mealie.repos.repository_factory import AllRepositories
@@ -67,41 +67,40 @@ def connect(session: orm.Session) -> bool:
def main():
session = create_session()
# Wait for database to connect
max_retry = 10
wait_seconds = 1
while True:
if connect(session):
logger.info("Database connection established.")
break
with session_context() as session:
while True:
if connect(session):
logger.info("Database connection established.")
break
logger.error(f"Database connection failed. Retrying in {wait_seconds} seconds...")
max_retry -= 1
logger.error(f"Database connection failed. Retrying in {wait_seconds} seconds...")
max_retry -= 1
sleep(wait_seconds)
sleep(wait_seconds)
if max_retry == 0:
raise ConnectionError("Database connection failed - exiting application.")
if max_retry == 0:
raise ConnectionError("Database connection failed - exiting application.")
alembic_cfg = Config(str(PROJECT_DIR / "alembic.ini"))
if db_is_at_head(alembic_cfg):
logger.info("Migration not needed.")
else:
logger.info("Migration needed. Performing migration...")
command.upgrade(alembic_cfg, "head")
alembic_cfg = Config(str(PROJECT_DIR / "alembic.ini"))
if db_is_at_head(alembic_cfg):
logger.info("Migration not needed.")
else:
logger.info("Migration needed. Performing migration...")
command.upgrade(alembic_cfg, "head")
db = get_repositories(session)
db = get_repositories(session)
if db.users.get_all():
logger.info("Database exists")
else:
logger.info("Database contains no users, initializing...")
init_db(db)
if db.users.get_all():
logger.info("Database exists")
else:
logger.info("Database contains no users, initializing...")
init_db(db)
safe_try(lambda: fix_slug_food_names(db))
safe_try(lambda: fix_slug_food_names(db))
if __name__ == "__main__":