Skip to content

Commit 641dc78

Browse files
authored
fix(api): add cleanup for orphan scheduled scans caused by transaction isolation (#9633)
1 parent 57b9a2e commit 641dc78

File tree

3 files changed

+412
-1
lines changed

3 files changed

+412
-1
lines changed

api/CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,20 @@
22

33
All notable changes to the **Prowler API** are documented in this file.
44

5-
## [1.18.0] (Prowler UUNRELEASED)
5+
## [1.18.0] (Prowler UNRELEASED)
66

77
### Added
88
- Support AlibabaCloud provider [(#9485)](https://github.com/prowler-cloud/prowler/pull/9485)
99

1010
---
1111

12+
## [1.17.1] (Prowler UNRELEASED)
13+
14+
### Fixed
15+
- Orphan scheduled scans caused by transaction isolation during provider creation [(#9633)](https://github.com/prowler-cloud/prowler/pull/9633)
16+
17+
---
18+
1219
## [1.17.0] (Prowler v5.16.0)
1320

1421
### Added

api/src/backend/tasks/tasks.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,58 @@
6161
logger = get_task_logger(__name__)
6262

6363

64+
def _cleanup_orphan_scheduled_scans(
65+
tenant_id: str,
66+
provider_id: str,
67+
scheduler_task_id: int,
68+
) -> int:
69+
"""
70+
TEMPORARY WORKAROUND: Clean up orphan AVAILABLE scans.
71+
72+
Detects and removes AVAILABLE scans that were never used due to an
73+
issue during the first scheduled scan setup.
74+
75+
An AVAILABLE scan is considered orphan if there's also a SCHEDULED scan for
76+
the same provider with the same scheduler_task_id. This situation indicates
77+
that the first scan execution didn't find the AVAILABLE scan (because it
78+
wasn't committed yet, probably) and created a new one, leaving the AVAILABLE orphaned.
79+
80+
Args:
81+
tenant_id: The tenant ID.
82+
provider_id: The provider ID.
83+
scheduler_task_id: The PeriodicTask ID that triggers these scans.
84+
85+
Returns:
86+
Number of orphan scans deleted (0 if none found).
87+
"""
88+
orphan_available_scans = Scan.objects.filter(
89+
tenant_id=tenant_id,
90+
provider_id=provider_id,
91+
trigger=Scan.TriggerChoices.SCHEDULED,
92+
state=StateChoices.AVAILABLE,
93+
scheduler_task_id=scheduler_task_id,
94+
)
95+
96+
scheduled_scan_exists = Scan.objects.filter(
97+
tenant_id=tenant_id,
98+
provider_id=provider_id,
99+
trigger=Scan.TriggerChoices.SCHEDULED,
100+
state=StateChoices.SCHEDULED,
101+
scheduler_task_id=scheduler_task_id,
102+
).exists()
103+
104+
if scheduled_scan_exists and orphan_available_scans.exists():
105+
orphan_count = orphan_available_scans.count()
106+
logger.warning(
107+
f"[WORKAROUND] Found {orphan_count} orphan AVAILABLE scan(s) for "
108+
f"provider {provider_id} alongside a SCHEDULED scan. Cleaning up orphans..."
109+
)
110+
orphan_available_scans.delete()
111+
return orphan_count
112+
113+
return 0
114+
115+
64116
def _perform_scan_complete_tasks(tenant_id: str, scan_id: str, provider_id: str):
65117
"""
66118
Helper function to perform tasks after a scan is completed.
@@ -247,6 +299,14 @@ def perform_scheduled_scan_task(self, tenant_id: str, provider_id: str):
247299
return serializer.data
248300

249301
next_scan_datetime = get_next_execution_datetime(task_id, provider_id)
302+
303+
# TEMPORARY WORKAROUND: Clean up orphan scans from transaction isolation issue
304+
_cleanup_orphan_scheduled_scans(
305+
tenant_id=tenant_id,
306+
provider_id=provider_id,
307+
scheduler_task_id=periodic_task_instance.id,
308+
)
309+
250310
scan_instance, _ = Scan.objects.get_or_create(
251311
tenant_id=tenant_id,
252312
provider_id=provider_id,

0 commit comments

Comments
 (0)