diff --git a/corehq/apps/users/tasks.py b/corehq/apps/users/tasks.py index 163bd601037a..a0280d892565 100644 --- a/corehq/apps/users/tasks.py +++ b/corehq/apps/users/tasks.py @@ -371,7 +371,7 @@ def _process_reporting_metadata_staging(): record.delete() -@retry_on(ResourceConflict, delays=[0]) +@retry_on(ResourceConflict, delays=[0, 0.5]) def _process_record_with_retry(record): """ It is possible that an unrelated user update is saved to the db while we are processing the record diff --git a/corehq/apps/users/tests/test_tasks.py b/corehq/apps/users/tests/test_tasks.py index 31b2bdbf7b39..570690cec7ee 100644 --- a/corehq/apps/users/tests/test_tasks.py +++ b/corehq/apps/users/tests/test_tasks.py @@ -209,7 +209,7 @@ def test_record_is_not_deleted_if_not_processed_successfully(self, mock_process_ self.assertEqual(mock_process_record.call_count, 1) self.assertTrue(UserReportingMetadataStaging.objects.get(id=record.id)) - def test_process_record_is_retried_if_resource_conflict_raised(self, mock_process_record): + def test_process_record_is_retried_successfully_after_resource_conflict_raised(self, mock_process_record): # Simulate the scenario where the first attempt to process a record raises ResourceConflict # but the next attempt succeeds mock_process_record.side_effect = [ResourceConflict, None] @@ -220,6 +220,17 @@ def test_process_record_is_retried_if_resource_conflict_raised(self, mock_proces self.assertEqual(mock_process_record.call_count, 2) self.assertEqual(UserReportingMetadataStaging.objects.all().count(), 0) + def test_process_record_raises_resource_conflict_after_three_tries(self, mock_process_record): + # ResourceConflict will always be raised when calling mock_process_record + mock_process_record.side_effect = ResourceConflict + UserReportingMetadataStaging.objects.create(user_id=self.user._id, domain='test-domain') + + with self.assertRaises(ResourceConflict): + _process_reporting_metadata_staging() + + self.assertEqual(mock_process_record.call_count, 3) + self.assertEqual(UserReportingMetadataStaging.objects.all().count(), 1) + def test_subsequent_records_are_not_processed_if_exception_raised(self, mock_process_record): mock_process_record.side_effect = [Exception, None] UserReportingMetadataStaging.objects.create(user_id=self.user._id, domain='test-domain')