Skip to content

Commit 75e130f

Browse files
committed
fix: pin bulk submission delete to primary DB
delete_xform_submissions and its async wrapper lack @use_master, so the submission_count correction reads from a replica that may have replication lag. The stale count matches num_of_submissions, skipping the correction entirely.
1 parent 3f398c3 commit 75e130f

4 files changed

Lines changed: 35 additions & 0 deletions

File tree

onadata/apps/api/tasks.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from django.utils.datastructures import MultiValueDict
1818

1919
from celery.result import AsyncResult
20+
from multidb.pinning import use_master
2021

2122
from onadata.apps.api import tools
2223
from onadata.apps.logger.models import Instance, Project, ProjectInvitation, XForm
@@ -213,6 +214,7 @@ def share_project_async(project_id, username, role, remove=False):
213214

214215

215216
@app.task(base=AutoRetryTask)
217+
@use_master
216218
def delete_xform_submissions_async(
217219
xform_id: int,
218220
deleted_by_id: int,

onadata/apps/api/tests/test_tasks.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
from django.core.cache import cache
88
from django.db import DatabaseError, OperationalError
99

10+
from multidb.pinning import this_thread_is_pinned
11+
1012
from onadata.apps.api.tasks import (
1113
ShareProject,
1214
delete_xform_submissions_async,
@@ -231,3 +233,11 @@ def test_user_id_invalid(self, mock_logger, mock_delete):
231233
delete_xform_submissions_async.delay(self.xform.pk, sys.maxsize)
232234
self.assertFalse(mock_delete.called)
233235
mock_logger.assert_called_once()
236+
237+
def test_pinned_to_primary_db(self, mock_delete):
238+
"""Thread is pinned to primary DB during task execution"""
239+
mock_delete.side_effect = lambda *a, **kw: self.assertTrue(
240+
this_thread_is_pinned(),
241+
"Thread was not pinned to primary DB when calling delete_xform_submissions",
242+
)
243+
delete_xform_submissions_async.delay(self.xform.pk, self.user.pk)

onadata/libs/tests/utils/test_logger_tools.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
from azure.storage.blob import AccountSasPermissions
2121
from defusedxml.ElementTree import ParseError
22+
from multidb.pinning import this_thread_is_pinned
2223

2324
from onadata.apps.logger.import_tools import django_file
2425
from onadata.apps.logger.models import Instance, InstanceHistory
@@ -1186,6 +1187,27 @@ def test_decrypted_submission_count_updated(self):
11861187
self.xform.refresh_from_db()
11871188
self.assertEqual(self.xform.num_of_decrypted_submissions, 3)
11881189

1190+
def test_pinned_to_primary_db(self):
1191+
"""Thread is pinned to primary DB during deletion"""
1192+
pinned_states = []
1193+
original_submission_count = type(self.xform).submission_count
1194+
1195+
def capture_pinned(xform_self, force_update=False):
1196+
if force_update:
1197+
pinned_states.append(this_thread_is_pinned())
1198+
return original_submission_count(xform_self, force_update=force_update)
1199+
1200+
with patch.object(type(self.xform), "submission_count", capture_pinned):
1201+
delete_xform_submissions(self.xform, self.user)
1202+
1203+
self.assertTrue(
1204+
pinned_states, "submission_count was not called with force_update"
1205+
)
1206+
self.assertTrue(
1207+
all(pinned_states),
1208+
"Thread was not pinned to primary DB during submission_count",
1209+
)
1210+
11891211

11901212
class ResponseWithMimetypeAndNameTestCase(TestBase):
11911213
"""Tests for method `response_with_mimetype_and_name`"""

onadata/libs/utils/logger_tools.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,6 +1313,7 @@ def publish_xform(self):
13131313
return publish_xml_form(self.xml_file, self.user, self.project)
13141314

13151315

1316+
@use_master
13161317
def delete_xform_submissions(
13171318
xform: XForm,
13181319
deleted_by: User,

0 commit comments

Comments
 (0)