🐛(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
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) add jitter to WS reconnection #2162
- 🐛(frontend) fix tree pagination #2145 - 🐛(frontend) fix tree pagination #2145
- 🐛(nginx) add page reconciliation on nginx #2154 - 🐛(nginx) add page reconciliation on nginx #2154
- 🐛(backend) fix race condition in reconciliation requests CSV import #2153
## [v4.8.4] - 2026-03-25 ## [v4.8.4] - 2026-03-25

View File

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

View File

@@ -1,6 +1,7 @@
"""Processing tasks for user reconciliation CSV imports.""" """Processing tasks for user reconciliation CSV imports."""
import csv import csv
import logging
import traceback import traceback
import uuid import uuid
@@ -14,6 +15,8 @@ from core.models import UserReconciliation, UserReconciliationCsvImport
from impress.celery_app import app from impress.celery_app import app
logger = logging.getLogger(__name__)
def _process_row(row, job, counters): def _process_row(row, job, counters):
"""Process a single row from the CSV file.""" """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 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. the entire job to fail or prevent the next rows from being processed.
""" """
# Imports the CSV file, breaks it into UserReconciliation items try:
job = UserReconciliationCsvImport.objects.get(id=job_id) 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.status = "running"
job.save() job.save()