Skip to content

Commit 8f4c1b2

Browse files
authored
♻️Computation backend: clean comp_tasks DB (🗃️) (#6968)
1 parent 38866c1 commit 8f4c1b2

File tree

14 files changed

+78
-74
lines changed

14 files changed

+78
-74
lines changed

.codecov.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ flag_management:
1010
statuses:
1111
- type: project
1212
target: auto
13-
threshold: 2%
13+
threshold: 5%
1414
- type: patch
1515
target: auto
16-
threshold: 2%
16+
threshold: 5%
1717

1818

1919
component_management:
@@ -22,7 +22,7 @@ component_management:
2222
statuses:
2323
- type: project
2424
target: auto
25-
threshold: 2%
25+
threshold: 5%
2626
branches:
2727
- "!master"
2828
individual_components:
@@ -116,12 +116,12 @@ coverage:
116116
project:
117117
default:
118118
informational: true
119-
threshold: 2%
119+
threshold: 5%
120120

121121
patch:
122122
default:
123123
informational: true
124-
threshold: 2%
124+
threshold: 5%
125125

126126
comment:
127127
layout: "header,diff,flags,components,footer"

packages/postgres-database/requirements/_test.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
--constraint _migration.txt
1111

1212
aiopg[sa]
13+
arrow
1314
coverage
1415
faker
1516
pytest

packages/postgres-database/requirements/_test.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
aiopg==1.4.0
22
# via -r requirements/_test.in
3+
arrow==1.3.0
4+
# via -r requirements/_test.in
35
async-timeout==4.0.3
46
# via
57
# -c requirements/_base.txt
@@ -52,7 +54,9 @@ pytest-instafail==0.5.0
5254
pytest-runner==6.0.1
5355
# via -r requirements/_test.in
5456
python-dateutil==2.9.0.post0
55-
# via faker
57+
# via
58+
# arrow
59+
# faker
5660
pyyaml==6.0.2
5761
# via
5862
# -c requirements/../../../requirements/constraints.txt
@@ -72,6 +76,8 @@ types-docker==7.1.0.20240827
7276
# via -r requirements/_test.in
7377
types-psycopg2==2.9.21.20241019
7478
# via -r requirements/_test.in
79+
types-python-dateutil==2.9.0.20241206
80+
# via arrow
7581
types-requests==2.32.0.20241016
7682
# via types-docker
7783
typing-extensions==4.12.2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""remove submit timestamp
2+
3+
Revision ID: 52a0e8148dd5
4+
Revises: 77ac824a77ff
5+
Create Date: 2024-12-16 14:55:15.114923+00:00
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
from sqlalchemy.dialects import postgresql
11+
12+
# revision identifiers, used by Alembic.
13+
revision = '52a0e8148dd5'
14+
down_revision = '77ac824a77ff'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
op.drop_column('comp_tasks', 'submit')
22+
# ### end Alembic commands ###
23+
24+
25+
def downgrade():
26+
# ### commands auto generated by Alembic - please adjust! ###
27+
op.add_column('comp_tasks', sa.Column('submit', postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=True))
28+
# ### end Alembic commands ###

packages/postgres-database/src/simcore_postgres_database/models/comp_tasks.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,6 @@ class NodeClass(enum.Enum):
7777
nullable=True,
7878
doc="current progress of the task if available",
7979
),
80-
# utc timestamps for submission/start/end
81-
sa.Column(
82-
"submit", sa.DateTime(timezone=True), doc="UTC timestamp for task submission"
83-
),
8480
sa.Column(
8581
"start", sa.DateTime(timezone=True), doc="UTC timestamp when task started"
8682
),

packages/pytest-simcore/src/pytest_simcore/helpers/faker_factories.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@
1616
import json
1717
import random
1818
from collections.abc import Callable
19-
from datetime import datetime, timedelta, timezone
19+
from datetime import UTC, datetime, timedelta
2020
from typing import Any, Final
2121
from uuid import uuid4
2222

23+
import arrow
2324
import faker
2425
from faker import Faker
2526

@@ -182,7 +183,7 @@ def fake_task_factory(first_internal_id=1) -> Callable:
182183
_index_in_sequence = itertools.count(start=first_internal_id)
183184

