|
17 | 17 |
|
18 | 18 | import asyncio |
19 | 19 | import sys |
| 20 | +import time |
20 | 21 | from io import BytesIO |
21 | 22 | from test.asynchronous.utils_spec_runner import AsyncSpecRunner |
22 | 23 |
|
|
37 | 38 | from bson.raw_bson import RawBSONDocument |
38 | 39 | from pymongo import WriteConcern, _csot |
39 | 40 | from pymongo.asynchronous import client_session |
40 | | -from pymongo.asynchronous.client_session import TransactionOptions |
| 41 | +from pymongo.asynchronous.client_session import ( |
| 42 | + _BACKOFF_MAX, |
| 43 | + TransactionOptions, |
| 44 | + _set_backoff_initial, |
| 45 | +) |
41 | 46 | from pymongo.asynchronous.command_cursor import AsyncCommandCursor |
42 | 47 | from pymongo.asynchronous.cursor import AsyncCursor |
43 | 48 | from pymongo.errors import ( |
@@ -613,6 +618,42 @@ async def callback(session): |
613 | 618 | await s.with_transaction(callback) |
614 | 619 | self.assertFalse(s.in_transaction) |
615 | 620 |
|
| 621 | + @async_client_context.require_test_commands |
| 622 | + @async_client_context.require_transactions |
| 623 | + async def test_transaction_backoff(self): |
| 624 | + client = async_client_context.client |
| 625 | + coll = client[self.db.name].test |
| 626 | + # set fail point to trigger transaction failure and trigger backoff |
| 627 | + await self.set_fail_point( |
| 628 | + { |
| 629 | + "configureFailPoint": "failCommand", |
| 630 | + "mode": {"times": 3}, |
| 631 | + "data": { |
| 632 | + "failCommands": ["commitTransaction"], |
| 633 | + "errorCode": 24, |
| 634 | + }, |
| 635 | + } |
| 636 | + ) |
| 637 | + self.addAsyncCleanup( |
| 638 | + self.set_fail_point, {"configureFailPoint": "failCommand", "mode": "off"} |
| 639 | + ) |
| 640 | + |
| 641 | + start = time.monotonic() |
| 642 | + |
| 643 | + async def callback(session): |
| 644 | + await coll.insert_one({}, session=session) |
| 645 | + |
| 646 | + total_backoff = 0 |
| 647 | + async with self.client.start_session() as s: |
| 648 | + await s.with_transaction(callback) |
| 649 | + self.assertEqual(len(s._transaction_retry_backoffs), 3) |
| 650 | + for backoff in s._transaction_retry_backoffs: |
| 651 | + self.assertGreater(backoff, 0) |
| 652 | + total_backoff += backoff |
| 653 | + |
| 654 | + end = time.monotonic() |
| 655 | + self.assertGreaterEqual(end - start, total_backoff) |
| 656 | + |
616 | 657 |
|
617 | 658 | class TestOptionsInsideTransactionProse(AsyncTransactionsBase): |
618 | 659 | @async_client_context.require_transactions |
|
0 commit comments