def _retry_with_session(self, retryable, func, session, bulk):
        """Execute an operation with at most one consecutive retries

        Returns func()'s return value on success. On error retries the same
        command once.

        Re-raises any exception thrown by func().
        """
        retryable = (retryable and self.retry_writes
                     and session and not session._in_transaction)
        last_error = None
        retrying = False

        def is_retrying():
            return bulk.retrying if bulk else retrying
        # Increment the transaction id up front to ensure any retry attempt
        # will use the proper txnNumber, even if server or socket selection
        # fails before the command can be sent.
        if retryable:
            session._start_retryable_write()
            if bulk:
                bulk.started_retryable_write = True

        while True:
            try:
                server = self._select_server(writable_server_selector, session)
                supports_session = (
                    session is not None and
                    server.description.retryable_writes_supported)
                with self._get_socket(server, session) as sock_info:
                    if retryable and not supports_session:
                        if is_retrying():
                            # A retry is not possible because this server does
                            # not support sessions raise the last error.
                            raise last_error
                        retryable = False
                    return func(session, sock_info, retryable)
            except ServerSelectionTimeoutError:
                if is_retrying():
                    # The application may think the write was never attempted
                    # if we raise ServerSelectionTimeoutError on the retry
                    # attempt. Raise the original exception instead.
                    raise last_error
                # A ServerSelectionTimeoutError error indicates that there may
                # be a persistent outage. Attempting to retry in this case will
                # most likely be a waste of time.
                raise
            except ConnectionFailure as exc:
                if not retryable or is_retrying():
                    raise
                if bulk:
                    bulk.retrying = True
                else:
                    retrying = True
                last_error = exc
            except BulkWriteError as exc:
                if not retryable or is_retrying():
                    raise
                # Check the last writeConcernError to determine if this
                # BulkWriteError is retryable.
                wces = exc.details['writeConcernErrors']
                wce = wces[-1] if wces else {}
                if wce.get('code', 0) not in helpers._RETRYABLE_ERROR_CODES:
                    raise
                if bulk:
                    bulk.retrying = True
                else:
                    retrying = True
                last_error = exc
            except OperationFailure as exc:
                if not retryable or is_retrying():
                    raise
                if exc.code not in helpers._RETRYABLE_ERROR_CODES:
                    raise
                if bulk:
                    bulk.retrying = True
                else:
                    retrying = True
                last_error = exc
def _retry_with_session ( self , retryable , func , session , bulk ) : retryable = ( retryable and self . retry_writes and session and not session . _in_transaction ) last_error = None retrying = False def is_retrying ( ) : return bulk . retrying if bulk else retrying if retryable : session . _start_retryable_write ( ) if bulk : bulk . started_retryable_write = True while True : try : server = self . _select_server ( writable_server_selector , session ) supports_session = ( session is not None and server . description . retryable_writes_supported ) with self . _get_socket ( server , session ) as sock_info : if retryable and not supports_session : if is_retrying ( ) : raise last_error retryable = False return func ( session , sock_info , retryable ) except ServerSelectionTimeoutError : if is_retrying ( ) : raise last_error raise except ConnectionFailure as exc : if not retryable or is_retrying ( ) : raise if bulk : bulk . retrying = True else : retrying = True last_error = exc except BulkWriteError as exc : if not retryable or is_retrying ( ) : raise wces = exc . details [ 'writeConcernErrors' ] wce = wces [ - 1 ] if wces else { } if wce . get ( 'code' , 0 ) not in helpers . _RETRYABLE_ERROR_CODES : raise if bulk : bulk . retrying = True else : retrying = True last_error = exc except OperationFailure as exc : if not retryable or is_retrying ( ) : raise if exc . code not in helpers . _RETRYABLE_ERROR_CODES : raise if bulk : bulk . retrying = True else : retrying = True last_error = exc
Execute an operation with at most one consecutive retries

        Returns func()'s return value on success. On error retries the same
        command once.

        Re-raises any exception thrown by func().