-
Notifications
You must be signed in to change notification settings - Fork 32
♻️ Preparations in webserver to integrate asyncpg engine #6466
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
pcrespov
merged 21 commits into
ITISFoundation:master
from
pcrespov:mai/db-async-engine
Sep 30, 2024
Merged
Changes from 18 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
28663c9
asyncpg interface for both fastapi and aiohttp
pcrespov 76f1c77
PostgresSettings url helper members
pcrespov c862398
rename app's state key for aiopg engine
pcrespov 6c1074a
same in storage service
pcrespov 7aa76dd
rename get_database_engine -> get_aiopg_engine
pcrespov cf49d8f
uses api
pcrespov f5da4f2
splits aiopg and asyncpg contributions
pcrespov 4e12b09
reverts names
pcrespov b0ec158
not active
pcrespov f60a38f
use api to get engine from app
pcrespov c9485df
catalog
pcrespov 8a077fa
payments
pcrespov 9bf9d04
storage
pcrespov b745870
test
pcrespov f36ea9f
pylint
pcrespov 70f4d87
cleanup
pcrespov c18b58f
minor fix in tests
pcrespov 54179cd
server settings
pcrespov 08a6261
Merge branch 'master' into mai/db-async-engine
pcrespov 0a8de81
Merge branch 'master' into mai/db-async-engine
pcrespov da1b807
Merge branch 'master' into mai/db-async-engine
pcrespov File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
packages/service-library/src/servicelib/aiohttp/db_asyncpg_engine.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| """ | ||
| Helpers on asyncpg specific for aiohttp | ||
| SEE migration aiopg->asyncpg https://github.com/ITISFoundation/osparc-simcore/issues/4529 | ||
| """ | ||
|
|
||
|
|
||
| import logging | ||
| from typing import Final | ||
|
|
||
| from aiohttp import web | ||
| from servicelib.logging_utils import log_context | ||
| from settings_library.postgres import PostgresSettings | ||
| from simcore_postgres_database.utils_aiosqlalchemy import ( # type: ignore[import-not-found] # this on is unclear | ||
| get_pg_engine_stateinfo, | ||
| ) | ||
| from sqlalchemy.ext.asyncio import AsyncEngine | ||
|
|
||
| from ..db_asyncpg_utils import create_async_engine_and_pg_database_ready | ||
| from ..logging_utils import log_context | ||
|
|
||
| APP_DB_ASYNC_ENGINE_KEY: Final[str] = f"{__name__ }.AsyncEngine" | ||
|
|
||
|
|
||
| _logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def _set_async_engine_to_app_state(app: web.Application, engine: AsyncEngine): | ||
| if exists := app.get(APP_DB_ASYNC_ENGINE_KEY, None): | ||
| msg = f"An instance of {type(exists)} already in app[{APP_DB_ASYNC_ENGINE_KEY}]={exists}" | ||
| raise ValueError(msg) | ||
|
|
||
| app[APP_DB_ASYNC_ENGINE_KEY] = engine | ||
| return get_async_engine(app) | ||
|
|
||
|
|
||
| def get_async_engine(app: web.Application) -> AsyncEngine: | ||
| engine: AsyncEngine = app[APP_DB_ASYNC_ENGINE_KEY] | ||
| assert engine # nosec | ||
| return engine | ||
|
|
||
|
|
||
| async def connect_to_db(app: web.Application, settings: PostgresSettings) -> None: | ||
| """ | ||
| - db services up, data migrated and ready to use | ||
| - sets an engine in app state (use `get_async_engine(app)` to retrieve) | ||
| """ | ||
| if settings.POSTGRES_CLIENT_NAME: | ||
| settings = settings.copy( | ||
| update={"POSTGRES_CLIENT_NAME": settings.POSTGRES_CLIENT_NAME + "-asyncpg"} | ||
| ) | ||
|
|
||
| with log_context( | ||
| _logger, | ||
| logging.INFO, | ||
| "Connecting app[APP_DB_ASYNC_ENGINE_KEY] to postgres with %s", | ||
| f"{settings=}", | ||
| ): | ||
| engine = await create_async_engine_and_pg_database_ready(settings) | ||
| _set_async_engine_to_app_state(app, engine) | ||
|
|
||
| _logger.info( | ||
| "app[APP_DB_ASYNC_ENGINE_KEY] ready : %s", | ||
| await get_pg_engine_stateinfo(engine), | ||
| ) | ||
|
|
||
|
|
||
| async def close_db_connection(app: web.Application) -> None: | ||
| engine = get_async_engine(app) | ||
| with log_context( | ||
| _logger, logging.DEBUG, f"app[APP_DB_ASYNC_ENGINE_KEY] disconnect of {engine}" | ||
| ): | ||
| if engine: | ||
| await engine.dispose() |
63 changes: 63 additions & 0 deletions
63
packages/service-library/src/servicelib/db_asyncpg_utils.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| import logging | ||
| import time | ||
| from datetime import timedelta | ||
|
|
||
| from models_library.healthchecks import IsNonResponsive, IsResponsive, LivenessResult | ||
| from settings_library.postgres import PostgresSettings | ||
| from simcore_postgres_database.utils_aiosqlalchemy import ( # type: ignore[import-not-found] # this on is unclear | ||
| raise_if_migration_not_ready, | ||
| ) | ||
| from sqlalchemy.exc import SQLAlchemyError | ||
| from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine | ||
| from tenacity import retry | ||
|
|
||
| from .retry_policies import PostgresRetryPolicyUponInitialization | ||
|
|
||
| _logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| @retry(**PostgresRetryPolicyUponInitialization(_logger).kwargs) | ||
| async def create_async_engine_and_pg_database_ready( | ||
| settings: PostgresSettings, | ||
| ) -> AsyncEngine: | ||
| """ | ||
| - creates asyncio engine | ||
| - waits until db service is up | ||
| - waits until db data is migrated (i.e. ready to use) | ||
| - returns engine | ||
| """ | ||
| server_settings = None | ||
| if settings.POSTGRES_CLIENT_NAME: | ||
| server_settings = { | ||
| "application_name": settings.POSTGRES_CLIENT_NAME, | ||
| } | ||
|
|
||
| engine: AsyncEngine = create_async_engine( | ||
| settings.dsn_with_async_sqlalchemy, | ||
| pool_size=settings.POSTGRES_MINSIZE, | ||
| max_overflow=settings.POSTGRES_MAXSIZE - settings.POSTGRES_MINSIZE, | ||
| connect_args={"server_settings": server_settings}, | ||
| pool_pre_ping=True, # https://docs.sqlalchemy.org/en/14/core/pooling.html#dealing-with-disconnects | ||
| future=True, # this uses sqlalchemy 2.0 API, shall be removed when sqlalchemy 2.0 is released | ||
| ) | ||
|
|
||
| try: | ||
| await raise_if_migration_not_ready(engine) | ||
| except Exception: | ||
| # NOTE: engine must be closed because retry will create a new engine | ||
| await engine.dispose() | ||
| raise | ||
|
|
||
| return engine | ||
|
|
||
|
|
||
| async def check_postgres_liveness(engine: AsyncEngine) -> LivenessResult: | ||
| try: | ||
| tic = time.time() | ||
| # test | ||
| async with engine.connect(): | ||
| ... | ||
| elapsed_time = time.time() - tic | ||
| return IsResponsive(elapsed=timedelta(seconds=elapsed_time)) | ||
| except SQLAlchemyError as err: | ||
| return IsNonResponsive(reason=f"{err}") | ||
33 changes: 33 additions & 0 deletions
33
packages/service-library/src/servicelib/fastapi/db_asyncpg_engine.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import logging | ||
|
|
||
| from fastapi import FastAPI | ||
| from settings_library.postgres import PostgresSettings | ||
| from simcore_postgres_database.utils_aiosqlalchemy import ( # type: ignore[import-not-found] # this on is unclear | ||
| get_pg_engine_stateinfo, | ||
| ) | ||
|
|
||
| from ..db_asyncpg_utils import create_async_engine_and_pg_database_ready | ||
| from ..logging_utils import log_context | ||
|
|
||
| _logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| async def connect_to_db(app: FastAPI, settings: PostgresSettings) -> None: | ||
| with log_context( | ||
| _logger, | ||
| logging.DEBUG, | ||
| f"Connecting and migraging {settings.dsn_with_async_sqlalchemy}", | ||
| ): | ||
| engine = await create_async_engine_and_pg_database_ready(settings) | ||
|
|
||
| app.state.engine = engine | ||
| _logger.debug( | ||
| "Setup engine: %s", | ||
| await get_pg_engine_stateinfo(engine), | ||
| ) | ||
|
|
||
|
|
||
| async def close_db_connection(app: FastAPI) -> None: | ||
| with log_context(_logger, logging.DEBUG, f"db disconnect of {app.state.engine}"): | ||
| if engine := app.state.engine: | ||
| await engine.dispose() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
.../resource-usage-tracker/src/simcore_service_resource_usage_tracker/modules/db/__init__.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.