Skip to content

Commit 8607c2e

Browse files
author
Andrei Neagu
committed
Merge remote-tracking branch 'upstream/master' into pr-osparc-migrate-dy-scheduler-part4
2 parents a5beb8a + 407f10e commit 8607c2e

File tree

142 files changed

+730
-528
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

142 files changed

+730
-528
lines changed

.env-devel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ CLUSTERS_KEEPER_COMPUTATIONAL_BACKEND_DEFAULT_CLUSTER_AUTH='{"type":"tls","tls_c
5656
CLUSTERS_KEEPER_COMPUTATIONAL_BACKEND_DOCKER_IMAGE_TAG=master-github-latest
5757
CLUSTERS_KEEPER_DASK_NPROCS=1
5858
CLUSTERS_KEEPER_DASK_NTHREADS=0
59+
CLUSTERS_KEEPER_DASK_NTHREADS_MULTIPLIER=1
5960
CLUSTERS_KEEPER_DASK_WORKER_SATURATION=inf
6061
CLUSTERS_KEEPER_EC2_ACCESS=null
6162
CLUSTERS_KEEPER_SSM_ACCESS=null

.github/instructions/python.instructions.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ Ensure compatibility with the following library versions:
3535

3636
* Use `f-string` formatting for all string interpolation except for logging message strings.
3737
* Use **relative imports** within the same package/module.
38+
- For imports within the same repository/project, always use relative imports (e.g., `from ..constants import APP_SETTINGS_KEY` instead of `from simcore_service_webserver.constants import APP_SETTINGS_KEY`)
39+
- Use absolute imports only for external libraries and packages
3840
* Place **all imports at the top** of the file.
3941
* Document functions when the code is not self-explanatory or if asked explicitly.
4042

@@ -44,6 +46,18 @@ Ensure compatibility with the following library versions:
4446
* Prefer `json_dumps` / `json_loads` from `common_library.json_serialization` instead of the built-in `json.dumps` / `json.loads`.
4547
* When using Pydantic models, prefer methods like `model.model_dump_json()` for serialization.
4648

47-
### 7. **Running tests**
49+
### 7. **aiohttp Framework**
50+
51+
* **Application Keys**: Always use `web.AppKey` for type-safe application storage instead of string keys
52+
- Define keys with specific types: `APP_MY_KEY: Final = web.AppKey("APP_MY_KEY", MySpecificType)`
53+
- Use precise types instead of generic `object` when the actual type is known
54+
- Example: `APP_SETTINGS_KEY: Final = web.AppKey("APP_SETTINGS_KEY", ApplicationSettings)`
55+
- Store and retrieve: `app[APP_MY_KEY] = value` and `data = app[APP_MY_KEY]`
56+
* **Request Keys**: Use `web.AppKey` for request storage as well for consistency and type safety
57+
* **Middleware**: Follow the repository's middleware patterns for cross-cutting concerns
58+
* **Error Handling**: Use the established exception handling decorators and patterns
59+
* **Route Definitions**: Use `web.RouteTableDef()` and organize routes logically within modules
60+
61+
### 8. **Running tests**
4862
* Use `--keep-docker-up` flag when testing to keep docker containers up between sessions.
4963
* Always activate the python virtual environment before running pytest.