184185
def fake_task(**overrides) -> dict[str, Any]:
185-
t0 = datetime.utcnow()
186+
t0 = arrow.utcnow().datetime
186187
data = {
187188
"project_id": uuid4(),
188189
"node_id": uuid4(),
@@ -193,7 +194,6 @@ def fake_task(**overrides) -> dict[str, Any]:
193194
"outputs": json.dumps({}),
194195
"image": json.dumps({}),
195196
"state": random.choice(_get_comp_pipeline_test_states()),
196-
"submit": t0,
197197
"start": t0 + timedelta(seconds=1),
198198
"end": t0 + timedelta(minutes=5),
199199
}
@@ -251,7 +251,7 @@ def random_product(
251251

252252

253253
def utcnow() -> datetime:
254-
return datetime.now(tz=timezone.utc)
254+
return datetime.now(tz=UTC)
255255

256256

257257
def random_payment_method(

services/director-v2/src/simcore_service_director_v2/api/routes/computations.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
""" CRUD operations on a "computation" resource
1+
"""CRUD operations on a "computation" resource
22
33
A computation is a resource that represents a running pipeline of computational services in a give project
44
Therefore,
@@ -15,7 +15,6 @@
1515
# pylint: disable=too-many-arguments
1616
# pylint: disable=too-many-statements
1717

18-
1918
import contextlib
2019
import logging
2120
from typing import Annotated, Any, Final
@@ -75,7 +74,6 @@
7574
compute_pipeline_details,
7675
compute_pipeline_started_timestamp,
7776
compute_pipeline_stopped_timestamp,
78-
compute_pipeline_submitted_timestamp,
7977
create_complete_dag,
8078
create_complete_dag_from_tasks,
8179
create_minimal_computational_graph_based_on_selection,
@@ -396,9 +394,7 @@ async def create_computation( # noqa: PLR0913 # pylint: disable=too-many-positi
396394
stopped=compute_pipeline_stopped_timestamp(
397395
minimal_computational_dag, comp_tasks
398396
),
399-
submitted=compute_pipeline_submitted_timestamp(
400-
minimal_computational_dag, comp_tasks
401-
),
397+
submitted=last_run.created if last_run else None,
402398
)
403399

404400
except ProjectNotFoundError as e:
@@ -498,7 +494,7 @@ async def get_computation(
498494
result=None,
499495
started=compute_pipeline_started_timestamp(pipeline_dag, all_tasks),
500496
stopped=compute_pipeline_stopped_timestamp(pipeline_dag, all_tasks),
501-
submitted=compute_pipeline_submitted_timestamp(pipeline_dag, all_tasks),
497+
submitted=last_run.created if last_run else None,
502498
)
503499

504500

@@ -572,7 +568,7 @@ async def stop_computation(
572568
result=None,
573569
started=compute_pipeline_started_timestamp(pipeline_dag, tasks),
574570
stopped=compute_pipeline_stopped_timestamp(pipeline_dag, tasks),
575-
submitted=compute_pipeline_submitted_timestamp(pipeline_dag, tasks),
571+
submitted=last_run.created if last_run else None,
576572
)
577573

578574
except ProjectNotFoundError as e:

services/director-v2/src/simcore_service_director_v2/models/comp_tasks.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ class CompTaskAtDB(BaseModel):
128128
description="the hex digest of the resolved inputs +outputs hash at the time when the last outputs were generated",
129129
)
130130
image: Image
131-
submit: dt.datetime
132131
start: dt.datetime | None = None
133132
end: dt.datetime | None = None
134133
state: RunningState
@@ -163,7 +162,7 @@ def _convert_state_from_state_type_enum_if_needed(cls, v):
163162
return RunningState(DB_TO_RUNNING_STATE[StateType(v)])
164163
return v
165164

166-
@field_validator("start", "end", "submit")
165+
@field_validator("start", "end")
167166
@classmethod
168167
def _ensure_utc(cls, v: dt.datetime | None) -> dt.datetime | None:
169168
if v is not None and v.tzinfo is None:
@@ -228,7 +227,6 @@ def to_db_model(self, **exclusion_rules) -> dict[str, Any]:
228227
}
229228
},
230229
"image": image_example,
231-
"submit": "2021-03-01 13:07:34.19161",
232230
"node_class": "INTERACTIVE",
233231
"state": "NOT_STARTED",
234232
"progress": 0.44,

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

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,12 @@ async def _get_node_infos(
145145
None,
146146
)
147147

