Skip to content

CSHARP-3537: CSOT: retryable reads and writes #1717

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

sanych-sun
Copy link
Member

No description provided.

@sanych-sun sanych-sun requested a review from a team as a code owner June 25, 2025 17:00
@sanych-sun sanych-sun requested review from papafe and removed request for a team June 25, 2025 17:00
@sanych-sun sanych-sun requested review from adelinowona and BorisDog and removed request for papafe June 25, 2025 17:04
@@ -88,73 +80,82 @@ public RetryableWriteContext(IWriteBinding binding, bool retryRequested)
public IChannelSourceHandle ChannelSource => _channelSource;
public bool RetryRequested => _retryRequested;

public void DisableRetriesIfAnyWriteRequestIsNotRetryable(IEnumerable<WriteRequest> requests)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As it turned out none of request.IsRetryable is using ConnectionDescription, so I've decided to remove this method and calculate _retryRequested upfront before the context creation.

}
}
}

public void Dispose()
internal async Task InitializeAsync(OperationContext operationContext, IReadOnlyCollection<ServerDescription> deprioritizedServers)
Copy link
Member Author

@sanych-sun sanych-sun Jun 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initialize and InitializeAsync are internal now, because they have retry logic, that is also useful on operation retry, when we replacing the channel. Might need to be renamed though, because OperationExecutor could call this method several times.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it needs a better naming.

catch (Exception ex) when (ShouldThrowOriginalException(ex))
{
throw originalException;
HashSet<ServerDescription> deprioritizedServers = null;
Copy link
Member Author

@sanych-sun sanych-sun Jun 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accordingly to spec's pseudo code we should provide only one previous server on retry in the list of deprioritized servers, but as it was discussed in the feature channel - we ought to maintain the list of previously attempted servers, because the original code was created when there was only 1 retry. At least Java and Python maintain the list as well.

while (true)
{
operationContext.ThrowIfTimedOutOrCanceled();
var server = context.ChannelSource.ServerDescription;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to preserve the server description BEFORE the operation, because in case of exception server's description might be reset, but we need the original one to determinate if the operation could be retried.

{
internal static class OperationContextExtensions
{
public static bool IsOperationTimeoutConfigured(this OperationContext operationContext)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be called IsRootOperationTimeoutConfigured ?
nit: Consider

IsOperationTimeoutConfigured(this OperationContext operationContext) =>
operationContext.GetRootOperationContext().Timeout != Timeout.InfiniteTimeSpan;

Also consider just having IsRootTimeoutConfigured/RootContext property for simplicity.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed OperationContext to have RootContext. Decided not to change the method name though, as we have a single operation, where the timeout might be configured.

}
catch (Exception ex)
{
var innerException = ex is MongoAuthenticationException mongoAuthenticationException ? mongoAuthenticationException.InnerException : ex;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not to continue extracting the exception in ShouldRetryOperation? Just to reuse the code.
Then you also can keep using the When pattern, so more compact code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

return await ExecuteAsync(operationContext, operation, context).ConfigureAwait(false);
try
{
context.Initialize(operationContext, deprioritizedServers);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably need a better naming. Initialize can run only once.

}
}
}

public void Dispose()
internal async Task InitializeAsync(OperationContext operationContext, IReadOnlyCollection<ServerDescription> deprioritizedServers)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it needs a better naming.

@@ -13,17 +13,14 @@
* limitations under the License.
*/

using System.Linq;
using System;
using System.Collections.Generic;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copyright 2010

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -13,6 +13,7 @@
* limitations under the License.
*/

using System.Collections.Generic;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copyright 2010

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@sanych-sun sanych-sun requested a review from BorisDog June 26, 2025 20:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 participants