packages/service-library/src/servicelib/aiohttp/aiopg_utils.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
1-
""" Holderplace for random helpers using aiopg
1+
"""Holderplace for random helpers using aiopg
22
3-
- Drop here functions/constants that at that time does
4-
not fit in any of the setups. Then, they can be moved and
5-
refactor when new abstractions are used in place.
3+
- Drop here functions/constants that at that time does
4+
not fit in any of the setups. Then, they can be moved and
5+
refactor when new abstractions are used in place.
66
7-
- aiopg is used as a client sdk to interact asynchronously with postgres service
7+
- aiopg is used as a client sdk to interact asynchronously with postgres service
88
9-
SEE for aiopg: https://aiopg.readthedocs.io/en/stable/sa.html
10-
SEE for underlying psycopg: http://initd.org/psycopg/docs/module.html
11-
SEE for extra keywords: https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS
9+
SEE for aiopg: https://aiopg.readthedocs.io/en/stable/sa.html
10+
SEE for underlying psycopg: http://initd.org/psycopg/docs/module.html
11+
SEE for extra keywords: https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS
1212
"""
1313

1414
# TODO: Towards implementing https://github.com/ITISFoundation/osparc-simcore/issues/1195
1515
# TODO: deprecate this module. Move utils into retry_policies, simcore_postgres_database.utils_aiopg
1616

1717
import logging
18+
from typing import Final
1819

1920
import sqlalchemy as sa
2021
from aiohttp import web
@@ -31,6 +32,8 @@
3132

3233
log = logging.getLogger(__name__)
3334

35+
APP_AIOPG_ENGINE_KEY: Final = web.AppKey("APP_AIOPG_ENGINE_KEY", Engine)
36+
3437

3538
async def raise_if_not_responsive(engine: Engine):
3639
async with engine.acquire() as conn:

packages/service-library/src/servicelib/aiohttp/application_keys.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
""" Namespace to keep all application storage keys
1+
"""Namespace to keep all application storage keys
22
33
Unique keys to identify stored data
44
Naming convention accounts for the storage scope: application, request, response, configuration and/or resources
@@ -8,22 +8,25 @@
88
99
See https://aiohttp.readthedocs.io/en/stable/web_advanced.html#data-sharing-aka-no-singletons-please
1010
"""
11+
1112
from typing import Final
1213

13-
# REQUIREMENTS:
14-
# - guarantees all keys are unique
15-
# - one place for all common keys
16-
# - hierarchical classification
14+
from aiohttp import ClientSession, web
15+
16+
# APPLICATION's CONTEXT KEYS
17+
18+
# NOTE: use these keys to store/retrieve data from aiohttp.web.Application
19+
# SEE https://docs.aiohttp.org/en/stable/web_quickstart.html#aiohttp-web-app-key
1720

1821
#
1922
# web.Application keys, i.e. app[APP_*_KEY]
2023
#
21-
APP_CONFIG_KEY: Final[str] = f"{__name__ }.config"
22-
APP_SETTINGS_KEY: Final[str] = f"{__name__ }.settings"
24+
APP_CONFIG_KEY = web.AppKey("APP_CONFIG_KEY", dict[str, object])
2325

2426
APP_AIOPG_ENGINE_KEY: Final[str] = f"{__name__ }.aiopg_engine"
2527

26-
APP_CLIENT_SESSION_KEY: Final[str] = f"{__name__ }.session"
28+
APP_CLIENT_SESSION_KEY: web.AppKey[ClientSession] = web.AppKey("APP_CLIENT_SESSION_KEY")
29+
2730

2831
APP_FIRE_AND_FORGET_TASKS_KEY: Final[str] = f"{__name__}.tasks"
2932

packages/service-library/src/servicelib/aiohttp/application_setup.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616
TypedDict,
1717
)
1818

19-
from .application_keys import APP_CONFIG_KEY, APP_SETTINGS_KEY
19+
from .application_keys import APP_CONFIG_KEY
2020

2121
_logger = logging.getLogger(__name__)
2222

23-
APP_SETUP_COMPLETED_KEY: Final[str] = f"{__name__ }.setup"
23+
APP_SETUP_COMPLETED_KEY: Final[web.AppKey] = web.AppKey("setup_completed", list[str])
2424

2525

2626
class _SetupFunc(Protocol):
@@ -115,13 +115,14 @@ def _get_app_settings_and_field_name(
115115
arg_settings_name: str | None,
116116
setup_func_name: str,
117117
logger: logging.Logger,
118+
app_settings_key: web.AppKey,
118119
) -> tuple[_ApplicationSettings | None, str | None]:
119-
app_settings: _ApplicationSettings | None = app.get(APP_SETTINGS_KEY)
120+
app_settings: _ApplicationSettings | None = app.get(app_settings_key)
120121
settings_field_name = arg_settings_name
121122

122123
if app_settings:
123124
if not settings_field_name:
124-
# FIXME: hard-coded WEBSERVER_ temporary
125+
# NOTE: hard-coded WEBSERVER_ temporary
125126
settings_field_name = f"WEBSERVER_{arg_module_name.split('.')[-1].upper()}"
126127

