Skip to content

Commit 21f8c16

Browse files
committed
CSHARP-3919: Drivers should retry operations if connection handshake fails
1 parent 8c53008 commit 21f8c16

File tree

168 files changed

+2170
-49
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

168 files changed

+2170
-49
lines changed

src/MongoDB.Driver.Core/Core/Operations/RetryableReadContext.cs

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -177,46 +177,30 @@ public void ReplaceChannelSource(IChannelSourceHandle channelSource)
177177
private void Initialize(CancellationToken cancellationToken)
178178
{
179179
_channelSource = _binding.GetReadChannelSource(cancellationToken);
180-
var serverDescription = _channelSource.ServerDescription;
181180

182181
try
183182
{
184183
_channel = _channelSource.GetChannel(cancellationToken);
185184
}
186-
catch (MongoConnectionPoolPausedException)
185+
catch (Exception ex) when (RetryableReadOperationExecutor.ShouldConnectionAcquireBeRetried(this, ex))
187186
{
188-
if (RetryableReadOperationExecutor.ShouldConnectionAcquireBeRetried(this, serverDescription))
189-
{
190-
ReplaceChannelSource(_binding.GetReadChannelSource(cancellationToken));
191-
ReplaceChannel(_channelSource.GetChannel(cancellationToken));
192-
}
193-
else
194-
{
195-
throw;
196-
}
187+
ReplaceChannelSource(_binding.GetReadChannelSource(cancellationToken));
188+
ReplaceChannel(_channelSource.GetChannel(cancellationToken));
197189
}
198190
}
199191

200192
private async Task InitializeAsync(CancellationToken cancellationToken)
201193
{
202194
_channelSource = await _binding.GetReadChannelSourceAsync(cancellationToken).ConfigureAwait(false);
203-
var serverDescription = _channelSource.ServerDescription;
204195

205196
try
206197
{
207198
_channel = await _channelSource.GetChannelAsync(cancellationToken).ConfigureAwait(false);
208199
}
209-
catch (MongoConnectionPoolPausedException)
200+
catch (Exception ex) when (RetryableReadOperationExecutor.ShouldConnectionAcquireBeRetried(this, ex))
210201
{
211-
if (RetryableReadOperationExecutor.ShouldConnectionAcquireBeRetried(this, serverDescription))
212-
{
213-
ReplaceChannelSource(await _binding.GetReadChannelSourceAsync(cancellationToken).ConfigureAwait(false));
214-
ReplaceChannel(await _channelSource.GetChannelAsync(cancellationToken).ConfigureAwait(false));
215-
}
216-
else
217-
{
218-
throw;
219-
}
202+
ReplaceChannelSource(await _binding.GetReadChannelSourceAsync(cancellationToken).ConfigureAwait(false));
203+
ReplaceChannel(await _channelSource.GetChannelAsync(cancellationToken).ConfigureAwait(false));
220204
}
221205
}
222206
}

src/MongoDB.Driver.Core/Core/Operations/RetryableReadOperationExecutor.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
using System.Threading;
1818
using System.Threading.Tasks;
1919
using MongoDB.Driver.Core.Bindings;
20-
using MongoDB.Driver.Core.Servers;
2120

2221
namespace MongoDB.Driver.Core.Operations
2322
{
@@ -115,9 +114,11 @@ public static async Task<TResult> ExecuteAsync<TResult>(IRetryableReadOperation<
115114
}
116115
}
117116

118-
public static bool ShouldConnectionAcquireBeRetried(RetryableReadContext context, ServerDescription serverDescription)
117+
public static bool ShouldConnectionAcquireBeRetried(RetryableReadContext context, Exception ex)
119118
{
120-
return context.RetryRequested && !context.Binding.Session.IsInTransaction;
119+
// According the spec error during handshake should be handle according to RetryableReads logic
120+
var innerException = ex is MongoAuthenticationException mongoAuthenticationException ? mongoAuthenticationException.InnerException : ex;
121+
return context.RetryRequested && !context.Binding.Session.IsInTransaction && RetryabilityHelper.IsRetryableReadException(innerException);
121122
}
122123

123124
// private static methods

src/MongoDB.Driver.Core/Core/Operations/RetryableWriteContext.cs

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -201,17 +201,10 @@ private void Initialize(CancellationToken cancellationToken)
201201
{
202202
_channel = _channelSource.GetChannel(cancellationToken);
203203
}
204-
catch (MongoConnectionPoolPausedException)
204+
catch (Exception ex) when (RetryableWriteOperationExecutor.ShouldConnectionAcquireBeRetried(this, serverDescription, ex))
205205
{
206-
if (RetryableWriteOperationExecutor.ShouldConnectionAcquireBeRetried(this, serverDescription))
207-
{
208-
ReplaceChannelSource(_binding.GetWriteChannelSource(cancellationToken));
209-
ReplaceChannel(_channelSource.GetChannel(cancellationToken));
210-
}
211-
else
212-
{
213-
throw;
214-
}
206+
ReplaceChannelSource(_binding.GetWriteChannelSource(cancellationToken));
207+
ReplaceChannel(_channelSource.GetChannel(cancellationToken));
215208
}
216209
}
217210

