Merge pull request #17390 from davelopez/cancel_deleted_user_jobs

Cancel all active jobs when the user is deleted
This commit is contained in:
Marius van den Beek
2024-02-02 11:01:28 +01:00
committed by GitHub
2 changed files with 61 additions and 1 deletions
+16
View File
@@ -40,6 +40,7 @@ from galaxy.managers import (
)
from galaxy.managers.base import combine_lists
from galaxy.model import (
Job,
User,
UserAddress,
UserQuotaUsage,
@@ -161,6 +162,21 @@ class UserManager(base.ModelManager, deletable.PurgableManagerMixin):
"The configuration of this Galaxy instance does not allow admins to delete users."
)
super().delete(user, flush=flush)
self._stop_all_jobs_from_user(user)
def _stop_all_jobs_from_user(self, user):
active_jobs = self._get_all_active_jobs_from_user(user)
session = self.session()
for job in active_jobs:
job.mark_deleted(self.app.config.track_jobs_in_database)
with transaction(session):
session.commit()
def _get_all_active_jobs_from_user(self, user: User) -> List[Job]:
"""Get all jobs that are not ready yet and belong to the given user."""
stmt = select(Job).where(and_(Job.user_id == user.id, Job.state.in_(Job.non_ready_states)))
jobs = self.session().scalars(stmt)
return jobs
def undelete(self, user, flush=True):
"""Remove the deleted flag for the given user."""
+45 -1
View File
@@ -2,13 +2,18 @@ from galaxy_test.api._framework import ApiTestCase
from galaxy_test.base.api_asserts import assert_object_id_error
from galaxy_test.base.decorators import (
requires_admin,
requires_new_history,
requires_new_user,
)
from galaxy_test.base.populators import skip_without_tool
from galaxy_test.base.populators import (
DatasetPopulator,
skip_without_tool,
)
TEST_USER_EMAIL = "user_for_users_index_test@bx.psu.edu"
TEST_USER_EMAIL_INDEX_DELETED = "user_for_users_index_deleted_test@bx.psu.edu"
TEST_USER_EMAIL_DELETE = "user_for_delete_test@bx.psu.edu"
TEST_USER_EMAIL_DELETE_CANCEL_JOBS = "user_for_delete_cancel_jobs_test@bx.psu.edu"
TEST_USER_EMAIL_PURGE = "user_for_purge_test@bx.psu.edu"
TEST_USER_EMAIL_UNDELETE = "user_for_undelete_test@bx.psu.edu"
TEST_USER_EMAIL_SHOW = "user_for_show_test@bx.psu.edu"
@@ -129,6 +134,45 @@ class TestUsersApi(ApiTestCase):
undeleted_user = self._get(f"users/{user['id']}", admin=True).json()
assert undeleted_user["deleted"] is False, undeleted_user
@requires_admin
@requires_new_user
@requires_new_history
@skip_without_tool("cat_data_and_sleep")
def test_delete_user_cancel_all_jobs(self):
dataset_populator = DatasetPopulator(self.galaxy_interactor)
with self._different_user(TEST_USER_EMAIL_DELETE_CANCEL_JOBS):
user_id = self._get_current_user_id()
history_id = dataset_populator.new_history()
hda_id = dataset_populator.new_dataset(history_id)["id"]
inputs = {
"input1": {"src": "hda", "id": hda_id},
"sleep_time": 6000,
}
run_response = dataset_populator.run_tool_raw(
"cat_data_and_sleep",
inputs,
history_id,
)
self._assert_status_code_is_ok(run_response)
job_id = run_response.json()["jobs"][0]["id"]
# Wait a bit for the job to be ready
expected_job_states = ["new", "queued", "running"]
dataset_populator.wait_for_job(job_id, ok_states=expected_job_states)
# Get the job state
job_response = self._get(f"jobs/{job_id}").json()
assert job_response["state"] in expected_job_states, job_response
# Delete user will cancel all jobs
self._delete(f"users/{user_id}", admin=True)
# Get the job state again (this time as admin), it should be deleting
job_response = self._get(f"jobs/{job_id}", admin=True).json()
assert job_response["state"] == "deleting", job_response
@requires_new_user
def test_information(self):
user = self._setup_user(TEST_USER_EMAIL)