-
Notifications
You must be signed in to change notification settings - Fork 1.1k
PYTHON-5794 - Add prose tests to verify correct retry behavior when a… #2755
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
6bd0214
ed52a0c
10d709b
4ff0116
9cce4c9
f76e12d
ac6d114
bf5ea70
e738bde
409c626
b448af5
eacc0c1
285dd6b
816a4b8
45a5929
8ff0005
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,7 +21,9 @@ | |
| import threading | ||
| from test.utils import set_fail_point | ||
|
|
||
| from pymongo.errors import OperationFailure | ||
| from pymongo import MongoClient | ||
| from pymongo.common import MAX_ADAPTIVE_RETRIES | ||
| from pymongo.errors import OperationFailure, PyMongoError | ||
|
|
||
| sys.path[0:0] = [""] | ||
|
|
||
|
|
@@ -38,6 +40,7 @@ | |
| ) | ||
|
|
||
| from pymongo.monitoring import ( | ||
| CommandFailedEvent, | ||
| ConnectionCheckedOutEvent, | ||
| ConnectionCheckOutFailedEvent, | ||
| ConnectionCheckOutFailedReason, | ||
|
|
@@ -145,6 +148,20 @@ def test_pool_paused_error_is_retryable(self): | |
|
|
||
|
|
||
| class TestRetryableReads(IntegrationTest): | ||
| def setUp(self) -> None: | ||
| super().setUp() | ||
| self.setup_client = MongoClient(**client_context.client_options) | ||
| self.addCleanup(self.setup_client.close) | ||
|
|
||
|
Comment on lines
+152
to
+156
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Separate PR) Can we add creating the collection here or do we have several deviations?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you open a ticket detailing what you mean?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Absolutely. https://jira.mongodb.org/browse/PYTHON-5796 |
||
| # TODO: After PYTHON-4595 we can use async event handlers and remove this workaround. | ||
| def configure_fail_point_sync(self, command_args, off=False) -> None: | ||
| cmd = {"configureFailPoint": "failCommand"} | ||
| cmd.update(command_args) | ||
| if off: | ||
| cmd["mode"] = "off" | ||
| cmd.pop("data", None) | ||
| self.setup_client.admin.command(cmd) | ||
|
|
||
| @client_context.require_multiple_mongoses | ||
| @client_context.require_failCommand_fail_point | ||
| def test_retryable_reads_are_retried_on_a_different_mongos_when_one_is_available(self): | ||
|
|
@@ -381,6 +398,58 @@ def test_03_03_retryable_reads_caused_by_overload_errors_are_retried_on_the_same | |
| # 6. Assert that both events occurred on the same server. | ||
| assert listener.failed_events[0].connection_id == listener.succeeded_events[0].connection_id | ||
|
|
||
| @client_context.require_failCommand_fail_point | ||
| @client_context.require_version_min(4, 4, 0) # type:ignore[untyped-decorator] | ||
| def test_overload_then_nonoverload_retries_increased_reads(self) -> None: | ||
| # Create a client. | ||
| listener = OvertCommandListener() | ||
|
|
||
| # Configure the client to listen to CommandFailedEvents. In the attached listener, configure a fail point with error | ||
| # code `91` (ShutdownInProgress) and `RetryableError` and `SystemOverloadedError` labels. | ||
| overload_fail_point = { | ||
| "configureFailPoint": "failCommand", | ||
| "mode": {"times": 1}, | ||
| "data": { | ||
| "failCommands": ["find"], | ||
| "errorLabels": ["RetryableError", "SystemOverloadedError"], | ||
| "errorCode": 91, | ||
| }, | ||
| } | ||
|
|
||
| # Configure a fail point with error code `91` (ShutdownInProgress) with only the `RetryableError` error label. | ||
| non_overload_fail_point = { | ||
| "configureFailPoint": "failCommand", | ||
| "mode": "alwaysOn", | ||
| "data": { | ||
| "failCommands": ["find"], | ||
| "errorCode": 91, | ||
| "errorLabels": ["RetryableError"], | ||
| }, | ||
| } | ||
|
|
||
| def failed(event: CommandFailedEvent) -> None: | ||
| # Configure the fail point command only if the failed event is for the 91 error configured in step 2. | ||
| if listener.failed_events: | ||
| return | ||
| assert event.failure["code"] == 91 | ||
| self.configure_fail_point_sync(non_overload_fail_point) | ||
| self.addCleanup(self.configure_fail_point_sync, {}, off=True) | ||
| listener.failed_events.append(event) | ||
|
|
||
| listener.failed = failed | ||
|
|
||
| client = self.rs_client(event_listeners=[listener]) | ||
| client.test.test.insert_one({}) | ||
|
|
||
| self.configure_fail_point_sync(overload_fail_point) | ||
| self.addCleanup(self.configure_fail_point_sync, {}, off=True) | ||
|
|
||
| with self.assertRaises(PyMongoError): | ||
| client.test.test.find_one() | ||
|
|
||
| started_finds = [e for e in listener.started_events if e.command_name == "find"] | ||
| self.assertEqual(len(started_finds), MAX_ADAPTIVE_RETRIES + 1) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| unittest.main() | ||
Uh oh!
There was an error while loading. Please reload this page.