@@ -224,17 +217,10 @@ private async Task InitializeAsync(CancellationToken cancellationToken)
224217
{
225218
_channel = await _channelSource.GetChannelAsync(cancellationToken).ConfigureAwait(false);
226219
}
227-
catch (MongoConnectionPoolPausedException)
220+
catch (Exception ex) when (RetryableWriteOperationExecutor.ShouldConnectionAcquireBeRetried(this, serverDescription, ex))
228221
{
229-
if (RetryableWriteOperationExecutor.ShouldConnectionAcquireBeRetried(this, serverDescription))
230-
{
231-
ReplaceChannelSource(await _binding.GetWriteChannelSourceAsync(cancellationToken).ConfigureAwait(false));
232-
ReplaceChannel(await _channelSource.GetChannelAsync(cancellationToken).ConfigureAwait(false));
233-
}
234-
else
235-
{
236-
throw;
237-
}
222+
ReplaceChannelSource(await _binding.GetWriteChannelSourceAsync(cancellationToken).ConfigureAwait(false));
223+
ReplaceChannel(await _channelSource.GetChannelAsync(cancellationToken).ConfigureAwait(false));
238224
}
239225
}
240226
}

src/MongoDB.Driver.Core/Core/Operations/RetryableWriteOperationExecutor.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,12 +127,16 @@ public static async Task<TResult> ExecuteAsync<TResult>(IRetryableWriteOperation
127127
}
128128
}
129129

130-
public static bool ShouldConnectionAcquireBeRetried(RetryableWriteContext context, ServerDescription serverDescription)
130+
public static bool ShouldConnectionAcquireBeRetried(RetryableWriteContext context, ServerDescription serverDescription, Exception exception)
131131
{
132+
var innerException = exception is MongoAuthenticationException mongoAuthenticationException ? mongoAuthenticationException.InnerException : exception;
133+
134+
// According the spec error during handshake should be handle according to RetryableReads logic
132135
return context.RetryRequested &&
133136
AreRetryableWritesSupported(serverDescription) &&
134137
context.Binding.Session.Id != null &&
135-
!context.Binding.Session.IsInTransaction;
138+
!context.Binding.Session.IsInTransaction &&
139+
RetryabilityHelper.IsRetryableReadException(innerException);
136140
}
137141

138142
// private static methods

tests/MongoDB.Driver.Tests/Specifications/retryable-reads/RetryableReadsTestRunner.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ public class TestCaseFactory : JsonDrivenTestCaseFactory
481481
#endregion
482482
// protected properties
483483
// the path is "retryable-reads" but the namespace is "retryable_reads"
484-
protected override string PathPrefix => "MongoDB.Driver.Tests.Specifications.retryable_reads.tests.";
484+
protected override string PathPrefix => "MongoDB.Driver.Tests.Specifications.retryable_reads.tests.legacy";
485485

486486
// protected methods
487487
protected override IEnumerable<JsonDrivenTestCase> CreateTestCases(BsonDocument document)
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System.Collections.Generic;
17+
using MongoDB.Bson;
18+
using MongoDB.Bson.TestHelpers.JsonDrivenTests;
19+
using MongoDB.Driver.Core.TestHelpers.Logging;
20+
using MongoDB.Driver.Tests.UnifiedTestOperations;
21+
using Xunit;
22+
using Xunit.Abstractions;
23+
24+
namespace MongoDB.Driver.Tests.Specifications.retryable_reads
25+
{
26+
[Trait("Category", "SupportLoadBalancing")]
27+
[Trait("Category", "Serverless")]
28+
public sealed class RetryableReadsUnifiedTestRunner : LoggableTestClass
29+
{
30+
// public constructors
31+
public RetryableReadsUnifiedTestRunner(ITestOutputHelper testOutputHelper)
32+
: base(testOutputHelper)
33+
{
34+
}
35+
36+
// public methods
37+
[SkippableTheory]
38+
[ClassData(typeof(TestCaseFactory))]
39+
public void Run(JsonDrivenTestCase testCase)
40+
{
41+
using (var runner = new UnifiedTestRunner())
42+
{
43+
runner.Run(testCase);
44+
}
45+
}
46+
47+
// nested types
48+
public class TestCaseFactory : JsonDrivenTestCaseFactory
49+
{
50+
// protected properties
51+
protected override string PathPrefix => "MongoDB.Driver.Tests.Specifications.retryable_reads.tests.unified";
52+
53+
// protected methods
54+
protected override IEnumerable<JsonDrivenTestCase> CreateTestCases(BsonDocument document)
55+
{
56+
foreach (var testCase in base.CreateTestCases(document))
57+
{
58+
foreach (var async in new[] { false, true })
59+
{
60+
var name = $"{testCase.Name}:async={async}";
61+
var test = testCase.Test.DeepClone().AsBsonDocument.Add("async", async);
62+
yield return new JsonDrivenTestCase(name, testCase.Shared, test);
63+
}
64+
}
65+
}
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)