Skip to content

Commit 961ad38

Browse files
🎨 Introduce grouping multiple jobs in task manager (Multiport simulation use case) (🗃️) (#8025)
1 parent 00b3d1d commit 961ad38

File tree

65 files changed

+2866
-118
lines changed

Some content is hidden

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

65 files changed

+2866
-118
lines changed

api/specs/web-server/_computations.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
from fastapi import APIRouter, Depends, status
55
from fastapi_pagination import Page
66
from models_library.api_schemas_webserver.computations import (
7+
ComputationCollectionRunListQueryParams,
8+
ComputationCollectionRunPathParams,
9+
ComputationCollectionRunTaskListQueryParams,
710
ComputationGet,
811
ComputationPathParams,
912
ComputationRunIterationsLatestListQueryParams,
@@ -95,3 +98,22 @@ async def list_computations_latest_iteration_tasks(
9598
_query: Annotated[as_query(ComputationTaskListQueryParams), Depends()],
9699
_path: Annotated[ComputationTaskPathParams, Depends()],
97100
): ...
101+
102+
103+
@router.get(
104+
"/computation-collection-runs",
105+
response_model=Page[ComputationTaskRestGet],
106+
)
107+
async def list_computation_collection_runs(
108+
_query: Annotated[as_query(ComputationCollectionRunListQueryParams), Depends()],
109+
): ...
110+
111+
112+
@router.get(
113+
"/computation-collection-runs/{collection_run_id}/tasks",
114+
response_model=Page[ComputationTaskRestGet],
115+
)
116+
async def list_computation_collection_run_tasks(
117+
_query: Annotated[as_query(ComputationCollectionRunTaskListQueryParams), Depends()],
118+
_path: Annotated[ComputationCollectionRunPathParams, Depends()],
119+
): ...

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

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from datetime import datetime
22
from typing import Any, NamedTuple
33

4+
from models_library.computations import CollectionRunID
45
from models_library.services_types import ServiceRunID
56
from pydantic import (
67
AnyUrl,
@@ -63,6 +64,55 @@ class ComputationRunRpcGetPage(NamedTuple):
6364
total: PositiveInt
6465

6566

67+
class ComputationCollectionRunRpcGet(BaseModel):
68+
collection_run_id: CollectionRunID
69+
project_ids: list[str]
70+
state: RunningState
71+
info: dict[str, Any]
72+
submitted_at: datetime
73+
started_at: datetime | None
74+
ended_at: datetime | None
75+
76+
model_config = ConfigDict(
77+
json_schema_extra={
78+
"examples": [
79+
{
80+
"collection_run_id": "12e0c8b2-bad6-40fb-9948-8dec4f65d4d9",
81+
"project_ids": ["beb16d18-d57d-44aa-a638-9727fa4a72ef"],
82+
"state": "SUCCESS",
83+
"info": {
84+
"wallet_id": 9866,
85+
"user_email": "[email protected]",
86+
"wallet_name": "test",
87+
"product_name": "osparc",
88+
"project_name": "test",
89+
"project_metadata": {
90+
"parent_node_id": "12e0c8b2-bad6-40fb-9948-8dec4f65d4d9",
91+
"parent_node_name": "UJyfwFVYySnPCaLuQIaz",
92+
"parent_project_id": "beb16d18-d57d-44aa-a638-9727fa4a72ef",
93+
"parent_project_name": "qTjDmYPxeqAWfCKCQCYF",
94+
"root_parent_node_id": "37176e84-d977-4993-bc49-d76fcfc6e625",
95+
"root_parent_node_name": "UEXExIZVPeFzGRmMglPr",
96+
"root_parent_project_id": "beb16d18-d57d-44aa-a638-9727fa4a72ef",
97+
"root_parent_project_name": "FuDpjjFIyeNTWRUWCuKo",
98+
},
99+
"node_id_names_map": {},
100+
"simcore_user_agent": "agent",
101+
},
102+
"submitted_at": "2023-01-11 13:11:47.293595",
103+
"started_at": "2023-01-11 13:11:47.293595",
104+
"ended_at": "2023-01-11 13:11:47.293595",
105+
}
106+
]
107+
}
108+
)
109+
110+
111+
class ComputationCollectionRunRpcGetPage(NamedTuple):
112+
items: list[ComputationCollectionRunRpcGet]
113+
total: PositiveInt
114+
115+
66116
class ComputationTaskRpcGet(BaseModel):
67117
project_uuid: ProjectID
68118
node_id: NodeID
@@ -100,3 +150,42 @@ class ComputationTaskRpcGet(BaseModel):
100150
class ComputationTaskRpcGetPage(NamedTuple):
101151
items: list[ComputationTaskRpcGet]
102152
total: PositiveInt
153+
154+
155+
class ComputationCollectionRunTaskRpcGet(BaseModel):
156+
project_uuid: ProjectID
157+
node_id: NodeID
158+
state: RunningState
159+
progress: float
160+
image: dict[str, Any]
161+
started_at: datetime | None
162+
ended_at: datetime | None
163+
log_download_link: AnyUrl | None
164+
service_run_id: ServiceRunID
165+
166+
model_config = ConfigDict(
167+
json_schema_extra={
168+
"examples": [
169+
{
170+
"project_uuid": "beb16d18-d57d-44aa-a638-9727fa4a72ef",
171+
"node_id": "12e0c8b2-bad6-40fb-9948-8dec4f65d4d9",
172+
"state": "SUCCESS",
173+
"progress": 0.0,
174+
"image": {
175+
"name": "simcore/services/comp/ti-solutions-optimizer",
176+
"tag": "1.0.19",
177+
"node_requirements": {"CPU": 8.0, "RAM": 25769803776},
178+
},
179+
"started_at": "2023-01-11 13:11:47.293595",
180+
"ended_at": "2023-01-11 13:11:47.293595",
181+
"log_download_link": "https://example.com/logs",
182+
"service_run_id": "comp_1_12e0c8b2-bad6-40fb-9948-8dec4f65d4d9_1",
183+
}
184+
]
185+
}
186+
)
187+
188+
189+
class ComputationCollectionRunTaskRpcGetPage(NamedTuple):
190+
items: list[ComputationCollectionRunTaskRpcGet]
191+
total: PositiveInt

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

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

3+
from models_library.computations import CollectionRunID
34
from pydantic import (
45
AnyHttpUrl,
56
AnyUrl,
@@ -72,6 +73,12 @@ class ComputationCreate(BaseModel):
7273
description="contains information about the wallet used to bill the running service"
7374
),
7475
] = None
76+
collection_run_id: Annotated[
77+
CollectionRunID | None,
78+
Field(
79+
description="In case start_pipeline is True, this is the collection run id to which the comp run belongs."
80+
),
81+
] = None
7582

7683
@field_validator("product_name")
7784
@classmethod
@@ -83,6 +90,20 @@ def _ensure_product_name_defined_if_computation_starts(
8390
raise ValueError(msg)
8491
return v
8592

93+
@field_validator("collection_run_id")
94+
@classmethod
95+
def _ensure_collection_run_id_dependency_on_start_pipeline(
96+
cls, v, info: ValidationInfo
97+
):
98+
start_pipeline = info.data.get("start_pipeline")
99+
if start_pipeline and v is None:
100+
msg = "collection_run_id must be provided when start_pipeline is True!"
101+
raise ValueError(msg)
102+
if not start_pipeline and v is not None:
103+
msg = "collection_run_id must be None when start_pipeline is False!"
104+
raise ValueError(msg)
105+
return v
106+
86107

87108
class ComputationStop(BaseModel):
88109
user_id: UserID

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

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,20 @@
88
BaseModel,
99
ConfigDict,
1010
Field,
11+
field_validator,
1112
)
1213

1314
from ..api_schemas_directorv2.computations import (
1415
ComputationGet as _DirectorV2ComputationGet,
1516
)
1617
from ..basic_types import IDStr
18+
from ..computations import CollectionRunID
1719
from ..projects import CommitID, ProjectID
1820
from ..projects_nodes_io import NodeID
1921
from ..projects_state import RunningState
2022
from ..rest_ordering import OrderBy, create_ordering_query_model_class
2123
from ..rest_pagination import PageQueryParameters
24+
from ..utils.common_validators import null_or_none_str_to_none_validator
2225
from ._base import (
2326
InputSchemaWithoutCamelCase,
2427
OutputSchema,
@@ -153,3 +156,54 @@ class ComputationTaskRestGet(OutputSchema):
153156
log_download_link: AnyUrl | None
154157
node_name: str
155158
osparc_credits: Decimal | None
159+
160+
161+
### Computation Collection Run
162+
163+
164+
class ComputationCollectionRunListQueryParams(
165+
PageQueryParameters,
166+
):
167+
filter_only_running: Annotated[
168+
bool, Field(description="If true, only running collection runs are returned")
169+
] = False
170+
171+
filter_by_root_project_id: ProjectID | None = None
172+
173+
_null_or_none_to_none = field_validator("filter_by_root_project_id", mode="before")(
174+
null_or_none_str_to_none_validator
175+
)
176+
177+
178+
class ComputationCollectionRunRestGet(OutputSchema):
179+
collection_run_id: CollectionRunID
180+
project_ids: list[str]
181+
state: RunningState
182+
info: dict[str, Any]
183+
submitted_at: datetime
184+
started_at: datetime | None
185+
ended_at: datetime | None
186+
name: str
187+
188+
189+
class ComputationCollectionRunPathParams(BaseModel):
190+
collection_run_id: CollectionRunID
191+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
192+
193+
194+
class ComputationCollectionRunTaskListQueryParams(
195+
PageQueryParameters,
196+
): ...
197+
198+
199+
class ComputationCollectionRunTaskRestGet(OutputSchema):
200+
project_uuid: ProjectID
201+
node_id: NodeID
202+
state: RunningState
203+
progress: float
204+
image: dict[str, Any]
205+
started_at: datetime | None
206+
ended_at: datetime | None
207+
log_download_link: AnyUrl | None
208+
osparc_credits: Decimal | None
209+
name: str

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

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from datetime import datetime
22
from decimal import Decimal
3-
from typing import Any
3+
from typing import Any, TypeAlias
4+
from uuid import UUID
45

56
from pydantic import AnyUrl, BaseModel
67

@@ -36,3 +37,34 @@ class ComputationRunWithAttributes(BaseModel):
3637
# Attributes added by the webserver
3738
root_project_name: str
3839
project_custom_metadata: dict[str, Any]
40+
41+
42+
CollectionRunID: TypeAlias = UUID
43+
44+
45+
class ComputationCollectionRunWithAttributes(BaseModel):
46+
collection_run_id: CollectionRunID
47+
project_ids: list[str]
48+
state: RunningState
49+
info: dict[str, Any]
50+
submitted_at: datetime
51+
started_at: datetime | None
52+
ended_at: datetime | None
53+
54+
# Attributes added by the webserver
55+
name: str # Either root project name or collection name if provided by the client on start
56+
57+
58+
class ComputationCollectionRunTaskWithAttributes(BaseModel):
59+
project_uuid: ProjectID
60+
node_id: NodeID
61+
state: RunningState
62+
progress: float
63+
image: dict[str, Any]
64+
started_at: datetime | None
65+
ended_at: datetime | None
66+
log_download_link: AnyUrl | None
67+
68+
# Attributes added by the webserver
69+
name: str # Either node name or job name if provided by the client on start
70+
osparc_credits: Decimal | None

packages/models-library/src/models_library/projects_state.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,32 @@ class RunningState(str, Enum):
2222
"""State of execution of a project's computational workflow
2323
2424
SEE StateType for task state
25+
26+
# Computational backend states explained:
27+
- UNKNOWN - The backend doesn't know about the task anymore, it has disappeared from the system or it was never created (eg. when we are asking for the task)
28+
- NOT_STARTED - Default state when the task is created
29+
- PUBLISHED - The task has been submitted to the computational backend (click on "Run" button in the UI)
30+
- PENDING - Task has been transferred to the Dask scheduler and is waiting for a worker to pick it up (director-v2 --> Dask scheduler)
31+
- But! it is also transition state (ex. PENDING -> WAITING_FOR_CLUSTER -> PENDING -> WAITING_FOR_RESOURCES -> PENDING -> STARTED)
32+
- WAITING_FOR_CLUSTER - No cluster (Dask scheduler) is available to run the task; waiting for one to become available
33+
- WAITING_FOR_RESOURCES - No worker (Dask worker) is available to run the task; waiting for one to become available
34+
- STARTED - A worker has picked up the task and is executing it
35+
- SUCCESS - Task finished successfully
36+
- FAILED - Task finished with an error
37+
- ABORTED - Task was aborted before completion
38+
2539
"""
2640

2741
UNKNOWN = "UNKNOWN"
28-
PUBLISHED = "PUBLISHED"
2942
NOT_STARTED = "NOT_STARTED"
43+
PUBLISHED = "PUBLISHED"
3044
PENDING = "PENDING"
45+
WAITING_FOR_CLUSTER = "WAITING_FOR_CLUSTER"
3146
WAITING_FOR_RESOURCES = "WAITING_FOR_RESOURCES"
3247
STARTED = "STARTED"
3348
SUCCESS = "SUCCESS"
3449
FAILED = "FAILED"
3550
ABORTED = "ABORTED"
36-
WAITING_FOR_CLUSTER = "WAITING_FOR_CLUSTER"
3751

3852
@staticmethod
3953
def list_running_states() -> list["RunningState"]:

0 commit comments

Comments
 (0)