Make namespace deletion asynchronous

Instead of deleting a namespace synchronously as before, we now mark the namespace for deletion, disable it, and rename it. A worker then comes along and deletes the namespace in the background. This results in a *significantly* better user experience, as the namespace deletion operation now "completes" in under a second, where before it could take 10s of minutes at the worse.

Fixes https://jira.coreos.com/browse/QUAY-838
This commit is contained in:
Joseph Schorr 2018-02-23 16:45:16 -05:00
parent d9015a1863
commit 8bc55a5676
21 changed files with 244 additions and 129 deletions

View file

@ -4,9 +4,11 @@ import pytest
from mock import patch
from data.database import EmailConfirmation
from data.database import EmailConfirmation, User, DeletedNamespace
from data.model.user import create_user_noverify, validate_reset_code, get_active_users
from data.model.user import mark_namespace_for_deletion, delete_namespace_via_marker
from util.timedeltastring import convert_to_timedelta
from data.queue import WorkQueue
from test.fixtures import *
def test_create_user_with_expiration(initialized_db):
@ -38,3 +40,46 @@ def test_get_active_users(disabled, initialized_db):
for user in users:
if not disabled:
assert user.enabled
def test_mark_namespace_for_deletion(initialized_db):
def create_transaction(db):
return db.transaction()
# Create a user and then mark it for deletion.
user = create_user_noverify('foobar', 'foo@example.com', email_required=False)
# Mark the user for deletion.
queue = WorkQueue('testgcnamespace', create_transaction)
mark_namespace_for_deletion(user, [], queue)
# Ensure the older user is still in the DB.
assert User.get(id=user.id).username != 'foobar'
# Ensure we can create a user with the same namespace again.
new_user = create_user_noverify('foobar', 'foo@example.com', email_required=False)
assert new_user.id != user.id
# Ensure the older user is still in the DB.
assert User.get(id=user.id).username != 'foobar'
def test_delete_namespace_via_marker(initialized_db):
def create_transaction(db):
return db.transaction()
# Create a user and then mark it for deletion.
user = create_user_noverify('foobar', 'foo@example.com', email_required=False)
# Mark the user for deletion.
queue = WorkQueue('testgcnamespace', create_transaction)
marker_id = mark_namespace_for_deletion(user, [], queue)
# Delete the user.
delete_namespace_via_marker(marker_id, [])
# Ensure the user was actually deleted.
with pytest.raises(User.DoesNotExist):
User.get(id=user.id)
with pytest.raises(DeletedNamespace.DoesNotExist):
DeletedNamespace.get(id=marker_id)