From c0c4a566c405ce7c6bfe595d561c628be123ddf1 Mon Sep 17 00:00:00 2001 From: Artem Litvinov Date: Sat, 30 Sep 2023 21:09:36 +0100 Subject: [PATCH] fix: postgres client & dispose engine --- src/fastapi_app/lib/app/app.py | 9 ++++ .../lib/app/split_settings/postgres.py | 49 +++++++------------ src/fastapi_app/lib/clients/__init__.py | 4 +- src/fastapi_app/lib/clients/postgres.py | 42 +++++++++------- src/fastapi_app/lib/models/__init__.py | 2 +- 5 files changed, 55 insertions(+), 51 deletions(-) diff --git a/src/fastapi_app/lib/app/app.py b/src/fastapi_app/lib/app/app.py index ea25a43..3443f7c 100644 --- a/src/fastapi_app/lib/app/app.py +++ b/src/fastapi_app/lib/app/app.py @@ -10,6 +10,7 @@ import lib.api.v1.handlers as api_v1_handlers import lib.app.errors as app_errors import lib.app.settings as app_settings import lib.app.split_settings as app_split_settings +import lib.clients as clients logger = logging.getLogger(__name__) @@ -43,6 +44,14 @@ class Application: # Global clients logger.info("Initializing global clients") + postgres_client = clients.AsyncPostgresClient(settings=settings) + + disposable_resources.append( + DisposableResource( + name="postgres_client", + dispose_callback=postgres_client.dispose_callback(), + ) + ) # Clients diff --git a/src/fastapi_app/lib/app/split_settings/postgres.py b/src/fastapi_app/lib/app/split_settings/postgres.py index 90c0aea..b5a2eb9 100644 --- a/src/fastapi_app/lib/app/split_settings/postgres.py +++ b/src/fastapi_app/lib/app/split_settings/postgres.py @@ -4,19 +4,28 @@ import pydantic_settings import lib.app.split_settings.utils as app_split_settings_utils -class DBSettings(pydantic_settings.BaseSettings): - """Parent DB Settings Class.""" +class PostgresSettings(pydantic_settings.BaseSettings): + """Postgres settings.""" + + model_config = pydantic_settings.SettingsConfigDict( + env_file=app_split_settings_utils.ENV_PATH, + env_prefix="POSTGRES_", + env_file_encoding="utf-8", + extra="ignore", + ) # Connection settings - driver: str - db_name: str - host: str - port: int - user: str - password: pydantic.SecretStr + driver: str = "postgresql+asyncpg" + db_name: str = "database_name" + host: str = "localhost" + port: int = 5432 + user: str = "app" + password: pydantic.SecretStr = pydantic.Field( + default=..., validation_alias=pydantic.AliasChoices("password", "postgres_password") + ) - # Enginge settings - pool_size: int = 10 + # Engine settings + pool_size: int = 50 pool_pre_ping: bool = True echo: bool = False @@ -33,23 +42,3 @@ class DBSettings(pydantic_settings.BaseSettings): @property def dsn_as_safe_url(self) -> str: return f"{self.driver}://{self.user}:***@{self.host}:{self.port}" - - -class PostgresSettings(DBSettings): - """Postgres settings.""" - - model_config = pydantic_settings.SettingsConfigDict( - env_file=app_split_settings_utils.ENV_PATH, - env_prefix="POSTGRES_", - env_file_encoding="utf-8", - extra="ignore", - ) - - driver: str = "postgresql+asyncpg" - db_name: str = "database_name" - host: str = "localhost" - port: int = 5432 - user: str = "app" - password: pydantic.SecretStr = pydantic.Field( - default=..., validation_alias=pydantic.AliasChoices("password", "postgres_password") - ) diff --git a/src/fastapi_app/lib/clients/__init__.py b/src/fastapi_app/lib/clients/__init__.py index 2a44c3f..1fbe64c 100644 --- a/src/fastapi_app/lib/clients/__init__.py +++ b/src/fastapi_app/lib/clients/__init__.py @@ -1,3 +1,3 @@ -from .postgres import get_async_session +from .postgres import AsyncPostgresClient -__all__ = ["get_async_session"] +__all__ = ["AsyncPostgresClient"] diff --git a/src/fastapi_app/lib/clients/postgres.py b/src/fastapi_app/lib/clients/postgres.py index 147e950..dece0dc 100644 --- a/src/fastapi_app/lib/clients/postgres.py +++ b/src/fastapi_app/lib/clients/postgres.py @@ -1,24 +1,30 @@ import sqlalchemy.ext.asyncio as sa_asyncio -import lib.app.split_settings as app_split_settings +import lib.app.settings as app_settings -async def get_async_session( - settings: app_split_settings.DBSettings, -) -> sa_asyncio.async_sessionmaker[sa_asyncio.AsyncSession]: - engine = sa_asyncio.create_async_engine( - url=settings.dsn, - pool_size=settings.pool_size, - pool_pre_ping=settings.pool_pre_ping, - echo=settings.echo, - future=True, - ) +class AsyncPostgresClient: + """Async Postgres Client that return sessionmaker.""" - async_session = sa_asyncio.async_sessionmaker( - bind=engine, - autocommit=settings.auto_commit, - autoflush=settings.auto_flush, - expire_on_commit=settings.expire_on_commit, - ) + def __init__(self, settings: app_settings.Settings) -> None: + self.settings = settings.postgres + self.async_enging = sa_asyncio.create_async_engine( + url=self.settings.dsn, + pool_size=self.settings.pool_size, + pool_pre_ping=self.settings.pool_pre_ping, + echo=self.settings.echo, + future=True, + ) - return async_session # noqa: RET504 + def get_async_session(self) -> sa_asyncio.async_sessionmaker[sa_asyncio.AsyncSession]: + async_session = sa_asyncio.async_sessionmaker( + bind=self.async_enging, + autocommit=self.settings.auto_commit, + autoflush=self.settings.auto_flush, + expire_on_commit=self.settings.expire_on_commit, + ) + + return async_session # noqa: RET504 + + async def dispose_callback(self) -> None: + await self.async_enging.dispose() diff --git a/src/fastapi_app/lib/models/__init__.py b/src/fastapi_app/lib/models/__init__.py index 80a73f7..33fb529 100644 --- a/src/fastapi_app/lib/models/__init__.py +++ b/src/fastapi_app/lib/models/__init__.py @@ -1,4 +1,4 @@ from .base_sqlalchemy import Base, IdCreatedUpdatedBaseMixin from .token import Token -__all__ = ["Base", "Token", "IdCreatedUpdatedBaseMixin"] +__all__ = ["Base", "IdCreatedUpdatedBaseMixin", "Token"]