Skip to content

Commit c663ee0

Browse files
perf: add bulk_delete_findings, fix CASCADE_DELETE and scope expansion
- Add bulk_delete_findings() wrapper: M2M cleanup + chunked cascade_delete - reconfigure_duplicate_cluster: return early when CASCADE_DELETE=True instead of calling Django .delete() which fires signals per finding - finding_delete: use bulk_delete_findings when CASCADE_DELETE=True - async_delete_crawl_task: expand scope to include outside-scope duplicates, use bulk_delete_findings instead of manual M2M + cascade_delete calls - Fix test to use async_delete class instead of direct task import
1 parent 0f82c0d commit c663ee0

4 files changed

Lines changed: 13 additions & 22 deletions

File tree

dojo/finding/helper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ def bulk_clear_finding_m2m(finding_qs):
751751

752752
def bulk_delete_findings(finding_qs, chunk_size=1000):
753753
"""
754-
Delete findings and all related objects efficiently.
754+
Delete findings and all related objects efficiently. Including any related object in Dojo-Pro
755755
756756
Sends the pre_bulk_delete signal, clears M2M through tables (not
757757
discovered by _meta.related_objects), then uses cascade_delete for

dojo/utils.py

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2047,7 +2047,7 @@ def _get_object_name(obj):
20472047

20482048

20492049
@app.task
2050-
def async_delete_crawl_task(obj, **kwargs):
2050+
def async_delete_task(obj, **kwargs):
20512051
"""
20522052
Delete an object and all its related objects using the SQL cascade walker.
20532053
@@ -2064,6 +2064,12 @@ def async_delete_crawl_task(obj, **kwargs):
20642064
)
20652065
from dojo.utils_cascade_delete import cascade_delete # noqa: PLC0415 circular import
20662066

2067+
logger.debug("ASYNC_DELETE: Deleting %s: %s", _get_object_name(obj), obj)
2068+
if not isinstance(obj, ASYNC_DELETE_SUPPORTED_TYPES):
2069+
logger.debug("ASYNC_DELETE: %s async delete not supported. Deleting normally: %s", _get_object_name(obj), obj)
2070+
obj.delete()
2071+
return
2072+
20672073
obj_name = _get_object_name(obj)
20682074
logger.info("ASYNC_DELETE: Starting deletion of %s: %s", obj_name, obj)
20692075

@@ -2116,24 +2122,6 @@ def async_delete_crawl_task(obj, **kwargs):
21162122
logger.info("ASYNC_DELETE: Successfully deleted %s: %s", obj_name, obj)
21172123

21182124

2119-
@app.task
2120-
def async_delete_task(obj, **kwargs):
2121-
"""
2122-
Module-level Celery task to delete an object and its related objects.
2123-
2124-
Accepts **kwargs for _pgh_context injected by dojo_dispatch_task.
2125-
Uses PgHistoryTask base class (default) to preserve pghistory context for audit trail.
2126-
"""
2127-
from dojo.celery_dispatch import dojo_dispatch_task # noqa: PLC0415 circular import
2128-
2129-
logger.debug("ASYNC_DELETE: Deleting %s: %s", _get_object_name(obj), obj)
2130-
if isinstance(obj, ASYNC_DELETE_SUPPORTED_TYPES):
2131-
dojo_dispatch_task(async_delete_crawl_task, obj)
2132-
else:
2133-
logger.debug("ASYNC_DELETE: %s async delete not supported. Deleting normally: %s", _get_object_name(obj), obj)
2134-
obj.delete()
2135-
2136-
21372125
class async_delete:
21382126

21392127
"""

dojo/utils_cascade_delete.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ def cascade_delete(from_model, instance_pk_query, skip_relations=None, base_mode
6161
recurses into CASCADE children first (bottom-up), then deletes at the
6262
current level. No query execution until recursion unwinds.
6363
64+
Includes any related object in Dojo-Pro
65+
6466
Args:
6567
from_model: The model class to delete from.
6668
instance_pk_query: QuerySet selecting the records to delete.

unittests/test_prepare_duplicates_for_delete.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ def test_delete_product_with_cross_engagement_duplicates(self):
340340
Action: delete the entire product via async_delete_crawl_task.
341341
Expected: product and all findings are deleted without errors.
342342
"""
343-
from dojo.utils import async_delete_crawl_task # noqa: PLC0415
343+
from dojo.utils import async_delete # noqa: PLC0415
344344

345345
finding_a = self._create_finding(self.test1, "Original A")
346346
finding_a.active = True
@@ -355,7 +355,8 @@ def test_delete_product_with_cross_engagement_duplicates(self):
355355
finding_b_id = finding_b.id
356356

357357
with impersonate(self.testuser):
358-
async_delete_crawl_task(self.product)
358+
async_del = async_delete()
359+
async_del.delete(self.product)
359360

360361
# Everything should be gone
361362
self.assertFalse(Product.objects.filter(id=product_id).exists())

0 commit comments

Comments
 (0)