Skip to content

Commit dc77030

Browse files
intro
1 parent b4ffe76 commit dc77030

File tree

28 files changed

+838
-49
lines changed

28 files changed

+838
-49
lines changed

api/specs/web-server/_computations.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import Annotated
22

3+
from _common import as_query
34
from fastapi import APIRouter, Depends, status
45
from models_library.api_schemas_webserver.computations import (
56
ComputationGet,
@@ -9,6 +10,11 @@
910
)
1011
from models_library.generics import Envelope
1112
from simcore_service_webserver._meta import API_VTAG
13+
from simcore_service_webserver.director_v2._computations_rest_schema import (
14+
ComputationRunListQueryParams,
15+
ComputationTaskListQueryParams,
16+
ComputationTaskPathParams,
17+
)
1218

1319
router = APIRouter(
1420
prefix=f"/{API_VTAG}",
@@ -53,3 +59,26 @@ async def start_computation(
5359
status_code=status.HTTP_204_NO_CONTENT,
5460
)
5561
async def stop_computation(_path: Annotated[ComputationPathParams, Depends()]): ...
62+
63+
64+
@router.get(
65+
"/computations/-/iterations/latest",
66+
response_model=Envelope[list[ComputationGet]],
67+
name="list_computations_latest_iteration",
68+
description="Lists the latest iteration of computations",
69+
)
70+
async def list_computations_latest_iteration(
71+
_query: Annotated[as_query(ComputationRunListQueryParams), Depends()],
72+
): ...
73+
74+
75+
@router.get(
76+
"/computations/{project_id}/iterations/latest/tasks",
77+
response_model=Envelope[list[ComputationGet]],
78+
name="list_computations_latest_iteration_tasks",
79+
description="Lists the latest iteration tasks for a computation",
80+
)
81+
async def list_computations_latest_iteration_tasks(
82+
_query: Annotated[as_query(ComputationTaskListQueryParams), Depends()],
83+
_path: Annotated[ComputationTaskPathParams, Depends()],
84+
): ...

packages/models-library/src/models_library/api_schemas_directorv2/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
1+
from typing import Final
2+
3+
from pydantic import TypeAdapter
4+
5+
from ..rabbitmq_basic_types import RPCNamespace
16
from . import clusters, dynamic_services
27

38
assert clusters # nosec
49
assert dynamic_services # nosec
510

11+
12+
DIRECTOR_V2_RPC_NAMESPACE: Final[RPCNamespace] = TypeAdapter(
13+
RPCNamespace
14+
).validate_python("director-v2")
15+
16+
617
__all__: tuple[str, ...] = (
718
"clusters",
819
"dynamic_services",
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from datetime import datetime
2+
from typing import Any, NamedTuple
3+
4+
from pydantic import (
5+
BaseModel,
6+
PositiveInt,
7+
)
8+
9+
from ..projects import ProjectID
10+
from ..projects_nodes_io import NodeID
11+
from ..projects_state import RunningState
12+
13+
14+
class ComputationRunRpcGet(BaseModel):
15+
project_uuid: ProjectID
16+
iteration: int
17+
state: RunningState
18+
info: dict[str, Any]
19+
submitted_at: datetime
20+
started_at: datetime | None
21+
ended_at: datetime | None
22+
23+
24+
class ComputationRunRpcGetPage(NamedTuple):
25+
items: list[ComputationRunRpcGet]
26+
total: PositiveInt
27+
28+
29+
class ComputationTaskRpcGet(BaseModel):
30+
project_uuid: ProjectID
31+
node_id: NodeID
32+
state: RunningState
33+
progress: float
34+
image: dict[str, Any]
35+
started_at: datetime | None
36+
ended_at: datetime | None
37+
38+
39+
class ComputationTaskRpcGetPage(NamedTuple):
40+
items: list[ComputationTaskRpcGet]
41+
total: PositiveInt

packages/models-library/src/models_library/api_schemas_webserver/computations.py

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
from typing import Annotated
1+
from datetime import datetime
2+
from typing import Annotated, Any, NamedTuple
23

34
from common_library.basic_types import DEFAULT_FACTORY
4-
from pydantic import BaseModel, Field
5+
from pydantic import (
6+
BaseModel,
7+
Field,
8+
PositiveInt,
9+
)
510

611
from ..api_schemas_directorv2.computations import (
712
ComputationGet as _DirectorV2ComputationGet,
813
)
914
from ..projects import CommitID, ProjectID
15+
from ..projects_nodes_io import NodeID
16+
from ..projects_state import RunningState
1017
from ._base import InputSchemaWithoutCamelCase, OutputSchemaWithoutCamelCase
1118

1219

@@ -41,3 +48,33 @@ class ComputationStarted(OutputSchemaWithoutCamelCase):
4148
json_schema_extra={"default": []},
4249
),
4350
] = DEFAULT_FACTORY
51+
52+
53+
class ComputationRunRestGet(BaseModel):
54+
project_uuid: ProjectID
55+
iteration: int
56+
state: RunningState
57+
info: dict[str, Any]
58+
submitted_at: datetime
59+
started_at: datetime | None
60+
ended_at: datetime | None
61+
62+
63+
class ComputationRunRestGetPage(NamedTuple):
64+
items: list[ComputationRunRestGet]
65+
total: PositiveInt
66+
67+
68+
class ComputationTaskRestGet(BaseModel):
69+
project_uuid: ProjectID
70+
node_id: NodeID
71+
state: RunningState
72+
progress: float
73+
image: dict[str, Any]
74+
started_at: datetime | None
75+
ended_at: datetime | None
76+
77+
78+
class ComputationTaskRestGetPage(NamedTuple):
79+
items: list[ComputationTaskRestGet]
80+
total: PositiveInt

packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/director_v2/__init__.py

Whitespace-only changes.
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# pylint: disable=too-many-arguments
2+
import logging
3+
from typing import Final
4+
5+
from models_library.api_schemas_directorv2 import (
6+
DIRECTOR_V2_RPC_NAMESPACE,
7+
)
8+
from models_library.api_schemas_directorv2.comp_runs import (
9+
ComputationRunRpcGetPage,
10+
ComputationTaskRpcGetPage,
11+
)
12+
from models_library.products import ProductName
13+
from models_library.projects import ProjectID
14+
from models_library.rabbitmq_basic_types import RPCMethodName
15+
from models_library.rest_ordering import OrderBy
16+
from models_library.users import UserID
17+
from pydantic import NonNegativeInt, TypeAdapter
18+
19+
from ....logging_utils import log_decorator
20+
from ... import RabbitMQRPCClient
21+
22+
_logger = logging.getLogger(__name__)
23+
24+
25+
_DEFAULT_TIMEOUT_S: Final[NonNegativeInt] = 20
26+
27+
_RPC_METHOD_NAME_ADAPTER: TypeAdapter[RPCMethodName] = TypeAdapter(RPCMethodName)
28+
29+
30+
@log_decorator(_logger, level=logging.DEBUG)
31+
async def list_computations_latest_iteration_page(
32+
rabbitmq_rpc_client: RabbitMQRPCClient,
33+
*,
34+
product_name: ProductName,
35+
user_id: UserID,
36+
# pagination
37+
offset: int = 0,
38+
limit: int = 20,
39+
# ordering
40+
order_by: OrderBy | None = None,
41+
) -> ComputationRunRpcGetPage:
42+
result = await rabbitmq_rpc_client.request(
43+
DIRECTOR_V2_RPC_NAMESPACE,
44+
_RPC_METHOD_NAME_ADAPTER.validate_python(
45+
"list_computations_latest_iteration_page"
46+
),
47+
product_name=product_name,
48+
user_id=user_id,
49+
offset=offset,
50+
limit=limit,
51+
order_by=order_by,
52+
timeout_s=_DEFAULT_TIMEOUT_S,
53+
)
54+
assert isinstance(result, ComputationRunRpcGetPage) # nosec
55+
return result
56+
57+
58+
@log_decorator(_logger, level=logging.DEBUG)
59+
async def list_computations_latest_iteration_tasks_page(
60+
rabbitmq_rpc_client: RabbitMQRPCClient,
61+
*,
62+
product_name: ProductName,
63+
user_id: UserID,
64+
project_id: ProjectID,
65+
# pagination
66+
offset: int = 0,
67+
limit: int = 20,
68+
# ordering
69+
order_by: OrderBy | None = None,
70+
) -> ComputationTaskRpcGetPage:
71+
result = await rabbitmq_rpc_client.request(
72+
DIRECTOR_V2_RPC_NAMESPACE,
73+
_RPC_METHOD_NAME_ADAPTER.validate_python(
74+
"list_computations_latest_iteration_tasks_page"
75+
),
76+
product_name=product_name,
77+
user_id=user_id,
78+
project_id=project_id,
79+
offset=offset,
80+
limit=limit,
81+
order_by=order_by,
82+
timeout_s=_DEFAULT_TIMEOUT_S,
83+
)
84+
assert isinstance(result, ComputationTaskRpcGetPage) # nosec
85+
return result

services/director-v2/src/simcore_service_director_v2/api/dependencies/database.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from typing import TypeVar, cast
44

