Skip to content

Commit 9405535

Browse files
committed
🐛(backend) fix race condition in reconciliation requests CSV import
The call to the background task is now wrapped in a on_commit to ensure that it isn't called before the save is finished, in order to avoid race condition issues.
1 parent cd882c8 commit 9405535

File tree

3 files changed

+16
-4
lines changed

3 files changed

+16
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ and this project adheres to
2121

2222
- 🐛(frontend) fix tree pagination #2145
2323
- 🐛(nginx) add page reconciliation on nginx #2154
24-
24+
- 🐛(backend) fix race condition in reconciliation requests CSV import #2153
2525

2626
## [v4.8.4] - 2026-03-25
2727

src/backend/core/admin.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
"""Admin classes and registrations for core app."""
22

3+
from functools import partial
4+
35
from django.contrib import admin, messages
46
from django.contrib.auth import admin as auth_admin
7+
from django.db import transaction
58
from django.shortcuts import redirect
69
from django.utils.translation import gettext_lazy as _
710

@@ -108,7 +111,9 @@ def save_model(self, request, obj, form, change):
108111
super().save_model(request, obj, form, change)
109112

110113
if not change:
111-
user_reconciliation_csv_import_job.delay(obj.pk)
114+
transaction.on_commit(
115+
partial(user_reconciliation_csv_import_job.delay, obj.pk)
116+
)
112117
messages.success(request, _("Import job created and queued."))
113118
return redirect("..")
114119

src/backend/core/tasks/user_reconciliation.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Processing tasks for user reconciliation CSV imports."""
22

33
import csv
4+
import logging
45
import traceback
56
import uuid
67

@@ -14,6 +15,8 @@
1415

1516
from impress.celery_app import app
1617

18+
logger = logging.getLogger(__name__)
19+
1720

1821
def _process_row(row, job, counters):
1922
"""Process a single row from the CSV file."""
@@ -89,8 +92,12 @@ def user_reconciliation_csv_import_job(job_id):
8992
Rows with errors are logged in the job logs and skipped, but do not cause
9093
the entire job to fail or prevent the next rows from being processed.
9194
"""
92-
# Imports the CSV file, breaks it into UserReconciliation items
93-
job = UserReconciliationCsvImport.objects.get(id=job_id)
95+
try:
96+
job = UserReconciliationCsvImport.objects.get(id=job_id)
97+
except UserReconciliationCsvImport.DoesNotExist:
98+
logger.warning("CSV import job %s no longer exists; skipping.", job_id)
99+
return
100+
94101
job.status = "running"
95102
job.save()
96103

0 commit comments

Comments
 (0)