Skip to content

Commit 80b4063

Browse files
committed
✨ Refactor: Simplify application lifespan management by moving logic to events module and updating related handlers
1 parent 5478548 commit 80b4063

File tree

4 files changed

+55
-48
lines changed

4 files changed

+55
-48
lines changed

services/catalog/src/simcore_service_catalog/core/application.py

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
import logging
2-
from collections.abc import AsyncIterator
32

43
from fastapi import FastAPI
54
from fastapi.middleware.gzip import GZipMiddleware
6-
from fastapi_lifespan_manager import LifespanManager, State
75
from models_library.basic_types import BootModeEnum
86
from servicelib.fastapi import timing_middleware
97
from servicelib.fastapi.openapi import override_fastapi_openapi_method
10-
from servicelib.fastapi.postgres_lifespan import (
11-
PostgresLifespanStateKeys,
12-
postgres_lifespan,
13-
)
148
from servicelib.fastapi.profiler import initialize_profiler
159
from servicelib.fastapi.prometheus_instrumentation import (
1610
setup_prometheus_instrumentation,
@@ -27,15 +21,12 @@
2721
)
2822
from ..api.rest.routes import setup_rest_api_routes
2923
from ..api.rpc.routes import setup_rpc_api_routes
30-
from ..db.events import setup_database
3124
from ..exceptions.handlers import setup_exception_handlers
3225
from ..services.function_services import setup_function_services
3326
from ..services.rabbitmq import setup_rabbitmq
27+
from . import events
3428
from .events import (
35-
create_on_shutdown,
36-
create_on_startup,
37-
flush_finished_banner,
38-
flush_started_banner,
29+
_create_on_shutdown,
3930
)
4031
from .settings import ApplicationSettings
4132

@@ -52,30 +43,6 @@
5243
)
5344

5445

55-
async def _main_setup(app: FastAPI) -> AsyncIterator[State]:
56-
flush_started_banner()
57-
58-
settings: ApplicationSettings = app.state.settings
59-
60-
yield {
61-
PostgresLifespanStateKeys.POSTGRES_SETTINGS: settings.CATALOG_POSTGRES,
62-
}
63-
64-
flush_finished_banner()
65-
66-
67-
def _create_app_lifespan():
68-
# app lifespan
69-
app_lifespan = LifespanManager()
70-
app_lifespan.add(_main_setup)
71-
72-
# - postgres lifespan
73-
postgres_lifespan.add(setup_database)
74-
app_lifespan.include(postgres_lifespan)
75-
76-
return app_lifespan
77-
78-
7946
def create_app() -> FastAPI:
8047
# keep mostly quiet noisy loggers
8148
quiet_level: int = max(
@@ -96,7 +63,7 @@ def create_app() -> FastAPI:
9663
openapi_url=f"/api/{API_VTAG}/openapi.json",
9764
docs_url="/dev/doc",
9865
redoc_url=None, # default disabled
99-
lifespan=_create_app_lifespan(),
66+
lifespan=events.create_app_lifespan(),
10067
)
10168
override_fastapi_openapi_method(app)
10269

@@ -106,9 +73,6 @@ def create_app() -> FastAPI:
10673
if settings.CATALOG_TRACING:
10774
initialize_tracing(app, settings.CATALOG_TRACING, APP_NAME)
10875

109-
# STARTUP-EVENT
110-
app.add_event_handler("startup", create_on_startup(app))
111-
11276
# PLUGIN SETUP
11377
setup_function_services(app)
11478
setup_rabbitmq(app)
@@ -133,7 +97,7 @@ def create_app() -> FastAPI:
13397
setup_rpc_api_routes(app)
13498

13599
# SHUTDOWN-EVENT
136-
app.add_event_handler("shutdown", create_on_shutdown(app))
100+
app.add_event_handler("shutdown", _create_on_shutdown(app))
137101

138102
# EXCEPTIONS
139103
setup_exception_handlers(app)

services/catalog/src/simcore_service_catalog/core/events.py

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
1+
import contextlib
12
import logging
2-
from collections.abc import Awaitable, Callable
3+
from collections.abc import AsyncIterator, Awaitable, Callable
34
from typing import TypeAlias
45

