Skip to content

Commit 551822d

Browse files
work
1 parent db71616 commit 551822d

File tree

8 files changed

+345
-35
lines changed

8 files changed

+345
-35
lines changed

api/specs/web-server/_computations.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
from models_library.api_schemas_webserver.computations import (
66
ComputationGet,
77
ComputationPathParams,
8+
ComputationRunPathParams,
89
ComputationRunRestGet,
10+
ComputationRunWithFiltersListQueryParams,
911
ComputationStart,
1012
ComputationStarted,
1113
ComputationTaskRestGet,
@@ -68,7 +70,17 @@ async def stop_computation(_path: Annotated[ComputationPathParams, Depends()]):
6870
response_model=Envelope[list[ComputationRunRestGet]],
6971
)
7072
async def list_computations_latest_iteration(
73+
_query: Annotated[as_query(ComputationRunWithFiltersListQueryParams), Depends()],
74+
): ...
75+
76+
77+
@router.get(
78+
"/computations/{project_id}/iterations",
79+
response_model=Envelope[list[ComputationRunRestGet]],
80+
)
81+
async def list_computation_iterations(
7182
_query: Annotated[as_query(ComputationRunListQueryParams), Depends()],
83+
_path: Annotated[ComputationRunPathParams, Depends()],
7284
): ...
7385

