diff --git a/packages/service-library/src/servicelib/fastapi/docker.py b/packages/service-library/src/servicelib/fastapi/docker.py index 058c0c676b52..c1e61f969d57 100644 --- a/packages/service-library/src/servicelib/fastapi/docker.py +++ b/packages/service-library/src/servicelib/fastapi/docker.py @@ -11,7 +11,6 @@ from fastapi import FastAPI from fastapi_lifespan_manager import State from pydantic import NonNegativeInt -from servicelib.fastapi.lifespan_utils import LifespanGenerator from settings_library.docker_api_proxy import DockerApiProxysettings _logger = logging.getLogger(__name__) @@ -19,43 +18,48 @@ _DEFAULT_DOCKER_API_PROXY_HEALTH_TIMEOUT: Final[NonNegativeInt] = 5 -def get_lifespan_remote_docker_client( - settings: DockerApiProxysettings, -) -> LifespanGenerator: - async def _(app: FastAPI) -> AsyncIterator[State]: +_DOCKER_API_PROXY_SETTINGS: Final[str] = "docker_api_proxy_settings" - session: ClientSession | None = None - if settings.DOCKER_API_PROXY_USER and settings.DOCKER_API_PROXY_PASSWORD: - session = ClientSession( - auth=aiohttp.BasicAuth( - login=settings.DOCKER_API_PROXY_USER, - password=settings.DOCKER_API_PROXY_PASSWORD.get_secret_value(), - ) + +def create_remote_docker_client_input_state(settings: DockerApiProxysettings) -> State: + return {_DOCKER_API_PROXY_SETTINGS: settings} + + +async def remote_docker_client_lifespan( + app: FastAPI, state: State +) -> AsyncIterator[State]: + settings: DockerApiProxysettings = state[_DOCKER_API_PROXY_SETTINGS] + + session: ClientSession | None = None + if settings.DOCKER_API_PROXY_USER and settings.DOCKER_API_PROXY_PASSWORD: + session = ClientSession( + auth=aiohttp.BasicAuth( + login=settings.DOCKER_API_PROXY_USER, + password=settings.DOCKER_API_PROXY_PASSWORD.get_secret_value(), ) + ) - async with AsyncExitStack() as exit_stack: - if settings.DOCKER_API_PROXY_USER and settings.DOCKER_API_PROXY_PASSWORD: - await exit_stack.enter_async_context( - ClientSession( - auth=aiohttp.BasicAuth( - login=settings.DOCKER_API_PROXY_USER, - password=settings.DOCKER_API_PROXY_PASSWORD.get_secret_value(), - ) + async with AsyncExitStack() as exit_stack: + if settings.DOCKER_API_PROXY_USER and settings.DOCKER_API_PROXY_PASSWORD: + await exit_stack.enter_async_context( + ClientSession( + auth=aiohttp.BasicAuth( + login=settings.DOCKER_API_PROXY_USER, + password=settings.DOCKER_API_PROXY_PASSWORD.get_secret_value(), ) ) - - client = await exit_stack.enter_async_context( - aiodocker.Docker(url=settings.base_url, session=session) ) - app.state.remote_docker_client = client + client = await exit_stack.enter_async_context( + aiodocker.Docker(url=settings.base_url, session=session) + ) - await wait_till_docker_api_proxy_is_responsive(app) + app.state.remote_docker_client = client - # NOTE this has to be inside exit_stack scope - yield {} + await wait_till_docker_api_proxy_is_responsive(app) - return _ + # NOTE this has to be inside exit_stack scope + yield {} @tenacity.retry( diff --git a/packages/service-library/src/servicelib/fastapi/lifespan_utils.py b/packages/service-library/src/servicelib/fastapi/lifespan_utils.py index 05d70104a172..8b16f5bec194 100644 --- a/packages/service-library/src/servicelib/fastapi/lifespan_utils.py +++ b/packages/service-library/src/servicelib/fastapi/lifespan_utils.py @@ -1,9 +1,4 @@ -from collections.abc import AsyncIterator -from typing import Protocol - from common_library.errors_classes import OsparcErrorMixin -from fastapi import FastAPI -from fastapi_lifespan_manager import LifespanManager, State class LifespanError(OsparcErrorMixin, RuntimeError): ... @@ -15,17 +10,3 @@ class LifespanOnStartupError(LifespanError): class LifespanOnShutdownError(LifespanError): msg_template = "Failed during shutdown of {module}" - - -class LifespanGenerator(Protocol): - def __call__(self, app: FastAPI) -> AsyncIterator["State"]: ... - - -def combine_lifespans(*generators: LifespanGenerator) -> LifespanManager: - - manager = LifespanManager() - - for generator in generators: - manager.add(generator) - - return manager diff --git a/packages/service-library/src/servicelib/fastapi/postgres_lifespan.py b/packages/service-library/src/servicelib/fastapi/postgres_lifespan.py index def76edd62af..cc207e6f397a 100644 --- a/packages/service-library/src/servicelib/fastapi/postgres_lifespan.py +++ b/packages/service-library/src/servicelib/fastapi/postgres_lifespan.py @@ -3,6 +3,7 @@ from collections.abc import AsyncIterator from enum import Enum +from fastapi import FastAPI from fastapi_lifespan_manager import State from servicelib.logging_utils import log_catch, log_context from settings_library.postgres import PostgresSettings @@ -23,11 +24,11 @@ class PostgresConfigurationError(LifespanOnStartupError): msg_template = "Invalid postgres settings [={settings}] on startup. Note that postgres cannot be disabled using settings" -def create_input_state(settings: PostgresSettings) -> State: +def create_postgres_database_input_state(settings: PostgresSettings) -> State: return {PostgresLifespanState.POSTGRES_SETTINGS: settings} -async def postgres_database_lifespan(_, state: State) -> AsyncIterator[State]: +async def postgres_database_lifespan(_: FastAPI, state: State) -> AsyncIterator[State]: with log_context(_logger, logging.INFO, f"{__name__}"): diff --git a/packages/service-library/src/servicelib/fastapi/prometheus_instrumentation.py b/packages/service-library/src/servicelib/fastapi/prometheus_instrumentation.py index c9b9fb581708..65464e6955fb 100644 --- a/packages/service-library/src/servicelib/fastapi/prometheus_instrumentation.py +++ b/packages/service-library/src/servicelib/fastapi/prometheus_instrumentation.py @@ -1,7 +1,7 @@ # pylint: disable=protected-access - from collections.abc import AsyncIterator +from typing import Final from fastapi import FastAPI from fastapi_lifespan_manager import State @@ -54,9 +54,23 @@ def _on_shutdown() -> None: return get_prometheus_instrumentator(app) -async def lifespan_prometheus_instrumentation(app: FastAPI) -> AsyncIterator[State]: +_PROMETHEUS_INSTRUMENTATION_ENABLED: Final[str] = "prometheus_instrumentation_enabled" + + +def create_prometheus_instrumentationmain_input_state(*, enabled: bool) -> State: + return {_PROMETHEUS_INSTRUMENTATION_ENABLED: enabled} + + +async def prometheus_instrumentation_lifespan( + app: FastAPI, state: State +) -> AsyncIterator[State]: # NOTE: requires ``initialize_prometheus_instrumentation`` to be called before the # lifespan of the applicaiton runs, usually rigth after the ``FastAPI`` instance is created - _startup(app) + + instrumentaiton_enabled = state.get(_PROMETHEUS_INSTRUMENTATION_ENABLED, False) + if instrumentaiton_enabled: + + _startup(app) yield {} - _shutdown(app) + if instrumentaiton_enabled: + _shutdown(app) diff --git a/packages/service-library/tests/fastapi/test_lifespan_utils.py b/packages/service-library/tests/fastapi/test_lifespan_utils.py index a89b64603f27..0c3d2767d2a1 100644 --- a/packages/service-library/tests/fastapi/test_lifespan_utils.py +++ b/packages/service-library/tests/fastapi/test_lifespan_utils.py @@ -18,7 +18,6 @@ from servicelib.fastapi.lifespan_utils import ( LifespanOnShutdownError, LifespanOnStartupError, - combine_lifespans, ) @@ -35,7 +34,11 @@ async def cache_lifespan(app: FastAPI) -> AsyncIterator[State]: yield {} print("shutdown CACHE") - app = FastAPI(lifespan=combine_lifespans(database_lifespan, cache_lifespan)) + lifespan_manager = LifespanManager() + lifespan_manager.add(database_lifespan) + lifespan_manager.add(cache_lifespan) + + app = FastAPI(lifespan=lifespan_manager) capsys.readouterr() diff --git a/services/catalog/src/simcore_service_catalog/core/events.py b/services/catalog/src/simcore_service_catalog/core/events.py index 95f48f8e07b8..57089d9fc5e9 100644 --- a/services/catalog/src/simcore_service_catalog/core/events.py +++ b/services/catalog/src/simcore_service_catalog/core/events.py @@ -4,10 +4,11 @@ from fastapi import FastAPI from fastapi_lifespan_manager import LifespanManager, State from servicelib.fastapi.postgres_lifespan import ( - PostgresLifespanState, + create_postgres_database_input_state, ) from servicelib.fastapi.prometheus_instrumentation import ( - lifespan_prometheus_instrumentation, + create_prometheus_instrumentationmain_input_state, + prometheus_instrumentation_lifespan, ) from .._meta import APP_FINISHED_BANNER_MSG, APP_STARTED_BANNER_MSG @@ -38,27 +39,21 @@ async def _banners_lifespan(_) -> AsyncIterator[State]: _flush_finished_banner() -async def _main_lifespan(app: FastAPI) -> AsyncIterator[State]: +async def _settings_lifespan(app: FastAPI) -> AsyncIterator[State]: settings: ApplicationSettings = app.state.settings yield { - PostgresLifespanState.POSTGRES_SETTINGS: settings.CATALOG_POSTGRES, - "prometheus_instrumentation_enabled": settings.CATALOG_PROMETHEUS_INSTRUMENTATION_ENABLED, + **create_postgres_database_input_state(settings.CATALOG_POSTGRES), + **create_prometheus_instrumentationmain_input_state( + enabled=settings.CATALOG_PROMETHEUS_INSTRUMENTATION_ENABLED + ), } -async def _prometheus_instrumentation_lifespan( - app: FastAPI, state: State -) -> AsyncIterator[State]: - if state.get("prometheus_instrumentation_enabled", False): - async for prometheus_state in lifespan_prometheus_instrumentation(app): - yield prometheus_state - - -def create_app_lifespan(): +def create_app_lifespan() -> LifespanManager: # WARNING: order matters app_lifespan = LifespanManager() - app_lifespan.add(_main_lifespan) + app_lifespan.add(_settings_lifespan) # - postgres app_lifespan.include(repository_lifespan_manager) @@ -79,7 +74,7 @@ def create_app_lifespan(): app_lifespan.add(background_task_lifespan) # - prometheus instrumentation - app_lifespan.add(_prometheus_instrumentation_lifespan) + app_lifespan.add(prometheus_instrumentation_lifespan) app_lifespan.add(_banners_lifespan) diff --git a/services/catalog/src/simcore_service_catalog/repository/events.py b/services/catalog/src/simcore_service_catalog/repository/events.py index fd95bfd40610..af6e77f178b9 100644 --- a/services/catalog/src/simcore_service_catalog/repository/events.py +++ b/services/catalog/src/simcore_service_catalog/repository/events.py @@ -13,11 +13,6 @@ _logger = logging.getLogger(__name__) -repository_lifespan_manager = LifespanManager() -repository_lifespan_manager.add(postgres_database_lifespan) - - -@repository_lifespan_manager.add async def _database_lifespan(app: FastAPI, state: State) -> AsyncIterator[State]: app.state.engine = state[PostgresLifespanState.POSTGRES_ASYNC_ENGINE] @@ -26,3 +21,8 @@ async def _database_lifespan(app: FastAPI, state: State) -> AsyncIterator[State] app.state.default_product_name = await repo.get_default_product_name() yield {} + + +repository_lifespan_manager = LifespanManager() +repository_lifespan_manager.add(postgres_database_lifespan) +repository_lifespan_manager.add(_database_lifespan) diff --git a/services/docker-api-proxy/tests/integration/conftest.py b/services/docker-api-proxy/tests/integration/conftest.py index 0d02392f9172..10878c70d574 100644 --- a/services/docker-api-proxy/tests/integration/conftest.py +++ b/services/docker-api-proxy/tests/integration/conftest.py @@ -6,15 +6,16 @@ import aiodocker import pytest -from asgi_lifespan import LifespanManager +from asgi_lifespan import LifespanManager as ASGILifespanManager from fastapi import FastAPI +from fastapi_lifespan_manager import LifespanManager, State from pydantic import Field from pytest_simcore.helpers.monkeypatch_envs import EnvVarsDict, setenvs_from_dict from servicelib.fastapi.docker import ( - get_lifespan_remote_docker_client, + create_remote_docker_client_input_state, get_remote_docker_client, + remote_docker_client_lifespan, ) -from servicelib.fastapi.lifespan_utils import combine_lifespans from settings_library.application import BaseApplicationSettings from settings_library.docker_api_proxy import DockerApiProxysettings @@ -32,20 +33,29 @@ def pytest_configure(config): config.option.asyncio_mode = "auto" -def _get_test_app() -> FastAPI: - class ApplicationSetting(BaseApplicationSettings): - DOCKER_API_PROXY: Annotated[ - DockerApiProxysettings, - Field(json_schema_extra={"auto_default_from_env": True}), - ] +class ApplicationSetting(BaseApplicationSettings): + DOCKER_API_PROXY: Annotated[ + DockerApiProxysettings, + Field(json_schema_extra={"auto_default_from_env": True}), + ] + + +async def _settings_lifespan(app: FastAPI) -> AsyncIterator[State]: + settings: ApplicationSetting = app.state.settings + + yield { + **create_remote_docker_client_input_state(settings.DOCKER_API_PROXY), + } + +def _get_test_app() -> FastAPI: settings = ApplicationSetting.create_from_envs() - app = FastAPI( - lifespan=combine_lifespans( - get_lifespan_remote_docker_client(settings.DOCKER_API_PROXY) - ) - ) + lifespan_manager = LifespanManager() + lifespan_manager.add(_settings_lifespan) + lifespan_manager.add(remote_docker_client_lifespan) + + app = FastAPI(lifespan=lifespan_manager) app.state.settings = settings return app @@ -61,7 +71,7 @@ async def _(env_vars: EnvVarsDict) -> AsyncIterator[aiodocker.Docker]: app = _get_test_app() - async with LifespanManager(app, startup_timeout=30, shutdown_timeout=30): + async with ASGILifespanManager(app, startup_timeout=30, shutdown_timeout=30): yield get_remote_docker_client(app) return _ diff --git a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/api/rpc/routes.py b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/api/rpc/routes.py index 2a2f4a3afd3f..f313e03aac99 100644 --- a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/api/rpc/routes.py +++ b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/api/rpc/routes.py @@ -13,7 +13,7 @@ ] -async def lifespan_rpc_api_routes(app: FastAPI) -> AsyncIterator[State]: +async def rpc_api_routes_lifespan(app: FastAPI) -> AsyncIterator[State]: rpc_server = get_rabbitmq_rpc_server(app) for router in ROUTERS: await rpc_server.register_router(router, DYNAMIC_SCHEDULER_RPC_NAMESPACE, app) diff --git a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/core/application.py b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/core/application.py index 9502da022fa1..e3996390ebab 100644 --- a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/core/application.py +++ b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/core/application.py @@ -1,70 +1,21 @@ -from collections.abc import AsyncIterator - from fastapi import FastAPI -from fastapi_lifespan_manager import State -from servicelib.fastapi.docker import get_lifespan_remote_docker_client -from servicelib.fastapi.lifespan_utils import LifespanGenerator, combine_lifespans from servicelib.fastapi.openapi import override_fastapi_openapi_method from servicelib.fastapi.profiler import initialize_profiler from servicelib.fastapi.prometheus_instrumentation import ( initialize_prometheus_instrumentation, - lifespan_prometheus_instrumentation, ) from servicelib.fastapi.tracing import initialize_tracing -from .._meta import ( - API_VERSION, - API_VTAG, - APP_FINISHED_BANNER_MSG, - APP_NAME, - APP_STARTED_BANNER_MSG, - PROJECT_NAME, - SUMMARY, -) +from .._meta import API_VERSION, API_VTAG, APP_NAME, PROJECT_NAME, SUMMARY from ..api.frontend import initialize_frontend from ..api.rest.routes import initialize_rest_api -from ..api.rpc.routes import lifespan_rpc_api_routes -from ..services.catalog import lifespan_catalog -from ..services.deferred_manager import lifespan_deferred_manager -from ..services.director_v0 import lifespan_director_v0 -from ..services.director_v2 import lifespan_director_v2 -from ..services.notifier import get_lifespans_notifier -from ..services.rabbitmq import lifespan_rabbitmq -from ..services.redis import lifespan_redis -from ..services.service_tracker import lifespan_service_tracker -from ..services.status_monitor import lifespan_status_monitor +from . import events from .settings import ApplicationSettings -async def _lifespan_banner(app: FastAPI) -> AsyncIterator[State]: - _ = app - print(APP_STARTED_BANNER_MSG, flush=True) # noqa: T201 - yield {} - print(APP_FINISHED_BANNER_MSG, flush=True) # noqa: T201 - - def create_app(settings: ApplicationSettings | None = None) -> FastAPI: app_settings = settings or ApplicationSettings.create_from_envs() - lifespans: list[LifespanGenerator] = [ - lifespan_director_v2, - lifespan_director_v0, - lifespan_catalog, - lifespan_rabbitmq, - lifespan_rpc_api_routes, - lifespan_redis, - *get_lifespans_notifier(), - lifespan_service_tracker, - lifespan_deferred_manager, - lifespan_status_monitor, - get_lifespan_remote_docker_client( - app_settings.DYNAMIC_SCHEDULER_DOCKER_API_PROXY - ), - ] - - if app_settings.DYNAMIC_SCHEDULER_PROMETHEUS_INSTRUMENTATION_ENABLED: - lifespans.append(lifespan_prometheus_instrumentation) - app = FastAPI( title=f"{PROJECT_NAME} web API", description=SUMMARY, @@ -74,7 +25,7 @@ def create_app(settings: ApplicationSettings | None = None) -> FastAPI: "/doc" if app_settings.DYNAMIC_SCHEDULER_SWAGGER_API_DOC_ENABLED else None ), redoc_url=None, - lifespan=combine_lifespans(*lifespans, _lifespan_banner), + lifespan=events.create_app_lifespan(), ) override_fastapi_openapi_method(app) @@ -84,7 +35,8 @@ def create_app(settings: ApplicationSettings | None = None) -> FastAPI: initialize_rest_api(app) - initialize_prometheus_instrumentation(app) + if app_settings.DYNAMIC_SCHEDULER_PROMETHEUS_INSTRUMENTATION_ENABLED: + initialize_prometheus_instrumentation(app) initialize_frontend(app) diff --git a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/core/events.py b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/core/events.py new file mode 100644 index 000000000000..d93bc537c90a --- /dev/null +++ b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/core/events.py @@ -0,0 +1,72 @@ +from collections.abc import AsyncIterator + +from fastapi import FastAPI +from fastapi_lifespan_manager import LifespanManager, State +from servicelib.fastapi.docker import ( + create_remote_docker_client_input_state, + remote_docker_client_lifespan, +) +from servicelib.fastapi.prometheus_instrumentation import ( + create_prometheus_instrumentationmain_input_state, + prometheus_instrumentation_lifespan, +) + +from .._meta import APP_FINISHED_BANNER_MSG, APP_STARTED_BANNER_MSG +from ..api.rpc.routes import rpc_api_routes_lifespan +from ..services.catalog import catalog_lifespan +from ..services.deferred_manager import deferred_manager_lifespan +from ..services.director_v0 import director_v0_lifespan +from ..services.director_v2 import director_v2_lifespan +from ..services.notifier import get_notifier_lifespans +from ..services.rabbitmq import rabbitmq_lifespan +from ..services.redis import redis_lifespan +from ..services.service_tracker import service_tracker_lifespan +from ..services.status_monitor import status_monitor_lifespan +from .settings import ApplicationSettings + + +async def _banner_lifespan(app: FastAPI) -> AsyncIterator[State]: + _ = app + print(APP_STARTED_BANNER_MSG, flush=True) # noqa: T201 + yield {} + print(APP_FINISHED_BANNER_MSG, flush=True) # noqa: T201 + + +async def _settings_lifespan(app: FastAPI) -> AsyncIterator[State]: + settings: ApplicationSettings = app.state.settings + + yield { + **create_prometheus_instrumentationmain_input_state( + enabled=settings.DYNAMIC_SCHEDULER_PROMETHEUS_INSTRUMENTATION_ENABLED + ), + **create_remote_docker_client_input_state( + settings.DYNAMIC_SCHEDULER_DOCKER_API_PROXY + ), + } + + +def create_app_lifespan() -> LifespanManager: + app_lifespan = LifespanManager() + app_lifespan.add(_settings_lifespan) + + app_lifespan.add(director_v2_lifespan) + app_lifespan.add(director_v0_lifespan) + app_lifespan.add(catalog_lifespan) + app_lifespan.add(rabbitmq_lifespan) + app_lifespan.add(rpc_api_routes_lifespan) + app_lifespan.add(redis_lifespan) + + for lifespan in get_notifier_lifespans(): + app_lifespan.add(lifespan) + + app_lifespan.add(service_tracker_lifespan) + app_lifespan.add(deferred_manager_lifespan) + app_lifespan.add(status_monitor_lifespan) + + app_lifespan.add(remote_docker_client_lifespan) + + app_lifespan.add(prometheus_instrumentation_lifespan) + + app_lifespan.add(_banner_lifespan) + + return app_lifespan diff --git a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/catalog/__init__.py b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/catalog/__init__.py index 86e004ee9b06..8cb49b7a1a05 100644 --- a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/catalog/__init__.py +++ b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/catalog/__init__.py @@ -1,7 +1,7 @@ from ._public_client import CatalogPublicClient -from ._setup import lifespan_catalog +from ._setup import catalog_lifespan __all__: tuple[str, ...] = ( "CatalogPublicClient", - "lifespan_catalog", + "catalog_lifespan", ) diff --git a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/catalog/_setup.py b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/catalog/_setup.py index 92d7b7617eb9..40f52050cc98 100644 --- a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/catalog/_setup.py +++ b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/catalog/_setup.py @@ -7,7 +7,7 @@ from ._thin_client import CatalogThinClient -async def lifespan_catalog(app: FastAPI) -> AsyncIterator[State]: +async def catalog_lifespan(app: FastAPI) -> AsyncIterator[State]: thin_client = CatalogThinClient(app) thin_client.set_to_app_state(app) thin_client.attach_lifespan_to(app) diff --git a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/deferred_manager.py b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/deferred_manager.py index 65cf20bd20d3..630a4e12158e 100644 --- a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/deferred_manager.py +++ b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/deferred_manager.py @@ -9,7 +9,7 @@ from .redis import get_redis_client -async def lifespan_deferred_manager(app: FastAPI) -> AsyncIterator[State]: +async def deferred_manager_lifespan(app: FastAPI) -> AsyncIterator[State]: rabbit_settings: RabbitSettings = app.state.settings.DYNAMIC_SCHEDULER_RABBITMQ redis_client_sdk = get_redis_client(app, RedisDatabase.DEFERRED_TASKS) diff --git a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v0/__init__.py b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v0/__init__.py index 85beb7073524..7b5fe80ca950 100644 --- a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v0/__init__.py +++ b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v0/__init__.py @@ -1,7 +1,7 @@ from ._public_client import DirectorV0PublicClient -from ._setup import lifespan_director_v0 +from ._setup import director_v0_lifespan __all__: tuple[str, ...] = ( "DirectorV0PublicClient", - "lifespan_director_v0", + "director_v0_lifespan", ) diff --git a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v0/_setup.py b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v0/_setup.py index 90e48e9b3f50..ccdc96d71c7e 100644 --- a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v0/_setup.py +++ b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v0/_setup.py @@ -7,7 +7,7 @@ from ._thin_client import DirectorV0ThinClient -async def lifespan_director_v0(app: FastAPI) -> AsyncIterator[State]: +async def director_v0_lifespan(app: FastAPI) -> AsyncIterator[State]: thin_client = DirectorV0ThinClient(app) thin_client.set_to_app_state(app) diff --git a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v2/__init__.py b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v2/__init__.py index 25216a03f2f8..424fae9ba1ec 100644 --- a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v2/__init__.py +++ b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v2/__init__.py @@ -1,6 +1,6 @@ -from ._public_client import DirectorV2Client, lifespan_director_v2 +from ._public_client import DirectorV2Client, director_v2_lifespan __all__: tuple[str, ...] = ( "DirectorV2Client", - "lifespan_director_v2", + "director_v2_lifespan", ) diff --git a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v2/_public_client.py b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v2/_public_client.py index c771923cb054..d833d3169bf6 100644 --- a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v2/_public_client.py +++ b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v2/_public_client.py @@ -143,7 +143,7 @@ async def update_projects_networks(self, *, project_id: ProjectID) -> None: await self.thin_client.patch_projects_networks(project_id=project_id) -async def lifespan_director_v2(app: FastAPI) -> AsyncIterator[State]: +async def director_v2_lifespan(app: FastAPI) -> AsyncIterator[State]: public_client = DirectorV2Client(app) public_client.set_to_app_state(app) diff --git a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/notifier/__init__.py b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/notifier/__init__.py index 7daeeb7e2fc0..e5e1609440b4 100644 --- a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/notifier/__init__.py +++ b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/notifier/__init__.py @@ -1,7 +1,7 @@ from ._notifier import notify_service_status_change -from ._setup import get_lifespans_notifier +from ._setup import get_notifier_lifespans __all__: tuple[str, ...] = ( - "get_lifespans_notifier", + "get_notifier_lifespans", "notify_service_status_change", ) diff --git a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/notifier/_setup.py b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/notifier/_setup.py index 5bd140959b2f..d9f9fd813408 100644 --- a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/notifier/_setup.py +++ b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/notifier/_setup.py @@ -1,7 +1,10 @@ -from servicelib.fastapi.lifespan_utils import LifespanGenerator +from collections.abc import AsyncIterator, Callable + +from fastapi import FastAPI +from fastapi_lifespan_manager import State from . import _notifier, _socketio -def get_lifespans_notifier() -> list[LifespanGenerator]: +def get_notifier_lifespans() -> list[Callable[[FastAPI], AsyncIterator[State]]]: return [_socketio.lifespan, _notifier.lifespan] diff --git a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/rabbitmq.py b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/rabbitmq.py index 4f555b8e5f58..c4357bb9439c 100644 --- a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/rabbitmq.py +++ b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/rabbitmq.py @@ -12,7 +12,7 @@ from settings_library.rabbit import RabbitSettings -async def lifespan_rabbitmq(app: FastAPI) -> AsyncIterator[State]: +async def rabbitmq_lifespan(app: FastAPI) -> AsyncIterator[State]: settings: RabbitSettings = app.state.settings.DYNAMIC_SCHEDULER_RABBITMQ await wait_till_rabbitmq_responsive(settings.dsn) diff --git a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/redis.py b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/redis.py index 2640218bee73..a2c72b0bf83e 100644 --- a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/redis.py +++ b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/redis.py @@ -20,7 +20,7 @@ _ALL_REDIS_DATABASES: Final[set[RedisDatabase]] = _DECODE_DBS | _BINARY_DBS -async def lifespan_redis(app: FastAPI) -> AsyncIterator[State]: +async def redis_lifespan(app: FastAPI) -> AsyncIterator[State]: settings: RedisSettings = app.state.settings.DYNAMIC_SCHEDULER_REDIS app.state.redis_clients_manager = manager = RedisClientsManager( diff --git a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/service_tracker/__init__.py b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/service_tracker/__init__.py index 58141505a6de..fee6fc069f35 100644 --- a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/service_tracker/__init__.py +++ b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/service_tracker/__init__.py @@ -13,13 +13,13 @@ should_notify_frontend_for_service, ) from ._models import TrackedServiceModel -from ._setup import lifespan_service_tracker +from ._setup import service_tracker_lifespan __all__: tuple[str, ...] = ( "get_all_tracked_services", "get_tracked_service", "get_user_id_for_service", - "lifespan_service_tracker", + "service_tracker_lifespan", "NORMAL_RATE_POLL_INTERVAL", "remove_tracked_service", "set_frontend_notified_for_service", diff --git a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/service_tracker/_setup.py b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/service_tracker/_setup.py index 45da842e9850..b00a4cb2874e 100644 --- a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/service_tracker/_setup.py +++ b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/service_tracker/_setup.py @@ -8,7 +8,7 @@ from ._tracker import Tracker -async def lifespan_service_tracker(app: FastAPI) -> AsyncIterator[State]: +async def service_tracker_lifespan(app: FastAPI) -> AsyncIterator[State]: app.state.service_tracker = Tracker( get_redis_client(app, RedisDatabase.DYNAMIC_SERVICES) ) diff --git a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/status_monitor/__init__.py b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/status_monitor/__init__.py index 86c116f704d9..c165d51a75b1 100644 --- a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/status_monitor/__init__.py +++ b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/status_monitor/__init__.py @@ -1,3 +1,3 @@ -from ._setup import lifespan_status_monitor +from ._setup import status_monitor_lifespan -__all__: tuple[str, ...] = ("lifespan_status_monitor",) +__all__: tuple[str, ...] = ("status_monitor_lifespan",) diff --git a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/status_monitor/_setup.py b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/status_monitor/_setup.py index 177300d1b83a..e0fad2a09fdd 100644 --- a/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/status_monitor/_setup.py +++ b/services/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/status_monitor/_setup.py @@ -10,7 +10,7 @@ _STATUS_WORKER_DEFAULT_INTERVAL: Final[timedelta] = timedelta(seconds=1) -async def lifespan_status_monitor(app: FastAPI) -> AsyncIterator[State]: +async def status_monitor_lifespan(app: FastAPI) -> AsyncIterator[State]: app.state.status_monitor = monitor = Monitor( app, status_worker_interval=_STATUS_WORKER_DEFAULT_INTERVAL ) diff --git a/services/dynamic-scheduler/tests/conftest.py b/services/dynamic-scheduler/tests/conftest.py index 5b2ed7db3617..7414b8945e28 100644 --- a/services/dynamic-scheduler/tests/conftest.py +++ b/services/dynamic-scheduler/tests/conftest.py @@ -83,38 +83,38 @@ def app_environment( ) -_PATH_APPLICATION: Final[str] = "simcore_service_dynamic_scheduler.core.application" +_PATH_APPLICATION: Final[str] = "simcore_service_dynamic_scheduler.core.events" @pytest.fixture def disable_rabbitmq_lifespan(mocker: MockerFixture) -> None: - mocker.patch(f"{_PATH_APPLICATION}.lifespan_rabbitmq") - mocker.patch(f"{_PATH_APPLICATION}.lifespan_rpc_api_routes") + mocker.patch(f"{_PATH_APPLICATION}.rabbitmq_lifespan") + mocker.patch(f"{_PATH_APPLICATION}.rpc_api_routes_lifespan") @pytest.fixture def disable_redis_lifespan(mocker: MockerFixture) -> None: - mocker.patch(f"{_PATH_APPLICATION}.lifespan_redis") + mocker.patch(f"{_PATH_APPLICATION}.redis_lifespan") @pytest.fixture def disable_service_tracker_lifespan(mocker: MockerFixture) -> None: - mocker.patch(f"{_PATH_APPLICATION}.lifespan_service_tracker") + mocker.patch(f"{_PATH_APPLICATION}.service_tracker_lifespan") @pytest.fixture def disable_deferred_manager_lifespan(mocker: MockerFixture) -> None: - mocker.patch(f"{_PATH_APPLICATION}.lifespan_deferred_manager") + mocker.patch(f"{_PATH_APPLICATION}.deferred_manager_lifespan") @pytest.fixture def disable_notifier_lifespan(mocker: MockerFixture) -> None: - mocker.patch(f"{_PATH_APPLICATION}.get_lifespans_notifier") + mocker.patch(f"{_PATH_APPLICATION}.get_notifier_lifespans") @pytest.fixture def disable_status_monitor_lifespan(mocker: MockerFixture) -> None: - mocker.patch(f"{_PATH_APPLICATION}.lifespan_status_monitor") + mocker.patch(f"{_PATH_APPLICATION}.status_monitor_lifespan") MAX_TIME_FOR_APP_TO_STARTUP: Final[float] = 10