Skip to content

Commit 0af3576

Browse files
authored
feat: fail at startup when connections info is incorrect - DIA-38713 (#42)
1 parent b47da06 commit 0af3576

5 files changed

Lines changed: 68 additions & 15 deletions

File tree

fastapi_sqla/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,17 @@ def startup():
6666
Base.metadata.bind = engine
6767
Base.prepare(engine)
6868
_Session.configure(bind=engine)
69+
70+
# Fail early:
71+
try:
72+
with open_session() as session:
73+
session.execute("select 'OK'")
74+
except Exception:
75+
logger.critical(
76+
"Fail querying db: is sqlalchemy_url envvar correctly configured?"
77+
)
78+
raise
79+
6980
logger.info("startup", engine=engine)
7081

7182

fastapi_sqla/_pytest_plugin.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def sqla_reflection(sqla_modules, sqla_connection, db_url):
7878
@fixture(autouse=True)
7979
def engine_from_config(request, db_url, sqla_connection, sqla_transaction):
8080
"""So that all DB operations are never written to db for real."""
81-
if "dont_patch_engine_from_config" in request.keywords:
81+
if "dont_patch_engines" in request.keywords:
8282
yield
8383

8484
else:
@@ -135,13 +135,19 @@ async def async_sqla_connection(async_engine, event_loop):
135135
await connection.rollback()
136136

137137
@fixture(autouse=True)
138-
async def patch_async_sessionmaker(async_sqlalchemy_url, async_sqla_connection):
138+
async def patch_async_sessionmaker(
139+
async_sqlalchemy_url, async_sqla_connection, request
140+
):
139141
"""So that all async DB operations are never written to db for real."""
140-
with patch(
141-
"fastapi_sqla.asyncio_support.create_async_engine"
142-
) as create_async_engine:
143-
create_async_engine.return_value = async_sqla_connection
144-
yield create_async_engine
142+
if "dont_patch_engines" in request.keywords:
143+
yield
144+
145+
else:
146+
with patch(
147+
"fastapi_sqla.asyncio_support.create_async_engine"
148+
) as create_async_engine:
149+
create_async_engine.return_value = async_sqla_connection
150+
yield create_async_engine
145151

146152
@fixture
147153
async def async_session(async_sqla_connection):

fastapi_sqla/asyncio_support.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import structlog
55
from fastapi import Request
6+
from sqlalchemy import text
67
from sqlalchemy.ext.asyncio import AsyncSession as SqlaAsyncSession
78
from sqlalchemy.ext.asyncio import create_async_engine
89
from sqlalchemy.orm.session import sessionmaker
@@ -12,10 +13,22 @@
1213
_AsyncSession = sessionmaker(class_=SqlaAsyncSession)
1314

1415

15-
def startup():
16+
async def startup():
1617
async_sqlalchemy_url = os.environ["async_sqlalchemy_url"]
17-
async_engine = create_async_engine(async_sqlalchemy_url)
18-
_AsyncSession.configure(bind=async_engine, expire_on_commit=False)
18+
engine = create_async_engine(async_sqlalchemy_url)
19+
_AsyncSession.configure(bind=engine, expire_on_commit=False)
20+
21+
# Fail early:
22+
try:
23+
async with open_session() as session:
24+
await session.execute(text("select 'ok'"))
25+
except Exception:
26+
logger.critical(
27+
"Fail querying db: is async_sqlalchemy_url envvar correctly configured?"
28+
)
29+
raise
30+
31+
logger.info("startup", async_engine=engine)
1932

2033

2134
class AsyncSession(SqlaAsyncSession):

tests/test_asyncio_support.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@
55

66

77
@fixture(autouse=True)
8-
def setup(environ):
8+
async def setup(environ):
99
from fastapi_sqla.asyncio_support import startup
1010

11-
startup()
11+
await startup()
1212
yield
1313

1414

1515
async def test_startup_configure_async_session():
1616
from fastapi_sqla.asyncio_support import _AsyncSession, startup
1717

18-
startup()
18+
await startup()
1919

2020
async with _AsyncSession() as session:
2121
res = await session.execute(text("SELECT 123"))

tests/test_startup.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import httpx
44
from asgi_lifespan import LifespanManager
55
from fastapi import FastAPI
6-
from pytest import fixture, mark
6+
from pytest import fixture, mark, raises
77
from sqlalchemy import text
88

99

@@ -16,7 +16,7 @@ def case_sensitive_environ(environ, request):
1616
yield values
1717

1818

19-
@mark.dont_patch_engine_from_config
19+
@mark.dont_patch_engines
2020
def test_startup(case_sensitive_environ):
2121
from fastapi_sqla import _Session, startup
2222

@@ -48,3 +48,26 @@ def now():
4848
res = await client.get("/one")
4949

5050
assert res.json() == 1
51+
52+
53+
@mark.dont_patch_engines
54+
def test_startup_fail_on_bad_sqlalchemy_url(monkeypatch):
55+
from fastapi_sqla import startup
56+
57+
monkeypatch.setenv("sqlalchemy_url", "postgresql://postgres@localhost/notexisting")
58+
59+
with raises(Exception):
60+
startup()
61+
62+
63+
@mark.asyncio
64+
@mark.dont_patch_engines
65+
async def test_async_startup_fail_on_bad_async_sqlalchemy_url(monkeypatch):
66+
from fastapi_sqla import asyncio_support
67+
68+
monkeypatch.setenv(
69+
"async_sqlalchemy_url", "postgresql+asyncpg://postgres@localhost/notexisting"
70+
)
71+
72+
with raises(Exception):
73+
await asyncio_support.startup()

0 commit comments

Comments
 (0)