-
Notifications
You must be signed in to change notification settings - Fork 30
✨ Adding director-v0 client to dynamic-scheduler #7001
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
GitHK
merged 21 commits into
ITISFoundation:master
from
GitHK:pr-osparc-add-director-v0-client
Jan 17, 2025
Merged
Changes from 11 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
2586ec8
removed unused
48c3b2b
remove redundant
9940bc6
Merge remote-tracking branch 'upstream/master' into pr-osparc-add-dir…
658c69d
added director-v0 client to dynamic-scheduler
21d89d7
Merge remote-tracking branch 'upstream/master' into pr-osparc-add-dir…
5dfe516
remove comments
2d28557
mypy
77aa41f
refactor
0ed3f04
Merge remote-tracking branch 'upstream/master' into pr-osparc-add-dir…
c450bfc
added tracing
7f4770d
refactor setup and optional values
a32a9e2
removed unused
f8ed436
Merge remote-tracking branch 'upstream/master' into pr-osparc-add-dir…
c3fd2de
unify naming
91b2683
Merge remote-tracking branch 'upstream/master' into pr-osparc-add-dir…
c5e9951
fixed
7118a6a
Merge remote-tracking branch 'upstream/master' into pr-osparc-add-dir…
e83cbb8
removed unused
8a07cd5
pylint
a6b2bf9
Merge branch 'master' into pr-osparc-add-director-v0-client
GitHK 9b13d07
Merge branch 'master' into pr-osparc-add-director-v0-client
GitHK 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
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
25 changes: 25 additions & 0 deletions
25
packages/settings-library/src/settings_library/director_v0.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,25 @@ | ||
from functools import cached_property | ||
|
||
from pydantic import AnyHttpUrl, Field, TypeAdapter | ||
from settings_library.base import BaseCustomSettings | ||
from settings_library.basic_types import PortInt, VersionTag | ||
|
||
|
||
class DirectorV0Settings(BaseCustomSettings): | ||
DIRECTOR_V0_ENABLED: bool = True | ||
|
||
DIRECTOR_HOST: str = "director" | ||
DIRECTOR_PORT: PortInt = TypeAdapter(PortInt).validate_python(8000) | ||
DIRECTOR_V0_VTAG: VersionTag = Field( | ||
default="v0", description="Director-v0 service API's version tag" | ||
) | ||
|
||
@cached_property | ||
def endpoint(self) -> str: | ||
url = AnyHttpUrl.build( # pylint: disable=no-member | ||
scheme="http", | ||
host=self.DIRECTOR_HOST, | ||
port=self.DIRECTOR_PORT, | ||
path=f"{self.DIRECTOR_V0_VTAG}", | ||
) | ||
return f"{url}" |
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
7 changes: 7 additions & 0 deletions
7
.../dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v0/__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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
from ._public_client import DirectorV0PublicClient | ||
from ._setup import setup_director_v0 | ||
|
||
__all__: tuple[str, ...] = ( | ||
"DirectorV0PublicClient", | ||
"setup_director_v0", | ||
) |
71 changes: 71 additions & 0 deletions
71
...ic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v0/_public_client.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,71 @@ | ||
import logging | ||
from typing import Any, cast | ||
|
||
import httpx | ||
from fastapi import FastAPI | ||
from models_library.api_schemas_directorv2.dynamic_services_service import ( | ||
RunningDynamicServiceDetails, | ||
) | ||
from models_library.projects import ProjectID | ||
from models_library.projects_nodes_io import NodeID | ||
from models_library.service_settings_labels import SimcoreServiceLabels | ||
from models_library.services_base import ServiceKeyVersion | ||
from models_library.users import UserID | ||
from pydantic import TypeAdapter | ||
from servicelib.fastapi.app_state import SingletonInAppStateMixin | ||
|
||
from ._thin_client import DirectorV0ThinClient | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def _unenvelope_or_raise_error(resp: httpx.Response) -> dict | list: | ||
""" | ||
Director responses are enveloped | ||
If successful response, we un-envelop it and return data as a dict | ||
If error, is detected raise an ValueError | ||
""" | ||
body = resp.json() | ||
if "data" in body: | ||
return body["data"] # type: ignore[no-any-return] | ||
|
||
msg = f"Unexpected, data was not returned: {body=}" | ||
raise ValueError(msg) | ||
|
||
|
||
class DirectorV0PublicClient(SingletonInAppStateMixin): | ||
app_state_name: str = "director_v0_public_client" | ||
|
||
def __init__(self, app: FastAPI) -> None: | ||
self.app = app | ||
|
||
async def get_running_service_details( | ||
self, node_id: NodeID | ||
) -> RunningDynamicServiceDetails: | ||
response = await DirectorV0ThinClient.get_from_app_state( | ||
self.app | ||
).get_running_interactive_service_details(node_id) | ||
return TypeAdapter(RunningDynamicServiceDetails).validate_python( | ||
_unenvelope_or_raise_error(response) | ||
) | ||
|
||
async def get_service_labels( # required | ||
self, service: ServiceKeyVersion | ||
) -> SimcoreServiceLabels: | ||
response = await DirectorV0ThinClient.get_from_app_state( | ||
self.app | ||
).get_services_labels(service) | ||
return TypeAdapter(SimcoreServiceLabels).validate_python( | ||
_unenvelope_or_raise_error(response) | ||
) | ||
|
||
async def get_running_services( # required | ||
self, user_id: UserID | None = None, project_id: ProjectID | None = None | ||
) -> list[RunningDynamicServiceDetails]: | ||
response = await DirectorV0ThinClient.get_from_app_state( | ||
self.app | ||
).get_running_interactive_services(user_id=user_id, project_id=project_id) | ||
return [ | ||
RunningDynamicServiceDetails(**x) | ||
for x in cast(list[dict[str, Any]], _unenvelope_or_raise_error(response)) | ||
] |
21 changes: 21 additions & 0 deletions
21
...es/dynamic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v0/_setup.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,21 @@ | ||
from fastapi import FastAPI | ||
|
||
from ._public_client import DirectorV0PublicClient | ||
from ._thin_client import DirectorV0ThinClient | ||
|
||
|
||
def setup_director_v0(app: FastAPI) -> None: | ||
async def _on_startup() -> None: | ||
thin_client = DirectorV0ThinClient(app) | ||
thin_client.set_to_app_state(app) | ||
thin_client.attach_lifespan_to(app) | ||
|
||
public_client = DirectorV0PublicClient(app) | ||
public_client.set_to_app_state(app) | ||
|
||
async def _on_shutdown() -> None: | ||
DirectorV0PublicClient.pop_from_app_state(app) | ||
DirectorV0ThinClient.pop_from_app_state(app) | ||
|
||
app.add_event_handler("startup", _on_startup) | ||
app.add_event_handler("shutdown", _on_shutdown) |
67 changes: 67 additions & 0 deletions
67
...amic-scheduler/src/simcore_service_dynamic_scheduler/services/director_v0/_thin_client.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,67 @@ | ||
import urllib.parse | ||
|
||
from common_library.unset import as_dict_exclude_none | ||
from fastapi import FastAPI, status | ||
from httpx import Response | ||
from models_library.projects import ProjectID | ||
from models_library.projects_nodes_io import NodeID | ||
from models_library.services_base import ServiceKeyVersion | ||
from models_library.users import UserID | ||
from servicelib.fastapi.app_state import SingletonInAppStateMixin | ||
from servicelib.fastapi.http_client import AttachLifespanMixin | ||
from servicelib.fastapi.http_client_thin import ( | ||
BaseThinClient, | ||
expect_status, | ||
retry_on_errors, | ||
) | ||
from yarl import URL | ||
|
||
from ...core.settings import ApplicationSettings | ||
|
||
|
||
class DirectorV0ThinClient( | ||
SingletonInAppStateMixin, BaseThinClient, AttachLifespanMixin | ||
): | ||
app_state_name: str = "director_v0_thin_client" | ||
|
||
def __init__(self, app: FastAPI) -> None: | ||
settings: ApplicationSettings = app.state.settings | ||
assert settings.CLIENT_REQUEST.HTTP_CLIENT_REQUEST_TOTAL_TIMEOUT # nosec | ||
|
||
super().__init__( | ||
total_retry_interval=int( | ||
settings.CLIENT_REQUEST.HTTP_CLIENT_REQUEST_TOTAL_TIMEOUT | ||
), | ||
extra_allowed_method_names={ | ||
"attach_lifespan_to", | ||
"get_from_app_state", | ||
"pop_from_app_state", | ||
"set_to_app_state", | ||
}, | ||
base_url=settings.DYNAMIC_SCHEDULER_DIRECTOR_V0_SETTINGS.endpoint, | ||
tracing_settings=settings.DYNAMIC_SCHEDULER_TRACING, | ||
) | ||
|
||
@retry_on_errors() | ||
@expect_status(status.HTTP_200_OK) | ||
async def get_running_interactive_service_details( | ||
self, node_id: NodeID | ||
) -> Response: | ||
return await self.client.get(f"/running_interactive_services/{node_id}") | ||
|
||
@retry_on_errors() | ||
@expect_status(status.HTTP_200_OK) | ||
async def get_services_labels(self, service: ServiceKeyVersion) -> Response: | ||
GitHK marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return await self.client.get( | ||
f"/services/{urllib.parse.quote_plus(service.key)}/{service.version}/labels" | ||
) | ||
|
||
@retry_on_errors() | ||
@expect_status(status.HTTP_200_OK) | ||
async def get_running_interactive_services( | ||
self, user_id: UserID | None, project_id: ProjectID | None | ||
) -> Response: | ||
request_url = URL("/running_interactive_services").with_query( | ||
as_dict_exclude_none(user_id=user_id, study_id=project_id) | ||
) | ||
return await self.client.get(f"{request_url}") |
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
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.