From e1a2b370d8b53ec120f621452219779ce710411e Mon Sep 17 00:00:00 2001 From: "sentry[bot]" <39604003+sentry[bot]@users.noreply.github.com> Date: Fri, 19 Jun 2026 19:18:11 +0000 Subject: [PATCH] perf(worker): Optimize N+1 queries in ProcessFlakesTask --- .../test_analytics/ta_process_flakes.py | 60 +++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/apps/worker/services/test_analytics/ta_process_flakes.py b/apps/worker/services/test_analytics/ta_process_flakes.py index 61cf26df09..7bc846de65 100644 --- a/apps/worker/services/test_analytics/ta_process_flakes.py +++ b/apps/worker/services/test_analytics/ta_process_flakes.py @@ -42,7 +42,27 @@ def get_testruns(upload: ReportSession) -> QuerySet[Testrun]: ).order_by("timestamp") -def handle_pass(curr_flakes: dict[bytes, Flake], test_id: bytes): +def get_testruns_for_uploads( + uploads: list[ReportSession], +) -> dict[int, list[Testrun]]: + """Fetch all testruns for a list of uploads in a single query, grouped by upload_id.""" + upload_ids = [upload.id for upload in uploads] + testruns = Testrun.objects.filter( + Q(timestamp__gte=timezone.now() - timedelta(days=1)) + & Q(upload_id__in=upload_ids) + ).order_by("timestamp") + + grouped: dict[int, list[Testrun]] = {upload_id: [] for upload_id in upload_ids} + for testrun in testruns: + grouped[testrun.upload_id].append(testrun) + return grouped + + +def handle_pass( + curr_flakes: dict[bytes, Flake], + test_id: bytes, + expired_flakes: list[Flake], +): # possible that we expire it and stop caring about it if test_id not in curr_flakes: return @@ -51,7 +71,7 @@ def handle_pass(curr_flakes: dict[bytes, Flake], test_id: bytes): curr_flakes[test_id].count += 1 if curr_flakes[test_id].recent_passes_count == 30: curr_flakes[test_id].end_date = timezone.now() - curr_flakes[test_id].save() + expired_flakes.append(curr_flakes[test_id]) del curr_flakes[test_id] @@ -81,10 +101,12 @@ def handle_failure( @sentry_sdk.trace def process_single_upload( - upload: ReportSession, curr_flakes: dict[bytes, Flake], repo_id: int -): - testruns = get_testruns(upload) - + upload: ReportSession, + testruns: list[Testrun], + curr_flakes: dict[bytes, Flake], + repo_id: int, + expired_flakes: list[Flake], +) -> list[Testrun]: for testrun in testruns: test_id = bytes(testrun.test_id) match testrun.outcome: @@ -92,13 +114,13 @@ def process_single_upload( if test_id not in curr_flakes: continue - handle_pass(curr_flakes, test_id) + handle_pass(curr_flakes, test_id, expired_flakes) case "failure" | "flaky_fail" | "error": handle_failure(curr_flakes, test_id, testrun, repo_id) case _: continue - Testrun.objects.bulk_update(testruns, ["outcome"]) + return testruns @sentry_sdk.trace @@ -106,7 +128,7 @@ def process_flakes_for_commit(repo_id: int, commit_id: str): log.info( "process_flakes_for_commit: starting processing", ) - uploads = get_relevant_uploads(repo_id, commit_id) + uploads = list(get_relevant_uploads(repo_id, commit_id)) log.info( "process_flakes_for_commit: fetched uploads", @@ -120,8 +142,18 @@ def process_flakes_for_commit(repo_id: int, commit_id: str): extra={"flakes": [flake.test_id.hex() for flake in curr_flakes.values()]}, ) + # Fetch all testruns for all uploads in a single query + testruns_by_upload = get_testruns_for_uploads(uploads) + + all_modified_testruns: list[Testrun] = [] + expired_flakes: list[Flake] = [] + for upload in uploads: - process_single_upload(upload, curr_flakes, repo_id) + testruns = testruns_by_upload.get(upload.id, []) + modified = process_single_upload( + upload, testruns, curr_flakes, repo_id, expired_flakes + ) + all_modified_testruns.extend(modified) log.info( "process_flakes_for_commit: processed upload", extra={"upload": upload.id}, @@ -132,6 +164,14 @@ def process_flakes_for_commit(repo_id: int, commit_id: str): extra={"flakes": [flake.test_id.hex() for flake in curr_flakes.values()]}, ) + # Single bulk_update for all modified testruns across all uploads + if all_modified_testruns: + Testrun.objects.bulk_update(all_modified_testruns, ["outcome"]) + + # Batch-update expired flakes instead of individual .save() calls + if expired_flakes: + Flake.objects.bulk_update(expired_flakes, ["end_date", "count", "recent_passes_count"]) + Flake.objects.bulk_create( curr_flakes.values(), update_conflicts=True,