Public Access
Server: start a retried write transaction from the database, not from the attempt that failed
This commit is contained in:
1 parent
36fb0817a4
commit
b2516ca7fb
8 files changed
+173
-21
No files matched your search
@@ -0,0 +1,43 @@
|
||||
using System.Data.Common;
|
||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
|
||||
namespace DodoSSH.Api.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Fails the next commit the way a connection dropped on the way to the server would, when asked to.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Before the commit reaches the database, so the transaction is rolled back — which is what a lost commit
|
||||
/// looks like from the server's side — and with a <see cref="TimeoutException"/>, which the retrying
|
||||
/// execution strategy treats as transient. That is the only way to watch a retry happen against a real
|
||||
/// database, and the retry is the thing worth watching: see <c>FreshAttempts</c>.
|
||||
/// </remarks>
|
||||
internal sealed class FlakyCommits : DbTransactionInterceptor
|
||||
{
|
||||
private int armed;
|
||||
|
||||
private int failed;
|
||||
|
||||
/// <summary>How many commits this has failed.</summary>
|
||||
internal int Failed => Volatile.Read(ref failed);
|
||||
|
||||
/// <summary>Makes the next commit, whoever's it is, fail once.</summary>
|
||||
internal void FailNextCommit() => Interlocked.Exchange(ref armed, 1);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ValueTask<InterceptionResult> TransactionCommittingAsync(
|
||||
DbTransaction transaction,
|
||||
TransactionEventData eventData,
|
||||
InterceptionResult result,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (Interlocked.Exchange(ref armed, 0) == 1)
|
||||
{
|
||||
Interlocked.Increment(ref failed);
|
||||
|
||||
throw new TimeoutException("The commit was lost on its way to the server.");
|
||||
}
|
||||
|
||||
return base.TransactionCommittingAsync(transaction, eventData, result, cancellationToken);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user