Я реализовал API на основе инфраструктуры REST Django и Django и обнаружил, что у него возникли некоторые проблемы, когда он работает в условиях большого параллелизма.
Поэтому мне было интересно написать некоторый код тестирования для воспроизведения проблемы, иулучшите код, чтобы потом обеспечить его безопасность в потоке.
Я пробовал библиотеку before_after
, и ее довольно сложно использовать, если занятая часть кода не является функцией или функцией, но содержитАргументы.
Я также пытался использовать ThreadPoolExecutor
для генерации условия гонки, но оно вызывает django.db.utils.DatabaseError: DatabaseWrapper objects created in a thread can only be used in that same thread. The object with alias 'default' was created in thread id 4328317000 and this is thread id 4690485864.
Моя реализация выглядит так:
class TestOrderViewSet(APILiveServerTestCase, AuthRequestMixin):
def test_replace_order_thread_safety(self):
john_balance = self.john.wallet.balance
jane_balance = self.jane.wallet.balance
order_user_pairs = [(mommy.make_recipe('payments.tests.jane_order'), self.jane)]
for i in range(10):
order_user_pairs.append((mommy.make_recipe('payments.tests.jane_order'), self.jane))
order_user_pairs.append((mommy.make_recipe('payments.tests.john_order'), self.john))
random.shuffle(order_user_pairs)
print(order_user_pairs)
self.assertGreaterEqual(Order.objects.count(), 20)
def replace_order(order, user, i):
print(i, order.id)
response = self.auth_post('order', {'pk': order.id}, user)
print(i, user.wallet.balance)
self.assertEqual(response.status_code, 200)
user.wallet.refresh_from_db()
print(i, user.wallet.balance)
def count_done():
return sum(int(r.done()) for r in results)
with ThreadPoolExecutor(max_workers=4) as e:
results = []
for i in range(10):
r = e.submit(replace_order, *order_user_pairs[i], i)
results.append(r)
r = e.submit(replace_order, *order_user_pairs[i], i)
results.append(r)
print('done', count_done())
# e.shutdown(wait=True)
print('done', count_done())
self.john.wallet.refresh_from_db()
self.jane.wallet.refresh_from_db()
self.assertEqual(self.john.wallet.balance, john_balance + 1)
self.assertEqual(self.jane.wallet.balance, jane_balance - 1)
Любые предложения приветствуются.Заранее спасибо.