5656
5757from bson .codec_options import DEFAULT_CODEC_OPTIONS , CodecOptions , TypeRegistry
5858from bson .timestamp import Timestamp
59- from pymongo import _csot , common , helpers_shared , periodic_executor
59+ from pymongo import _csot , _op_id , common , helpers_shared , periodic_executor
6060from pymongo ._telemetry import log_command_retry
6161from pymongo .asynchronous import client_session , database , uri_parser
6262from pymongo .asynchronous .change_stream import AsyncChangeStream , AsyncClusterChangeStream
9494 _log_client_error ,
9595 _log_or_warn ,
9696)
97- from pymongo .message import _CursorAddress , _GetMore , _Query
97+ from pymongo .message import _CursorAddress , _GetMore , _Query , _randint
9898from pymongo .monitoring import ConnectionClosedReason , _EventListeners
9999from pymongo .operations import (
100100 DeleteMany ,
@@ -1838,6 +1838,8 @@ async def _select_server(
18381838 be pinned to a mongos server address.
18391839 - `address` (optional): Address when sending a message
18401840 to a specific server, used for getMore.
1841+ - `operation_id` (optional): Stable operation id shared across retries,
1842+ used for command monitoring.
18411843 """
18421844 try :
18431845 topology = await self ._get_topology ()
@@ -2013,6 +2015,7 @@ async def _retry_internal(
20132015 :param retryable: If the operation should be retried once, defaults to None
20142016 :param is_run_command: If this is a runCommand operation, defaults to False
20152017 :param is_aggregate_write: If this is a aggregate operation with a write, defaults to False.
2018+ :param operation_id: Stable operation id shared across retries, defaults to None
20162019
20172020 :return: Output of the calling func()
20182021 """
@@ -2059,6 +2062,7 @@ async def _retryable_read(
20592062 (may not always be supported even if supplied), defaults to False
20602063 :param is_run_command: If this is a runCommand operation, defaults to False.
20612064 :param is_aggregate_write: If this is a aggregate operation with a write, defaults to False.
2065+ :param operation_id: Stable operation id shared across retries, defaults to None
20622066 """
20632067
20642068 # Ensure that the client supports retrying on reads and there is no session in
@@ -2102,6 +2106,7 @@ async def _retryable_write(
21022106 :param session: Client session we will use to execute write operation
21032107 :param operation: The name of the operation that the server is being selected for
21042108 :param bulk: bulk abstraction to execute operations in bulk, defaults to None
2109+ :param operation_id: Stable operation id shared across retries, defaults to None
21052110 """
21062111 async with self ._tmp_session (session ) as s :
21072112 return await self ._retry_with_session (retryable , func , s , bulk , operation , operation_id )
@@ -2785,7 +2790,7 @@ def __init__(
27852790 self ._server : Server = None # type: ignore
27862791 self ._deprioritized_servers : list [Server ] = []
27872792 self ._operation = operation
2788- self ._operation_id = operation_id
2793+ self ._operation_id = operation_id if operation_id is not None else _randint ()
27892794 self ._attempt_number = 0
27902795 self ._is_run_command = is_run_command
27912796 self ._is_aggregate_write = is_aggregate_write
@@ -3014,7 +3019,9 @@ async def _write(self) -> T:
30143019 self ._retryable = False
30153020 if self ._retrying :
30163021 self ._log_retry (is_write = True )
3017- return await self ._func (self ._session , conn , self ._retryable ) # type: ignore
3022+ # One operation id across all attempts of this operation.
3023+ with _op_id ._OpIdContext (self ._operation_id ):
3024+ return await self ._func (self ._session , conn , self ._retryable ) # type: ignore
30183025 except PyMongoError as exc :
30193026 if not self ._retryable :
30203027 raise
@@ -3037,7 +3044,9 @@ async def _read(self) -> T:
30373044 self ._check_last_error ()
30383045 if self ._retrying :
30393046 self ._log_retry (is_write = False )
3040- return await self ._func (self ._session , self ._server , conn , read_pref ) # type: ignore
3047+ # One operation id across all attempts of this operation.
3048+ with _op_id ._OpIdContext (self ._operation_id ):
3049+ return await self ._func (self ._session , self ._server , conn , read_pref ) # type: ignore
30413050
30423051
30433052def _after_fork_child () -> None :
0 commit comments