-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Delete project and organization objects asynchronously #12541
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,9 +4,13 @@ | |
|
|
||
| import redis | ||
| import structlog | ||
| from django.apps import apps | ||
| from django.conf import settings | ||
| from django.contrib.auth.models import User | ||
| from django.core.mail import EmailMultiAlternatives | ||
|
|
||
| from readthedocs.builds.utils import memcache_lock | ||
| from readthedocs.core.history import set_change_reason | ||
| from readthedocs.worker import app | ||
|
|
||
|
|
||
|
|
@@ -71,3 +75,38 @@ def cleanup_pidbox_keys(): | |
| client.delete(key) | ||
|
|
||
| log.info("Redis pidbox objects.", memory=total_memory, keys=len(keys)) | ||
|
|
||
|
|
||
| @app.task(queue="web", bind=True) | ||
| def delete_object(self, model_name: str, pk: int, user_id: int | None = None): | ||
| """ | ||
| Delete an object from the database asynchronously. | ||
|
|
||
| This is useful for deleting large objects that may take time | ||
| to delete, without timing out the request. | ||
|
|
||
| :param model_name: The model name in the format 'app_label.ModelName'. | ||
| :param pk: The primary key of the object to delete. | ||
| :param user_id: The ID of the user performing the deletion. | ||
| Just for logging purposes. | ||
| """ | ||
| task_log = log.bind(model_name=model_name, object_pk=pk, user_id=user_id) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are you using
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. log is a global variable and python gets confused with the scope, raising an error that the variable is unbound. |
||
| lock_id = f"{self.name}-{model_name}-{pk}-lock" | ||
| lock_expire = 60 * 60 * 2 # 2 hours | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe one hour is fine? or less...
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I think it's not super important. |
||
| with memcache_lock( | ||
| lock_id=lock_id, lock_expire=lock_expire, app_identifier=self.app.oid | ||
| ) as acquired: | ||
| if not acquired: | ||
| task_log.info("Object is already being deleted.") | ||
| return | ||
|
|
||
| user = User.objects.filter(pk=user_id).first() if user_id else None | ||
| Model = apps.get_model(model_name) | ||
| obj = Model.objects.filter(pk=pk).first() | ||
| if obj: | ||
| task_log.info("Deleting object.") | ||
| set_change_reason(obj, reason="Object deleted asynchronously", user=user) | ||
| obj.delete() | ||
| task_log.info("Object deleted.") | ||
| else: | ||
| task_log.info("Object does not exist.") | ||
Uh oh!
There was an error while loading. Please reload this page.