Skip to content

Commit

Permalink
fixes and annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
pcrespov committed Apr 9, 2022
1 parent 803ad2f commit 3db6293
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
"""

import asyncio
import functools
import logging
from typing import Callable, List
from uuid import UUID

from aiohttp import web
from models_library.projects import ProjectID
Expand Down Expand Up @@ -39,13 +37,13 @@ async def mark_project_as_deleted(app: web.Application, project_uuid: ProjectID)
# TODO: note that if any of the steps below fail, it might results in a
# services/projects/data that might be incosistent. The GC should
# be able to detect that and resolve it.
await db.set_hidden_flag(f"{project_uuid}", enabled=True)
await db.set_hidden_flag(project_uuid, enabled=True)


async def delete_project(
app: web.Application,
project_uuid: str,
user_id: int,
project_uuid: ProjectID,
user_id: UserID,
# TODO: this function was tmp added here to avoid refactoring all projects_api in a single PR
remove_project_dynamic_services: Callable,
) -> None:
Expand All @@ -64,7 +62,7 @@ async def delete_project(
db: ProjectDBAPI = app[APP_PROJECT_DBAPI]

try:
mark_project_as_deleted(app, project_uuid)
await mark_project_as_deleted(app, project_uuid)

# stops dynamic services
# - raises ProjectNotFoundError, UserNotFoundError, ProjectLockError
Expand All @@ -74,13 +72,13 @@ async def delete_project(

# stops computational services
# - raises DirectorServiceError
await director_v2_api.delete_pipeline(app, user_id, UUID(project_uuid))
await director_v2_api.delete_pipeline(app, user_id, project_uuid)

# rm data from storage
await delete_data_folders_of_project(app, project_uuid, user_id)

# rm project from database
await db.delete_user_project(user_id, project_uuid)
await db.delete_user_project(user_id, f"{project_uuid}")

except ProjectLockError as err:
raise ProjectDeleteError(
Expand All @@ -95,8 +93,8 @@ async def delete_project(

def create_delete_project_background_task(
app: web.Application,
project_uuid: str,
user_id: int,
project_uuid: ProjectID,
user_id: UserID,
remove_project_dynamic_services: Callable,
logger: logging.Logger,
) -> asyncio.Task:
Expand All @@ -122,7 +120,7 @@ def _log_errors(fut: asyncio.Future):
project_uuid, user_id
)

task.add_done_callback(functools.partial(_log_errors, log))
task.add_done_callback(_log_errors)
return task


Expand All @@ -143,8 +141,3 @@ def is_delete_project_background_task_running(
tasks = get_delete_project_background_tasks(project_uuid, user_id)
assert len(tasks) <= 1 # nosec
return len(tasks) > 0


# alias
create_background_task = create_delete_project_background_task
is_background_task_running = is_delete_project_background_task_running
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from uuid import UUID, uuid4

from aiohttp import web
from models_library.projects import ProjectID
from models_library.projects_state import (
Owner,
ProjectLocked,
Expand All @@ -26,6 +27,7 @@
ProjectStatus,
RunningState,
)
from models_library.users import UserID
from pydantic.types import PositiveInt
from servicelib.aiohttp.application_keys import APP_JSONSCHEMA_SPECS_KEY
from servicelib.aiohttp.jsonschema_validation import validate_instance
Expand Down Expand Up @@ -186,8 +188,13 @@ async def start_project_interactive_services(
log.error("Error while starting dynamic service %s", f"{entry=}")


async def delete_project(app: web.Application, project_uuid: str, user_id: int) -> None:
async def delete_project(
app: web.Application, project_uuid: ProjectID, user_id: UserID
) -> asyncio.Task:
"""
Returns the background task to delete project using user permissions. If the
task is already running, it returns existing task otherwise it creates a new one.
The returned task can be ignored to implement a fire&forget or followed up with add_done_callback
raises ProjectDeleteError
"""
Expand All @@ -197,15 +204,17 @@ async def delete_project(app: web.Application, project_uuid: str, user_id: int)
except ProjectNotFoundError as err:
raise ProjectDeleteError(project_uuid, reason=f"Invalid project {err}") from err

# If you have multiple tasks deleting the same project then one will atmost succeed and
# the rest always fail (because the project is deleted).
in_progress: bool = _delete.is_background_task_running(project_uuid, user_id)
# Ensures
tasks: List[asyncio.Task] = _delete.get_delete_project_background_tasks(
project_uuid, user_id
)
assert len(tasks) <= 1, f"{tasks=}" # nosec
if tasks:
return tasks[0]

# This avoids having a burst of background tasks that were fire&forget failing
if not in_progress:
await _delete.create_background_task(
app, project_uuid, user_id, remove_project_dynamic_services, log
)
return await _delete.create_delete_project_background_task(
app, project_uuid, user_id, remove_project_dynamic_services, log
)


@observe(event="SIGNAL_USER_DISCONNECTED")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from aiopg.sa.connection import SAConnection
from aiopg.sa.result import RowProxy
from change_case import ChangeCase
from models_library.projects import ProjectAtDB, ProjectIDStr
from models_library.projects import ProjectAtDB, ProjectID, ProjectIDStr
from pydantic import ValidationError
from pydantic.types import PositiveInt
from servicelib.aiohttp.application_keys import APP_DB_ENGINE_KEY
Expand Down Expand Up @@ -864,12 +864,12 @@ async def update_project_without_checking_permissions(
)
return result.rowcount == 1

async def set_hidden_flag(self, project_uuid: str, enabled: bool):
async def set_hidden_flag(self, project_uuid: ProjectID, enabled: bool):
async with self.engine.acquire() as conn:
stmt = (
projects.update()
.values(hidden=enabled)
.where(projects.c.uuid == project_uuid)
.where(projects.c.uuid == f"{project_uuid}")
)
await conn.execute(stmt)

Expand Down

0 comments on commit 3db6293

Please sign in to comment.