Skip to content

Commit 0be97a7

Browse files
committed
tests(Spanner): Fix flake in transaction scope tests.
Two transaction scope tests modify the same row. Since tests run in parallel, on ocassion the transaction for one is aborted. The retry mechanism we had only looks at Spanner exceptions, but since these tests are testing System.Transactions integration, the exception we get is System.Transactions.TransactionAbortedException. This commit modifies the existing retry mechanism to accept custom retry conditions so that we can retry on these cases.
1 parent dea2c67 commit 0be97a7

File tree

2 files changed

+10
-8
lines changed

2 files changed

+10
-8
lines changed

apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data.CommonTesting/RetryHelpers.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,21 @@ public static Task<int> ExecuteNonQueryAsyncWithRetry(this SpannerCommand comman
4747
/// <summary>
4848
/// Executes the given action, retrying once if the first attempt is aborted.
4949
/// </summary>
50-
public static void ExecuteWithRetry(Action action) => ExecuteWithRetryImpl(() => { action(); return 0; });
50+
public static void ExecuteWithRetry(Action action, Func<Exception, bool> shouldRetry = null) =>
51+
ExecuteWithRetryImpl(() => { action(); return 0; }, shouldRetry);
5152

5253
/// <summary>
5354
/// Executes the given asynchronous action, retrying once if the first attempt is aborted.
5455
/// </summary>
55-
public static Task ExecuteWithRetryAsync(Func<Task> action) => ExecuteWithRetryAsyncImpl(async () => { await action(); return 0; });
56+
public static Task ExecuteWithRetryAsync(Func<Task> action, Func<Exception, bool> shouldRetry = null) =>
57+
ExecuteWithRetryAsyncImpl(async () => { await action(); return 0; }, shouldRetry);
5658

5759
private static int _calls;
5860
private static int _retries;
5961

6062
// TODO: Move this retry code into production code, so that everyone can use it.
6163

62-
private static T ExecuteWithRetryImpl<T>(Func<T> func)
64+
private static T ExecuteWithRetryImpl<T>(Func<T> func, Func<Exception, bool> shouldRetry = null)
6365
{
6466
Interlocked.Increment(ref _calls);
6567

@@ -76,15 +78,15 @@ private static T ExecuteWithRetryImpl<T>(Func<T> func)
7678
{
7779
return func();
7880
}
79-
catch (SpannerException e) when (attempt.ShouldRetry(e))
81+
catch (Exception e) when (attempt.ShouldRetry(e) || (shouldRetry?.Invoke(e) ?? false))
8082
{
8183
attempt.Backoff(default);
8284
}
8385
}
8486
throw new InvalidOperationException("Bug in GAX retry handling: finished sequence of attempts");
8587
}
8688

87-
private static async Task<T> ExecuteWithRetryAsyncImpl<T>(Func<Task<T>> func)
89+
private static async Task<T> ExecuteWithRetryAsyncImpl<T>(Func<Task<T>> func, Func<Exception, bool> shouldRetry = null)
8890
{
8991
Interlocked.Increment(ref _calls);
9092

@@ -101,7 +103,7 @@ private static async Task<T> ExecuteWithRetryAsyncImpl<T>(Func<Task<T>> func)
101103
{
102104
return await func();
103105
}
104-
catch (SpannerException e) when (attempt.ShouldRetry(e))
106+
catch (Exception e) when (attempt.ShouldRetry(e) || (shouldRetry?.Invoke(e) ?? false))
105107
{
106108
await attempt.BackoffAsync(default);
107109
}

apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data.IntegrationTests/TransactionScopeTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ await RetryHelpers.ExecuteWithRetryAsync(async () =>
209209
await UpdateValueAsync(writeConnection);
210210
scope.Complete();
211211
}
212-
});
212+
}, ex => ex is TransactionAbortedException);
213213
}
214214

215215
[Fact]
@@ -224,7 +224,7 @@ public void OneWrite_Success()
224224
UpdateValue(writeConnection);
225225
scope.Complete();
226226
}
227-
});
227+
}, ex => ex is TransactionAbortedException);
228228
}
229229

230230
[Fact]

0 commit comments

Comments
 (0)