🐛(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.
This commit is contained in:
Sylvain Boissel 2026-04-10 12:46:56 +02:00 committed by GitHub
parent a29b25f82f
commit 3399734a55
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 16 additions and 4 deletions

View file

@ -47,7 +47,7 @@ ctrl/command/middle-mouse click #2170
- ⚡️(frontend) add jitter to WS reconnection #2162
- 🐛(frontend) fix tree pagination #2145
- 🐛(nginx) add page reconciliation on nginx #2154
- 🐛(backend) fix race condition in reconciliation requests CSV import #2153
## [v4.8.4] - 2026-03-25

View file

@ -1,7 +1,10 @@
"""Admin classes and registrations for core app."""
from functools import partial
from django.contrib import admin, messages
from django.contrib.auth import admin as auth_admin
from django.db import transaction
from django.shortcuts import redirect
from django.utils.translation import gettext_lazy as _
@ -108,7 +111,9 @@ class UserReconciliationCsvImportAdmin(admin.ModelAdmin):
super().save_model(request, obj, form, change)
if not change:
user_reconciliation_csv_import_job.delay(obj.pk)
transaction.on_commit(
partial(user_reconciliation_csv_import_job.delay, obj.pk)
)
messages.success(request, _("Import job created and queued."))
return redirect("..")

View file

@ -1,6 +1,7 @@
"""Processing tasks for user reconciliation CSV imports."""
import csv
import logging
import traceback
import uuid
@ -14,6 +15,8 @@ from core.models import UserReconciliation, UserReconciliationCsvImport
from impress.celery_app import app
logger = logging.getLogger(__name__)
def _process_row(row, job, counters):
"""Process a single row from the CSV file."""
@ -89,8 +92,12 @@ def user_reconciliation_csv_import_job(job_id):
Rows with errors are logged in the job logs and skipped, but do not cause
the entire job to fail or prevent the next rows from being processed.
"""
# Imports the CSV file, breaks it into UserReconciliation items
job = UserReconciliationCsvImport.objects.get(id=job_id)
try:
job = UserReconciliationCsvImport.objects.get(id=job_id)
except UserReconciliationCsvImport.DoesNotExist:
logger.warning("CSV import job %s no longer exists; skipping.", job_id)
return
job.status = "running"
job.save()