55
from aiopg.sa import Engine
6-
from fastapi import Depends
6+
from fastapi import Depends, FastAPI
77
from fastapi.requests import Request
88

99
from ...modules.db.repositories import BaseRepository
@@ -47,3 +47,11 @@ async def _get_repo(
4747
yield get_base_repository(engine=engine, repo_type=repo_type)
4848

4949
return _get_repo
50+
51+
52+
def get_repository_instance(app: FastAPI, repo_type: type[RepoType]) -> RepoType:
53+
"""
54+
Retrieves an instance of the specified repository type using the database engine from the FastAPI app.
55+
"""
56+
engine = cast(Engine, app.state.engine)
57+
return get_base_repository(engine=engine, repo_type=repo_type)

services/director-v2/src/simcore_service_director_v2/api/rpc/__init__.py

Whitespace-only changes.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# pylint: disable=too-many-arguments
2+
from fastapi import FastAPI
3+
from models_library.api_schemas_directorv2.comp_runs import (
4+
ComputationRunRpcGetPage,
5+
ComputationTaskRpcGetPage,
6+
)
7+
from models_library.products import ProductName
8+
from models_library.projects import ProjectID
9+
from models_library.rest_ordering import OrderBy
10+
from models_library.users import UserID
11+
from servicelib.rabbitmq import RPCRouter
12+
13+
from ...modules.db.repositories.comp_runs import CompRunsRepository
14+
from ...modules.db.repositories.comp_tasks import CompTasksRepository
15+
from ..dependencies.database import get_repository_instance
16+
17+
router = RPCRouter()
18+
19+
20+
@router.expose(reraise_if_error_type=())
21+
async def list_computations_latest_iteration_page(
22+
app: FastAPI,
23+
*,
24+
product_name: ProductName,
25+
user_id: UserID,
26+
# pagination
27+
offset: int = 0,
28+
limit: int = 20,
29+
# ordering
30+
order_by: OrderBy | None = None,
31+
) -> ComputationRunRpcGetPage:
32+
comp_runs_repo = get_repository_instance(app, CompRunsRepository)
33+
total, comp_runs = await comp_runs_repo.list_for_user__only_latest_iterations(
34+
product_name=product_name,
35+
user_id=user_id,
36+
offset=offset,
37+
limit=limit,
38+
order_by=order_by,
39+
)
40+
return ComputationRunRpcGetPage(
41+
items=comp_runs,
42+
total=total,
43+
)
44+
45+
46+
@router.expose(reraise_if_error_type=())
47+
async def list_computations_latest_iteration_tasks_page(
48+
app: FastAPI,
49+
*,
50+
product_name: ProductName,
51+
user_id: UserID,
52+
project_id: ProjectID,
53+
# pagination
54+
offset: int = 0,
55+
limit: int = 20,
56+
# ordering
57+
order_by: OrderBy | None = None,
58+
) -> ComputationTaskRpcGetPage:
59+
assert product_name # nosec NOTE: Whether project_id belong to the product_name was checked in the webserver
60+
assert user_id # nosec NOTE: Whether user_id has access to the project was checked in the webserver
61+
62+
comp_tasks_repo = get_repository_instance(app, CompTasksRepository)
63+
total, comp_runs = (
64+
await comp_tasks_repo.list_computational_tasks_for_frontend_client(
65+
project_id=project_id,
66+
offset=offset,
67+
limit=limit,
68+
order_by=order_by,
69+
)
70+
)
71+
return ComputationTaskRpcGetPage(
72+
items=comp_runs,
73+
total=total,
74+
)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import logging
2+
3+
from fastapi import FastAPI
4+
from models_library.api_schemas_directorv2 import (
5+
DIRECTOR_V2_RPC_NAMESPACE,
6+
)
7+
from servicelib.logging_utils import log_context
8+
from servicelib.rabbitmq import RPCRouter
9+
10+
from ...modules.rabbitmq import get_rabbitmq_rpc_server
11+
from . import (
12+
_computations,
13+
)
14+
15+
_logger = logging.getLogger(__name__)
16+
17+
18+
ROUTERS: list[RPCRouter] = [
19+
_computations.router,
20+
]
21+
22+
23+
def setup_rpc_api_routes(app: FastAPI) -> None:
24+
async def startup() -> None:
25+
with log_context(
26+
_logger,
27+
logging.INFO,
28+
msg="Director-v2 startup RPC API Routes",
29+
):
30+
rpc_server = get_rabbitmq_rpc_server(app)
31+
for router in ROUTERS:
32+
await rpc_server.register_router(router, DIRECTOR_V2_RPC_NAMESPACE, app)
33+
34+
app.add_event_handler("startup", startup)

0 commit comments

Comments
 (0)