Skip to content

Commit d37dd0c

Browse files
committed
stop services
1 parent 2a7611f commit d37dd0c

File tree

3 files changed

+66
-24
lines changed

3 files changed

+66
-24
lines changed

services/web/server/src/simcore_service_webserver/projects/_projects_db.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,7 @@ async def patch_project(
172172
*,
173173
project_uuid: ProjectID,
174174
new_partial_project_data: dict,
175-
) -> None:
176-
175+
) -> ProjectDBGet:
177176
async with transaction_context(get_asyncpg_engine(app), connection) as conn:
178177
result = await conn.stream(
179178
projects.update()
@@ -182,10 +181,12 @@ async def patch_project(
182181
last_change_date=sql.func.now(),
183182
)
184183
.where(projects.c.uuid == f"{project_uuid}")
184+
.returning(*PROJECT_DB_COLS)
185185
)
186186
row = await result.one_or_none()
187187
if row is None:
188188
raise ProjectNotFoundError(project_uuid=project_uuid)
189+
return ProjectDBGet.model_validate(row)
189190

190191

191192
async def delete_project(
Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,91 @@
1-
# NOTE: should replace _crud_api_delete.py:delete_project
2-
1+
import asyncio
32
import logging
4-
from typing import Protocol
3+
import time
4+
from contextlib import contextmanager
5+
from typing import Any, Protocol
56

67
from aiohttp import web
78
from models_library.projects import ProjectID
9+
from models_library.users import UserID
10+
from servicelib.common_headers import UNDEFINED_DEFAULT_SIMCORE_USER_AGENT_VALUE
811
from servicelib.redis._errors import ProjectLockError
912
from simcore_service_director_v2.core.errors import ProjectNotFoundError
1013
from simcore_service_webserver.projects.exceptions import ProjectDeleteError
1114

15+
from ..director_v2 import api as director_v2_service
1216
from . import _projects_db as _projects_repository
17+
from . import projects_service
1318

1419
_logger = logging.getLogger(__name__)
1520

1621

22+
@contextmanager
23+
def _monitor_step(steps: dict[str, Any], *, name: str, elapsed: bool = False):
24+
# util
25+
start_time = time.perf_counter()
26+
steps[name] = {"status": "starting"}
27+
try:
28+
yield
29+
except Exception as e:
30+
steps[name]["status"] = "failed"
31+
steps[name]["exception"] = str(e)
32+
raise
33+
else:
34+
steps[name]["status"] = "success"
35+
finally:
36+
if elapsed:
37+
steps[name]["elapsed"] = time.perf_counter() - start_time
38+
39+
1740
class StopServicesCallback(Protocol):
1841
async def __call__(self, app: web.Application, project_uuid: ProjectID) -> None:
1942
...
2043

2144

45+
async def batch_stop_services_in_project(
46+
app: web.Application, *, user_id: UserID, project_uuid: ProjectID
47+
) -> None:
48+
await asyncio.gather(
49+
director_v2_service.stop_pipeline(
50+
app, user_id=user_id, project_id=project_uuid
51+
),
52+
projects_service.remove_project_dynamic_services(
53+
user_id=user_id,
54+
project_uuid=f"{project_uuid}",
55+
app=app,
56+
simcore_user_agent=UNDEFINED_DEFAULT_SIMCORE_USER_AGENT_VALUE,
57+
notify_users=False,
58+
),
59+
)
60+
61+
2262
async def delete_project_as_admin(
2363
app: web.Application,
2464
*,
2565
project_uuid: ProjectID,
26-
stop_project_services_as_admin: StopServicesCallback | None,
2766
):
28-
hidden = False
29-
stopped = not stop_project_services_as_admin
30-
deleted = False
67+
68+
state: dict[str, Any] = {}
3169

3270
try:
33-
# hide
34-
await _projects_repository.patch_project(
35-
app,
36-
project_uuid=project_uuid,
37-
new_partial_project_data={"hidden": True},
38-
)
39-
hidden = True
71+
# 1. hide
72+
with _monitor_step(state, name="hide"):
73+
project = await _projects_repository.patch_project(
74+
app,
75+
project_uuid=project_uuid,
76+
new_partial_project_data={"hidden": True},
77+
)
4078

41-
if stop_project_services_as_admin:
79+
# 2. stop
80+
with _monitor_step(state, name="stop", elapsed=True):
4281
# NOTE: this callback could take long or raise whatever!
43-
await stop_project_services_as_admin(app, project_uuid)
44-
stopped = True
82+
await batch_stop_services_in_project(
83+
app, user_id=project.prj_owner, project_uuid=project_uuid
84+
)
4585

46-
await _projects_repository.delete_project(app, project_uuid=project_uuid)
47-
deleted = True
86+
# 3. delete
87+
with _monitor_step(state, name="delete"):
88+
await _projects_repository.delete_project(app, project_uuid=project_uuid)
4889

4990
except ProjectNotFoundError as err:
5091
_logger.debug(
@@ -62,5 +103,6 @@ async def delete_project_as_admin(
62103
except Exception as err:
63104
raise ProjectDeleteError(
64105
project_uuid=project_uuid,
65-
reason=f"Unexpected error. Deletion sequence: {hidden=}, {stopped=}, {deleted=} ",
106+
reason=f"Unexpected error. Deletion sequence: {state=}",
107+
state=state,
66108
) from err

services/web/server/src/simcore_service_webserver/projects/_trash_service.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ async def trash_project(
7676
if force_stop_first:
7777

7878
async def _schedule():
79+
# TODO: use batch_stop_services_in_project instead. Change mocks!
7980
await asyncio.gather(
8081
director_v2_api.stop_pipeline(
8182
app, user_id=user_id, project_id=project_id
@@ -275,8 +276,6 @@ async def batch_delete_trashed_projects_as_admin(
275276
await _projects_service_delete.delete_project_as_admin(
276277
app,
277278
project_uuid=project.uuid,
278-
# FIXME: trashed project does not have services running?
279-
stop_project_services_as_admin=None,
280279
)
281280
deleted_project_ids.append(project.uuid)
282281
except Exception as err: # pylint: disable=broad-exception-caught

0 commit comments

Comments
 (0)