56
from fastapi import FastAPI
7+
from fastapi_lifespan_manager import LifespanManager, State
8+
from servicelib.fastapi.postgres_lifespan import (
9+
PostgresLifespanStateKeys,
10+
postgres_lifespan,
11+
)
612
from servicelib.logging_utils import log_context
713

814
from .._meta import APP_FINISHED_BANNER_MSG, APP_STARTED_BANNER_MSG
15+
from ..db.events import setup_database
916
from ..services.director import close_director, setup_director
1017
from .background_tasks import start_registry_sync_task, stop_registry_sync_task
18+
from .settings import ApplicationSettings
1119

1220
_logger = logging.getLogger(__name__)
1321

@@ -24,7 +32,19 @@ def flush_finished_banner() -> None:
2432
print(APP_FINISHED_BANNER_MSG, flush=True) # noqa: T201
2533

2634

27-
def create_on_startup(app: FastAPI) -> EventCallable:
35+
async def _main_setup(app: FastAPI) -> AsyncIterator[State]:
36+
flush_started_banner()
37+
38+
settings: ApplicationSettings = app.state.settings
39+
40+
yield {
41+
PostgresLifespanStateKeys.POSTGRES_SETTINGS: settings.CATALOG_POSTGRES,
42+
}
43+
44+
flush_finished_banner()
45+
46+
47+
def _create_on_startup(app: FastAPI) -> EventCallable:
2848
async def _() -> None:
2949

3050
if app.state.settings.CATALOG_DIRECTOR:
@@ -40,7 +60,7 @@ async def _() -> None:
4060
return _
4161

4262

43-
def create_on_shutdown(app: FastAPI) -> EventCallable:
63+
def _create_on_shutdown(app: FastAPI) -> EventCallable:
4464
async def _() -> None:
4565

4666
with log_context(_logger, logging.INFO, "Application shutdown"):
@@ -52,3 +72,27 @@ async def _() -> None:
5272
_logger.exception("Unexpected error while closing application")
5373

5474
return _
75+
76+
77+
@contextlib.asynccontextmanager
78+
async def _other_setup(app: FastAPI) -> AsyncIterator[State]:
79+
80+
await _create_on_startup(app)()
81+
82+
yield {}
83+
84+
await _create_on_shutdown(app)()
85+
86+
87+
def create_app_lifespan():
88+
# app lifespan
89+
app_lifespan = LifespanManager()
90+
app_lifespan.add(_main_setup)
91+
92+
# - postgres lifespan
93+
postgres_lifespan.add(setup_database)
94+
app_lifespan.include(postgres_lifespan)
95+
96+
app_lifespan.add(_other_setup)
97+
98+
return app_lifespan

services/catalog/tests/unit/conftest.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,11 @@ def spy_app(mocker: MockerFixture) -> AppLifeSpanSpyTargets:
117117
# work as expected
118118
return AppLifeSpanSpyTargets(
119119
on_startup=mocker.spy(
120-
simcore_service_catalog.core.application,
120+
simcore_service_catalog.core.events,
121121
"flush_started_banner",
122122
),
123123
on_shutdown=mocker.spy(
124-
simcore_service_catalog.core.application,
124+
simcore_service_catalog.core.events,
125125
"flush_finished_banner",
126126
),
127127
)
@@ -217,9 +217,7 @@ def service_caching_disabled(monkeypatch: pytest.MonkeyPatch) -> None:
217217

218218
@pytest.fixture
219219
def postgres_setup_disabled(mocker: MockerFixture) -> MockType:
220-
return mocker.patch.object(
221-
simcore_service_catalog.core.application, "postgres_lifespan"
222-
)
220+
return mocker.patch.object(simcore_service_catalog.core.events, "postgres_lifespan")
223221

224222

225223
@pytest.fixture

services/catalog/tests/unit/test_services_director.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ async def test_director_client_high_level_api(
6161

6262

6363
async def test_director_client_low_level_api(
64+
postgres_setup_disabled: MockType,
6465
background_tasks_setup_disabled: None,
6566
rabbitmq_and_rpc_setup_disabled: None,
6667
mocked_director_service_api: MockRouter,

0 commit comments

Comments
 (0)