7486

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,10 @@ class ComputationStarted(OutputSchemaWithoutCamelCase):
8181
class ComputationRunListQueryParams(
8282
PageQueryParameters,
8383
ComputationRunListOrderParams, # type: ignore[misc, valid-type]
84-
):
84+
): ...
85+
86+
87+
class ComputationRunWithFiltersListQueryParams(ComputationRunListQueryParams):
8588
filter_only_running: bool = Field(
8689
default=False,
8790
description="If true, only running computations are returned",
@@ -100,6 +103,11 @@ class ComputationRunRestGet(OutputSchema):
100103
project_custom_metadata: dict[str, Any]
101104

102105

106+
class ComputationRunPathParams(BaseModel):
107+
project_id: ProjectID
108+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
109+
110+
103111
### Computation Task
104112

105113

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,34 @@ async def list_computations_latest_iteration_page(
5858
return result
5959

6060

61+
@log_decorator(_logger, level=logging.DEBUG)
62+
async def list_computations_iterations_page(
63+
rabbitmq_rpc_client: RabbitMQRPCClient,
64+
*,
65+
product_name: ProductName,
66+
user_id: UserID,
67+
project_id: ProjectID,
68+
# pagination
69+
offset: int = 0,
70+
limit: int = 20,
71+
# ordering
72+
order_by: OrderBy | None = None,
73+
) -> ComputationRunRpcGetPage:
74+
result = await rabbitmq_rpc_client.request(
75+
DIRECTOR_V2_RPC_NAMESPACE,
76+
_RPC_METHOD_NAME_ADAPTER.validate_python("list_computations_iterations_page"),
77+
product_name=product_name,
78+
user_id=user_id,
79+
project_id=project_id,
80+
offset=offset,
81+
limit=limit,
82+
order_by=order_by,
83+
timeout_s=_DEFAULT_TIMEOUT_S,
84+
)
85+
assert isinstance(result, ComputationRunRpcGetPage) # nosec
86+
return result
87+
88+
6189
@log_decorator(_logger, level=logging.DEBUG)
6290
async def list_computations_latest_iteration_tasks_page(
6391
rabbitmq_rpc_client: RabbitMQRPCClient,

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,36 @@ async def list_computations_latest_iteration_page(
5353
)
5454

5555

56+
@router.expose(reraise_if_error_type=())
57+
async def list_computations_iterations_page(
58+
app: FastAPI,
59+
*,
60+
product_name: ProductName,
61+
user_id: UserID,
62+
project_id: ProjectID,
63+
# pagination
64+
offset: int = 0,
65+
limit: int = 20,
66+
# ordering
67+
order_by: OrderBy | None = None,
68+
) -> ComputationRunRpcGetPage:
69+
comp_runs_repo = CompRunsRepository.instance(db_engine=app.state.engine)
70+
total, comp_runs_output = (
71+
await comp_runs_repo.list_for_user_and_project_all_iterations(
72+
product_name=product_name,
73+
user_id=user_id,
74+
project_id=project_id,
75+
offset=offset,
76+
limit=limit,
77+
order_by=order_by,
78+
)
79+
)
80+
return ComputationRunRpcGetPage(
81+
items=comp_runs_output,
82+
total=total,
83+
)
84+
85+
5686
async def _fetch_task_log(
5787
user_id: UserID, project_id: ProjectID, task: ComputationTaskForRpcDBGet
5888
) -> TaskLogFileGet | None:

services/director-v2/src/simcore_service_director_v2/modules/db/repositories/comp_runs.py

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,16 @@ async def list_(
190190
)
191191
]
192192

193+
_COMPUTATION_RUNS_RPC_GET_COLUMNS = [ # noqa: RUF012
194+
comp_runs.c.project_uuid,
195+
comp_runs.c.iteration,
196+
comp_runs.c.result.label("state"),
197+
comp_runs.c.metadata.label("info"),
198+
comp_runs.c.created.label("submitted_at"),
199+
comp_runs.c.started.label("started_at"),
200+
comp_runs.c.ended.label("ended_at"),
201+
]
202+
193203
async def list_for_user__only_latest_iterations(
194204
self,
195205
*,
@@ -212,13 +222,7 @@ async def list_for_user__only_latest_iterations(
212222
order_by = OrderBy(field=IDStr("run_id")) # default ordering
213223

214224
base_select_query = sa.select(
215-
comp_runs.c.project_uuid,
216-
comp_runs.c.iteration,
217-
comp_runs.c.result.label("state"),
218-
comp_runs.c.metadata.label("info"),
219-
comp_runs.c.created.label("submitted_at"),
220-
comp_runs.c.started.label("started_at"),
221-
comp_runs.c.ended.label("ended_at"),
225+
*self._COMPUTATION_RUNS_RPC_GET_COLUMNS
222226
).select_from(
223227
sa.select(
224228
comp_runs.c.project_uuid,
@@ -286,6 +290,62 @@ async def list_for_user__only_latest_iterations(
286290

287291
return cast(int, total_count), items
288292

293+
async def list_for_user_and_project_all_iterations(
294+
self,
295+
*,
296+
product_name: str,
297+
user_id: UserID,
298+
project_id: ProjectID,
299+
# pagination
300+
offset: int,
301+
limit: int,
302+
# ordering
303+
order_by: OrderBy | None = None,
304+
) -> tuple[int, list[ComputationRunRpcGet]]:
305+
if order_by is None:
306+
order_by = OrderBy(field=IDStr("run_id")) # default ordering
307+
308+
base_select_query = sa.select(
309+
*self._COMPUTATION_RUNS_RPC_GET_COLUMNS,
310+
).where(
311+
(comp_runs.c.user_id == user_id)
312+
& (comp_runs.c.project_uuid == f"{project_id}")
313+
& (
314+
comp_runs.c.metadata["product_name"].astext == product_name
315+
) # <-- NOTE: We might create a separate column for this for fast retrieval
316+
)
317+
318+
# Select total count from base_query
319+
count_query = sa.select(sa.func.count()).select_from(
320+
base_select_query.subquery()
321+
)
322+
323+
# Ordering and pagination
324+
if order_by.direction == OrderDirection.ASC:
325+
list_query = base_select_query.order_by(
326+
sa.asc(getattr(comp_runs.c, order_by.field)), comp_runs.c.run_id
327+
)
328+
else:
329+
list_query = base_select_query.order_by(
330+
desc(getattr(comp_runs.c, order_by.field)), comp_runs.c.run_id
331+
)
332+
list_query = list_query.offset(offset).limit(limit)
333+
334+
async with pass_or_acquire_connection(self.db_engine) as conn:
335+
total_count = await conn.scalar(count_query)
336+
337+
items = [
338+
ComputationRunRpcGet.model_validate(
339+
{
340+
**row,
341+
"state": DB_TO_RUNNING_STATE[row["state"]],
342+
}
343+
)
344+
async for row in await conn.stream(list_query)
345+
]
346+
347+
return cast(int, total_count), items
348+
289349
async def create(
290350
self,
291351
*,

services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2581,6 +2581,51 @@ paths:
25812581
application/json:
25822582
schema:
25832583
$ref: '#/components/schemas/Envelope_list_ComputationRunRestGet__'
2584+
/v0/computations/{project_id}/iterations:
2585+
get:
2586+
tags:
2587+
- computations
2588+
- projects
2589+
summary: List Computation Iterations
2590+
operationId: list_computation_iterations
2591+
parameters:
2592+
- name: project_id
2593+
in: path
2594+
required: true
2595+
schema:
2596+
type: string
2597+
format: uuid
2598+
title: Project Id
2599+
- name: order_by
2600+
in: query
2601+
required: false
2602+
schema:
2603+
type: string
2604+
contentMediaType: application/json
2605+
contentSchema: {}
2606+
default: '{"field":"created","direction":"asc"}'
2607+
title: Order By
2608+
- name: limit
2609+
in: query
2610+
required: false
2611+
schema:
2612+
type: integer
2613+
default: 20
2614+
title: Limit
2615+
- name: offset
2616+
in: query
2617+
required: false
2618+
schema:
2619+
type: integer
2620+
default: 0
2621+
title: Offset
2622+
responses:
2623+
'200':
2624+
description: Successful Response
2625+
content:
2626+
application/json:
2627+
schema:
2628+
$ref: '#/components/schemas/Envelope_list_ComputationRunRestGet__'
25842629
/v0/computations/{project_id}/iterations/latest/tasks:
25852630
get:
25862631
tags:

0 commit comments

Comments
 (0)