127128
logger.debug("Checking addon's %s ", f"{settings_field_name=}")
@@ -246,6 +247,7 @@ def app_module_setup(
246247
module_name: str,
247248
category: ModuleCategory,
248249
*,
250+
app_settings_key: web.AppKey,
249251
settings_name: str | None = None,
250252
depends: list[str] | None = None,
251253
logger: logging.Logger = _logger,
@@ -336,6 +338,7 @@ def _wrapper(app: web.Application, *args, **kargs) -> bool:
336338
settings_name,
337339
setup_func.__name__,
338340
logger,
341+
app_settings_key,
339342
)
340343

341344
if (

packages/service-library/src/servicelib/aiohttp/client_session.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from collections.abc import AsyncGenerator
2-
from typing import cast
32

43
from aiohttp import ClientSession, ClientTimeout, web
54
from common_library.json_serialization import json_dumps
@@ -41,10 +40,11 @@ async def persistent_client_session(app: web.Application) -> AsyncGenerator[None
4140
def get_client_session(app: web.Application) -> ClientSession:
4241
"""Refers to the one-and-only client in the app"""
4342
assert APP_CLIENT_SESSION_KEY in app # nosec
44-
return cast(ClientSession, app[APP_CLIENT_SESSION_KEY])
43+
return app[APP_CLIENT_SESSION_KEY]
4544

4645

4746
__all__: tuple[str, ...] = (
47+
"APP_CLIENT_SESSION_KEY",
4848
"get_client_session",
4949
"persistent_client_session",
5050
)

packages/service-library/src/servicelib/aiohttp/docker_utils.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import logging
2+
from typing import Final
23

4+
import aiodocker
35
import aiohttp
6+
from aiohttp import web
47
from models_library.docker import DockerGenericTag
58
from pydantic import TypeAdapter, ValidationError
69
from settings_library.docker_registry import RegistrySettings
@@ -18,6 +21,8 @@
1821

1922
_logger = logging.getLogger(__name__)
2023

24+
APP_DOCKER_ENGINE_KEY: Final = web.AppKey("APP_DOCKER_ENGINE_KEY", aiodocker.Docker)
25+
2126

2227
async def retrieve_image_layer_information(
2328
image: DockerGenericTag, registry_settings: RegistrySettings

packages/service-library/src/servicelib/aiohttp/long_running_tasks/server.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,17 @@
66
running task.
77
"""
88

9+
from typing import Final
10+
11+
from aiohttp import web
12+
913
from ._manager import get_long_running_manager
1014
from ._server import setup, start_long_running_task
1115

16+
APP_LONG_RUNNING_TASKS_KEY: Final = web.AppKey(
17+
"APP_LONG_RUNNING_TASKS_KEY", dict[str, object]
18+
)
19+
1220
__all__: tuple[str, ...] = (
1321
"get_long_running_manager",
1422
"setup",

packages/service-library/src/servicelib/aiohttp/monitor_slow_callbacks.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
import asyncio.events
22
import sys
33
import time
4+
from typing import Final
45

6+
from aiohttp import web
57
from pyinstrument import Profiler
68

79
from .incidents import LimitedOrderedStack, SlowCallback
810

11+
APP_SLOW_CALLBACKS_MONITOR_KEY: Final = web.AppKey(
12+
"APP_SLOW_CALLBACKS_MONITOR_KEY", LimitedOrderedStack[SlowCallback]
13+
)
14+
915

1016
def enable(
1117
slow_duration_secs: float, incidents: LimitedOrderedStack[SlowCallback]

packages/service-library/src/servicelib/aiohttp/monitoring.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
_logger = logging.getLogger(__name__)
2929

3030
_PROMETHEUS_METRICS: Final[str] = f"{__name__}.prometheus_metrics" # noqa: N816
31+
APP_MONITORING_NAMESPACE_KEY: Final = web.AppKey("APP_MONITORING_NAMESPACE_KEY", str)
3132

3233

3334
def get_collector_registry(app: web.Application) -> CollectorRegistry:

0 commit comments

Comments
 (0)