<!-- 
RSS generated by JIRA (9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66) at Thu Feb 08 09:01:04 UTC 2024

It is possible to restrict the fields that are returned in this document by specifying the 'field' parameter in your request.
For example, to request only the issue key and summary append 'field=key&field=summary' to the URL of your request.
-->
<rss version="0.92" >
<channel>
    <title>MongoDB Jira</title>
    <link>https://jira.mongodb.org</link>
    <description>This file is an XML representation of an issue</description>
    <language>en-us</language>    <build-info>
        <version>9.7.1</version>
        <build-number>970001</build-number>
        <build-date>13-04-2023</build-date>
    </build-info>


<item>
            <title>[JAVA-4034] Refactor read/write retries to accommodate for both PoolClearedError and CSOT</title>
                <link>https://jira.mongodb.org/browse/JAVA-4034</link>
                <project id="10006" key="JAVA">Java Driver</project>
                    <description>
    &lt;div id=&quot;script-target-wrapper&quot;&gt;
        &lt;br&gt;
        &lt;b&gt;DRIVERS Ticket Description&lt;/b&gt;
        &lt;div id=&quot;lang-script-target&quot;&gt;
            &lt;!-- This block of HTML and the script in it auto-populate the DRIVERS ticket description on page load. --&gt;
            Script Target - If you can read this text, the script has failed
            &lt;script&gt;
                $.get(&apos;https://jira.mongodb.org/browse/DRIVERS-1483&apos;, function(data) {
                    var description = $(data).find(&quot;#description-val&quot;);
                    $(&quot;#lang-script-target&quot;).html(description);
                });
            &lt;/script&gt;
        &lt;/div&gt;
    &lt;/div&gt;
</description>
                <environment></environment>
        <key id="1640960">JAVA-4034</key>
            <summary>Refactor read/write retries to accommodate for both PoolClearedError and CSOT</summary>
                <type id="4" iconUrl="https://jira.mongodb.org/secure/viewavatar?size=xsmall&amp;avatarId=14710&amp;avatarType=issuetype">Improvement</type>
                                            <priority id="3" iconUrl="https://jira.mongodb.org/images/icons/priorities/major.svg">Major - P3</priority>
                        <status id="6" iconUrl="https://jira.mongodb.org/images/icons/statuses/closed.png" description="The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.">Closed</status>
                    <statusCategory id="3" key="done" colorName="success"/>
                                    <resolution id="13201">Fixed</resolution>
                                        <assignee username="valentin.kovalenko@mongodb.com">Valentin Kavalenka</assignee>
                                    <reporter username="backlog-server-pm">Backlog - Core Eng Program Management Team</reporter>
                        <labels>
                    </labels>
                <created>Fri, 5 Mar 2021 16:55:57 +0000</created>
                <updated>Sat, 28 Oct 2023 11:21:22 +0000</updated>
                            <resolved>Mon, 27 Sep 2021 19:48:12 +0000</resolved>
                                                    <fixVersion>4.4.0</fixVersion>
                                    <component>Internal</component>
                                        <votes>0</votes>
                                    <watches>3</watches>
                                                                                                                <comments>
                            <comment id="4701510" author="xgen-internal-githook" created="Mon, 25 Jul 2022 12:44:14 +0000"  >&lt;p&gt;Author:&lt;/p&gt;
{&apos;name&apos;: &apos;Jeff Yemin&apos;, &apos;email&apos;: &apos;jeff.yemin@mongodb.com&apos;, &apos;username&apos;: &apos;jyemin&apos;}
&lt;p&gt;Message: Do not retry a read operation when in a transaction (#982)&lt;/p&gt;

&lt;p&gt;Fixes a regression introduced in 4.4.0 in scope of &lt;a href=&quot;https://jira.mongodb.org/browse/JAVA-4034&quot; title=&quot;Refactor read/write retries to accommodate for both PoolClearedError and CSOT&quot; class=&quot;issue-link&quot; data-issue-key=&quot;JAVA-4034&quot;&gt;&lt;del&gt;JAVA-4034&lt;/del&gt;&lt;/a&gt;, and&lt;br/&gt;
was undetected due to the lack of a specification test for the&lt;br/&gt;
required behavior.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://jira.mongodb.org/browse/JAVA-4684&quot; title=&quot;Read operations in transactions are incorrectly retried&quot; class=&quot;issue-link&quot; data-issue-key=&quot;JAVA-4684&quot;&gt;&lt;del&gt;JAVA-4684&lt;/del&gt;&lt;/a&gt;&lt;br/&gt;
Branch: 4.7.x&lt;br/&gt;
&lt;a href=&quot;https://github.com/mongodb/mongo-java-driver/commit/f42ef7d028dc4b5b2bdda3e32bfe1f8991c2c21b&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;https://github.com/mongodb/mongo-java-driver/commit/f42ef7d028dc4b5b2bdda3e32bfe1f8991c2c21b&lt;/a&gt;&lt;/p&gt;</comment>
                            <comment id="4701485" author="xgen-internal-githook" created="Mon, 25 Jul 2022 12:33:14 +0000"  >&lt;p&gt;Author:&lt;/p&gt;
{&apos;name&apos;: &apos;Jeff Yemin&apos;, &apos;email&apos;: &apos;jeff.yemin@mongodb.com&apos;, &apos;username&apos;: &apos;jyemin&apos;}
&lt;p&gt;Message: Do not retry a read operation when in a transaction (#982)&lt;/p&gt;

&lt;p&gt;Fixes a regression introduced in 4.4.0 in scope of &lt;a href=&quot;https://jira.mongodb.org/browse/JAVA-4034&quot; title=&quot;Refactor read/write retries to accommodate for both PoolClearedError and CSOT&quot; class=&quot;issue-link&quot; data-issue-key=&quot;JAVA-4034&quot;&gt;&lt;del&gt;JAVA-4034&lt;/del&gt;&lt;/a&gt;, and&lt;br/&gt;
was undetected due to the lack of a specification test for the&lt;br/&gt;
required behavior.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://jira.mongodb.org/browse/JAVA-4684&quot; title=&quot;Read operations in transactions are incorrectly retried&quot; class=&quot;issue-link&quot; data-issue-key=&quot;JAVA-4684&quot;&gt;&lt;del&gt;JAVA-4684&lt;/del&gt;&lt;/a&gt;&lt;br/&gt;
Branch: master&lt;br/&gt;
&lt;a href=&quot;https://github.com/mongodb/mongo-java-driver/commit/afb5d0ae6693d1915b7afa3b84d250974fe15998&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;https://github.com/mongodb/mongo-java-driver/commit/afb5d0ae6693d1915b7afa3b84d250974fe15998&lt;/a&gt;&lt;/p&gt;</comment>
                            <comment id="4087561" author="xgen-internal-githook" created="Mon, 27 Sep 2021 19:41:45 +0000"  >&lt;p&gt;Author:&lt;/p&gt;
{&apos;name&apos;: &apos;Valentin Kovalenko&apos;, &apos;email&apos;: &apos;valentin.kovalenko@mongodb.com&apos;, &apos;username&apos;: &apos;stIncMale&apos;}
&lt;p&gt;Message: &lt;a href=&quot;https://jira.mongodb.org/browse/JAVA-4034&quot; title=&quot;Refactor read/write retries to accommodate for both PoolClearedError and CSOT&quot; class=&quot;issue-link&quot; data-issue-key=&quot;JAVA-4034&quot;&gt;&lt;del&gt;JAVA-4034&lt;/del&gt;&lt;/a&gt; Refactor read/write retries to accommodate for both `PoolClearedError` and CSOT (#782)&lt;/p&gt;

&lt;p&gt;Changes in this commit do the following two major things:&lt;/p&gt;

&lt;p&gt;1) These changes make selecting a server (`binding.get*ConnectionSource`)&lt;br/&gt;
and checking out a connection (`source.getConnection`) part of a retryable operation.&lt;br/&gt;
Such a change makes `MongoConnectionPoolClearedException`s part of the operation,&lt;br/&gt;
thus allowing us to retry the operation when the exception happens.&lt;/p&gt;

&lt;p&gt;2) The retry limit (not more than two attempts) was hardcoded in the driver&apos;s code structure,&lt;br/&gt;
i.e., the code was written in such a way that it was describing the first attempt, then depending&lt;br/&gt;
on the outcome, the code for the second attempt was executed, with the code for the second attempt&lt;br/&gt;
mostly duplicating the code for the first attempt, but having different error handling. Such an approach&lt;br/&gt;
not only negatively affects the code readability, but also prevents changing the number of attempts,&lt;br/&gt;
let alone making decisions on whether to retry based not on an attempt limit.&lt;br/&gt;
The pseudocode in the specifications is also written this way, and at least some other drivers,&lt;br/&gt;
e.g., C#, Rust, took a similar approach to structure the code.&lt;/p&gt;

&lt;p&gt;Changes in this commit represent the outcome of refactoring the code related to the retry logic.&lt;br/&gt;
In the new code the retry logic is decoupled from the logic of a retryable operation as much as possible.&lt;br/&gt;
Since our operations are quite complex and may decide to break retrying in the middle of an attempt,&lt;br/&gt;
e.g., because the server selected in the attempt does not support retries, the operation logic&lt;br/&gt;
is still aware of the fact that it may be retried. However, it is important to understand that&lt;br/&gt;
this awareness is a direct consequence of the business logic. It cannot be gotten rid of&lt;br/&gt;
regardless of the approach taken to structure the code. Operations that have simpler business logic&lt;br/&gt;
can be written in a retry-agnostic way without making changes to the retry framework&lt;br/&gt;
that was added as part of this commit.&lt;/p&gt;

&lt;p&gt;With the changes in this commit, applying the client-side timeout (CSOT) to a retryable operation&lt;br/&gt;
is as simple as replacing the hard retry limit condition with a condition that checks&lt;br/&gt;
whether there is time left for attempting the operation again.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://jira.mongodb.org/browse/JAVA-4034&quot; title=&quot;Refactor read/write retries to accommodate for both PoolClearedError and CSOT&quot; class=&quot;issue-link&quot; data-issue-key=&quot;JAVA-4034&quot;&gt;&lt;del&gt;JAVA-4034&lt;/del&gt;&lt;/a&gt;&lt;br/&gt;
Branch: master&lt;br/&gt;
&lt;a href=&quot;https://github.com/mongodb/mongo-java-driver/commit/c11600db1156d65bbf1db584111f4778aaccafc4&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;https://github.com/mongodb/mongo-java-driver/commit/c11600db1156d65bbf1db584111f4778aaccafc4&lt;/a&gt;&lt;/p&gt;</comment>
                            <comment id="4087560" author="mms-build@10gen.com" created="Mon, 27 Sep 2021 19:41:44 +0000"  >&lt;p&gt; &lt;a href=&quot;https://github.com/stIncMale&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;stIncMale&lt;/a&gt; merged a pull request (&lt;a href=&quot;https://github.com/mongodb/mongo-java-driver/pull/782&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;JAVA-4034 Refactor read write retries to accommodate for both `PoolClearedError` and CSOT&lt;/a&gt;) into the following branch:&lt;br/&gt;
                       master: &lt;a href=&quot;https://github.com/stIncMale/mongo-java-driver/commit/c11600db1156d65bbf1db584111f4778aaccafc4&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;c11600db1156d65bbf1db584111f4778aaccafc4&lt;/a&gt;&lt;/p&gt;
</comment>
                            <comment id="3755004" author="JIRAUSER1258163" created="Tue, 4 May 2021 19:06:32 +0000"  >&lt;p&gt;Currently the retry logic is hardcoded to have at most two attempts (one retry) and is located in the execution order of a command at points after selecting a server and checking out a connection for the first attempt. &lt;tt&gt;MongoConnectionPoolClearedException&lt;/tt&gt; may happen when checking out a connection for the first attempt, therefore we must move the retry logic earlier in the execution order: before checking out a connection for the first attempt, but after selecting a server for the first attempt, as all specifications either explicitly indicate that errors while selecting the server for the first attempt are not retryable, or say nothing about this:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;https://github.com/mongodb/specifications/blob/master/source/retryable-reads/retryable-reads.rst#1-selecting-the-initial-server&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;&lt;em&gt;&quot;When selecting a server for the first attempt of a retryable read command, drivers MUST allow a server selection error to propagate.&quot;&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;https://github.com/mongodb/specifications/blob/master/source/retryable-writes/retryable-writes.rst#executing-retryable-write-commands&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;&lt;em&gt;&quot;When selecting a writable server for the first attempt of a retryable write command, drivers MUST allow a server selection error to propagate.&quot;&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;The &lt;a href=&quot;https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.rst&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;change streams specification&lt;/a&gt; says nothing. I am interpreting this as an implication that rules for retryable reads are applied.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Following are the retryable operations and the relevant specifications:&lt;/p&gt;

&lt;div class=&apos;table-wrap&apos;&gt;
&lt;table class=&apos;confluenceTable&apos;&gt;&lt;tbody&gt;
&lt;tr&gt;
&lt;th class=&apos;confluenceTh&apos;&gt;operation and spec link&lt;/th&gt;
&lt;th class=&apos;confluenceTh&apos;&gt;retry code location&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;a href=&quot;https://github.com/mongodb/specifications/blob/master/source/retryable-reads/retryable-reads.rst&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;read&lt;/a&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt; &lt;a href=&quot;https://github.com/mongodb/mongo-java-driver/blob/7206b7100a3eb22ce7588460de0104c49809d8e2/driver-core/src/main/com/mongodb/internal/operation/CommandOperationHelper.java#L193-L196&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;sync&lt;/a&gt;, &lt;a href=&quot;https://github.com/mongodb/mongo-java-driver/blob/7206b7100a3eb22ce7588460de0104c49809d8e2/driver-core/src/main/com/mongodb/internal/operation/CommandOperationHelper.java#L442-L453&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;async&lt;/a&gt;, see also &lt;tt&gt;CommandOperationHelper.isRetryableException&lt;/tt&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;a href=&quot;https://github.com/mongodb/specifications/blob/master/source/retryable-writes/retryable-writes.rst&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;write&lt;/a&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt; &lt;a href=&quot;https://github.com/mongodb/mongo-java-driver/blob/7206b7100a3eb22ce7588460de0104c49809d8e2/driver-core/src/main/com/mongodb/internal/operation/CommandOperationHelper.java#L583-L586&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;sync&lt;/a&gt;, &lt;a href=&quot;https://github.com/mongodb/mongo-java-driver/blob/7206b7100a3eb22ce7588460de0104c49809d8e2/driver-core/src/main/com/mongodb/internal/operation/CommandOperationHelper.java#L674-L684&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;async&lt;/a&gt;, see also &lt;tt&gt;CommandOperationHelper.isRetryableException&lt;/tt&gt;, &lt;tt&gt;CommandOperationHelper.addRetryableWriteErrorLabel&lt;/tt&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;a href=&quot;https://github.com/mongodb/specifications/blob/master/source/retryable-writes/retryable-writes.rst#supported-write-operations&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;bulk write&lt;/a&gt; and &lt;a href=&quot;https://github.com/mongodb/specifications/blob/master/source/driver-bulk-update.rst&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;bulk API spec&lt;/a&gt; &lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt; &lt;tt&gt;MixedBulkWriteOperation.execute&lt;/tt&gt;, &lt;tt&gt;executeAsync&lt;/tt&gt;, see also &lt;tt&gt;CommandOperationHelper.isRetryableException&lt;/tt&gt;, &lt;tt&gt;CommandOperationHelper.addRetryableWriteErrorLabel&lt;/tt&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;a href=&quot;https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.rst&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;&lt;del&gt;iterate over a change stream cursor&lt;/del&gt;&lt;/a&gt; (turned out, change streams create cursors via the normal read operations, which means nothing needs to be done; see &lt;tt&gt;wrapped.execute&lt;/tt&gt; in &lt;tt&gt;ChangeStreamOperation.execute&lt;/tt&gt; and &lt;tt&gt;AggregateOperationImpl.execute&lt;/tt&gt;)&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt; &lt;tt&gt;ChangeStreamBatchCursor&lt;/tt&gt;, &lt;tt&gt;AsyncChangeStreamBatchCursor&lt;/tt&gt;, see also &lt;tt&gt;ChangeStreamBatchCursorHelper.isRetryableError&lt;/tt&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;


&lt;p&gt;Consider &lt;a href=&quot;https://jira.mongodb.org/browse/DRIVERS-1570&quot; title=&quot;Consider wire version changes when sending equivalent write command on a retry attempt&quot; class=&quot;issue-link&quot; data-issue-key=&quot;DRIVERS-1570&quot;&gt;DRIVERS-1570&lt;/a&gt; and DRIVERS-1815 when doing the changes.&lt;/p&gt;</comment>
                    </comments>
                <issuelinks>
                            <issuelinktype id="10020">
                    <name>Gantt Dependency</name>
                                            <outwardlinks description="has to be done before">
                                        <issuelink>
            <issuekey id="1637148">JAVA-4028</issuekey>
        </issuelink>
                            </outwardlinks>
                                                        </issuelinktype>
                            <issuelinktype id="10620">
                    <name>Issue split</name>
                                                                <inwardlinks description="split from">
                                                        </inwardlinks>
                                    </issuelinktype>
                    </issuelinks>
                <attachments>
                    </attachments>
                <subtasks>
                    </subtasks>
                <customfields>
                                                                                                                                                                                                                        <customfield id="customfield_10011" key="com.atlassian.jira.plugin.system.customfieldtypes:radiobuttons">
                        <customfieldname>Backwards Compatibility</customfieldname>
                        <customfieldvalues>
                                <customfieldvalue key="10038"><![CDATA[Fully Compatible]]></customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                <customfield id="customfield_15850" key="com.atlassian.jira.plugins.jira-development-integration-plugin:devsummary">
                        <customfieldname>Development</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10257" key="com.atlassian.jira.plugin.system.customfieldtypes:radiobuttons">
                        <customfieldname>Documentation Changes</customfieldname>
                        <customfieldvalues>
                                <customfieldvalue key="11861"><![CDATA[Not Needed]]></customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                                                        <customfield id="customfield_10857" key="com.pyxis.greenhopper.jira:gh-epic-link">
                        <customfieldname>Epic Link</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>JAVA-3890</customfieldvalue>
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                            <customfield id="customfield_21553" key="com.atlassian.jira.plugin.system.customfieldtypes:labels">
                        <customfieldname>Quarter</customfieldname>
                        <customfieldvalues>
                                        <label>FY22Q4</label>
    
                        </customfieldvalues>
                    </customfield>
                                                                                            <customfield id="customfield_12550" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
                        <customfieldname>Rank</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>2|hr3ny7:</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10558" key="com.pyxis.greenhopper.jira:gh-global-rank">
                        <customfieldname>Rank (Obsolete)</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>9223372036854775807</customfieldvalue>
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            </customfields>
    </item>
</channel>
</rss>