Skip to content

Commit

Permalink
Merge pull request #17390 from davelopez/cancel_deleted_user_jobs
Browse files Browse the repository at this point in the history
Cancel all active jobs when the user is deleted
  • Loading branch information
mvdbeek authored Feb 2, 2024
2 parents c2c3154 + c0a3b29 commit beea9fa
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 1 deletion.
16 changes: 16 additions & 0 deletions lib/galaxy/managers/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
)
from galaxy.managers.base import combine_lists
from galaxy.model import (
Job,
User,
UserAddress,
UserQuotaUsage,
Expand Down Expand Up @@ -161,6 +162,21 @@ def delete(self, user, flush=True):
"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."""
Expand Down
46 changes: 45 additions & 1 deletion lib/galaxy_test/api/test_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@
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 = "[email protected]"
TEST_USER_EMAIL_INDEX_DELETED = "[email protected]"
TEST_USER_EMAIL_DELETE = "[email protected]"
TEST_USER_EMAIL_DELETE_CANCEL_JOBS = "[email protected]"
TEST_USER_EMAIL_PURGE = "[email protected]"
TEST_USER_EMAIL_UNDELETE = "[email protected]"
TEST_USER_EMAIL_SHOW = "[email protected]"
Expand Down Expand Up @@ -129,6 +134,45 @@ def test_undelete_user(self):
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)
Expand Down

0 comments on commit beea9fa

Please sign in to comment.