148-
result: tuple[ServiceMetaDataPublished, ServiceExtras, SimcoreServiceLabels] = (
149-
await asyncio.gather(
150-
_get_service_details(catalog_client, user_id, product_name, node),
151-
director_client.get_service_extras(node.key, node.version),
152-
director_client.get_service_labels(node),
153-
)
148+
result: tuple[
149+
ServiceMetaDataPublished, ServiceExtras, SimcoreServiceLabels
150+
] = await asyncio.gather(
151+
_get_service_details(catalog_client, user_id, product_name, node),
152+
director_client.get_service_extras(node.key, node.version),
153+
director_client.get_service_labels(node),
154154
)
155155
return result
156156

@@ -246,9 +246,9 @@ async def _get_pricing_and_hardware_infos(
246246
return pricing_info, hardware_info
247247

248248

249-
_RAM_SAFE_MARGIN_RATIO: Final[float] = (
250-
0.1 # NOTE: machines always have less available RAM than advertised
251-
)
249+
_RAM_SAFE_MARGIN_RATIO: Final[
250+
float
251+
] = 0.1 # NOTE: machines always have less available RAM than advertised
252252
_CPUS_SAFE_MARGIN: Final[float] = 0.1
253253

254254

@@ -266,11 +266,11 @@ async def _update_project_node_resources_from_hardware_info(
266266
if not hardware_info.aws_ec2_instances:
267267
return
268268
try:
269-
unordered_list_ec2_instance_types: list[EC2InstanceTypeGet] = (
270-
await get_instance_type_details(
271-
rabbitmq_rpc_client,
272-
instance_type_names=set(hardware_info.aws_ec2_instances),
273-
)
269+
unordered_list_ec2_instance_types: list[
270+
EC2InstanceTypeGet
271+
] = await get_instance_type_details(
272+
rabbitmq_rpc_client,
273+
instance_type_names=set(hardware_info.aws_ec2_instances),
274274
)
275275

276276
assert unordered_list_ec2_instance_types # nosec
@@ -439,7 +439,6 @@ async def generate_tasks_list_from_project(
439439
inputs=node.inputs,
440440
outputs=node.outputs,
441441
image=image,
442-
submit=arrow.utcnow().datetime,
443442
state=task_state,
444443
internal_id=internal_id,
445444
node_class=to_node_class(node.key),

services/director-v2/src/simcore_service_director_v2/utils/dags.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -217,17 +217,6 @@ def compute_pipeline_stopped_timestamp(
217217
return pipeline_stopped_at
218218

219219

220-
def compute_pipeline_submitted_timestamp(
221-
pipeline_dag: nx.DiGraph, comp_tasks: list[CompTaskAtDB]
222-
) -> datetime.datetime | None:
223-
if not pipeline_dag.nodes:
224-
return None
225-
node_id_to_comp_task: dict[NodeIDStr, CompTaskAtDB] = {
226-
NodeIDStr(f"{task.node_id}"): task for task in comp_tasks
227-
}
228-
return max(node_id_to_comp_task[node_id].submit for node_id in pipeline_dag.nodes)
229-
230-
231220
async def compute_pipeline_details(
232221
complete_dag: nx.DiGraph, pipeline_dag: nx.DiGraph, comp_tasks: list[CompTaskAtDB]
233222
) -> PipelineDetails:

services/director-v2/tests/mocks/fake_task.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
"requires_gpu": false,
5151
"requires_mpi": true
5252
},
53-
"submit": "1994-11-10T19:23:02.115Z",
5453
"state": "PUBLISHED",
5554
"internal_id": 21107840,
5655
"node_class": "COMPUTATIONAL",

services/director-v2/tests/unit/test_utils_dags.py

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -485,9 +485,8 @@ def pipeline_test_params(
485485
state=RunningState.NOT_STARTED,
486486
internal_id=3,
487487
node_class=NodeClass.COMPUTATIONAL,
488-
submit=datetime.datetime.now(tz=datetime.timezone.utc),
489-
created=datetime.datetime.now(tz=datetime.timezone.utc),
490-
modified=datetime.datetime.now(tz=datetime.timezone.utc),
488+
created=datetime.datetime.now(tz=datetime.UTC),
489+
modified=datetime.datetime.now(tz=datetime.UTC),
491490
last_heartbeat=None,
492491
progress=1.00,
493492
)
@@ -536,9 +535,8 @@ def pipeline_test_params(
536535
state=RunningState.NOT_STARTED,
537536
internal_id=3,
538537
node_class=NodeClass.COMPUTATIONAL,
539-
submit=datetime.datetime.now(tz=datetime.timezone.utc),
540-
created=datetime.datetime.now(tz=datetime.timezone.utc),
541-
modified=datetime.datetime.now(tz=datetime.timezone.utc),
538+
created=datetime.datetime.now(tz=datetime.UTC),
539+
modified=datetime.datetime.now(tz=datetime.UTC),
542540
last_heartbeat=None,
543541
),
544542
CompTaskAtDB.model_construct(
@@ -550,9 +548,8 @@ def pipeline_test_params(
550548
state=RunningState.NOT_STARTED,
551549
internal_id=3,
552550
node_class=NodeClass.COMPUTATIONAL,
553-
submit=datetime.datetime.now(tz=datetime.timezone.utc),
554-
created=datetime.datetime.now(tz=datetime.timezone.utc),
555-
modified=datetime.datetime.now(tz=datetime.timezone.utc),
551+
created=datetime.datetime.now(tz=datetime.UTC),
552+
modified=datetime.datetime.now(tz=datetime.UTC),
556553
last_heartbeat=None,
557554
),
558555
CompTaskAtDB.model_construct(
@@ -564,9 +561,8 @@ def pipeline_test_params(
564561
state=RunningState.NOT_STARTED,
565562
internal_id=3,
566563
node_class=NodeClass.COMPUTATIONAL,
567-
submit=datetime.datetime.now(tz=datetime.timezone.utc),
568-
created=datetime.datetime.now(tz=datetime.timezone.utc),
569-
modified=datetime.datetime.now(tz=datetime.timezone.utc),
564+
created=datetime.datetime.now(tz=datetime.UTC),
565+
modified=datetime.datetime.now(tz=datetime.UTC),
570566
last_heartbeat=None,
571567
progress=1.00,
572568
),

services/director-v2/tests/unit/with_dbs/comp_scheduler/test_api_route_computations.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,11 @@ def _mocked_services_details(
258258
).isoformat()
259259
}
260260

261-
data = {**ServiceGet.model_config["json_schema_extra"]["examples"][0], **data_published, **deprecated} # type: ignore
261+
data = {
262+
**ServiceGet.model_config["json_schema_extra"]["examples"][0],
263+
**data_published,
264+
**deprecated,
265+
} # type: ignore
262266

263267
payload = ServiceGet.model_validate(data)
264268

@@ -354,7 +358,6 @@ def _mocked_get_pricing_unit(request, pricing_plan_id: int) -> httpx.Response:
354358
assert_all_called=False,
355359
assert_all_mocked=True,
356360
) as respx_mock:
357-
358361
respx_mock.get(
359362
re.compile(
360363
r"services/(?P<service_key>simcore/services/(comp|dynamic|frontend)/[^/]+)/(?P<service_version>[^\.]+.[^\.]+.[^/\?]+)/pricing-plan.+"
@@ -915,13 +918,7 @@ async def test_get_computation_from_not_started_computation_task(
915918
stopped=None,
916919
submitted=None,
917920
)
918-
_CHANGED_FIELDS = {"submitted"}
919-
assert returned_computation.model_dump(
920-
exclude=_CHANGED_FIELDS
921-
) == expected_computation.model_dump(exclude=_CHANGED_FIELDS)
922-
assert returned_computation.model_dump(
923-
include=_CHANGED_FIELDS
924-
) != expected_computation.model_dump(include=_CHANGED_FIELDS)
921+
assert returned_computation == expected_computation
925922

926923

927924
async def test_get_computation_from_published_computation_task(

0 commit comments

Comments
 (0)