Skip to content

Commit

Permalink
Fix the isolation level for authentication state storage transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
gunndabad committed Dec 1, 2023
1 parent 8d7b16d commit a3247b2
Showing 1 changed file with 14 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Npgsql;
using Polly;
using TeacherIdentity.AuthServer.Models;

namespace TeacherIdentity.AuthServer.State;
Expand Down Expand Up @@ -38,52 +37,33 @@ public DbAuthenticationStateProvider(

_transaction ??= await CreateTransaction();

var retryPolicy = Policy
.Handle<InvalidOperationException>(IsPostgresSerializationError)
.RetryAsync(
3,
onRetryAsync: async (ex, retryCount) =>
{
// Transaction will be aborted at this point - create a new one
await _transaction.DisposeAsync();
_transaction = await CreateTransaction();
});

if (httpContext.Request.Query.TryGetValue(AuthenticationStateMiddleware.IdQueryParameterName, out var asidStr) &&
Guid.TryParse(asidStr, out var journeyId) &&
userJourneyIds.Contains(journeyId))
{
return await retryPolicy.ExecuteAsync(async () =>
{
using var suppressScope = SentryErrors.Suppress(IsPostgresSerializationError);
var dbAuthState = await _dbContext.AuthenticationStates.FromSqlInterpolated(
$"select * from authentication_states where journey_id = {journeyId} for update")
.SingleOrDefaultAsync();

var dbAuthState = await _dbContext.AuthenticationStates.FromSqlInterpolated(
$"select * from authentication_states where journey_id = {journeyId} for update")
.SingleOrDefaultAsync();

if (dbAuthState is not null)
if (dbAuthState is not null)
{
try
{
try
{
return AuthenticationState.Deserialize(dbAuthState.Payload);
}
catch (Exception ex)
{
_logger.LogError(ex, $"Failed deserializing {nameof(AuthenticationState)}.");
}
return AuthenticationState.Deserialize(dbAuthState.Payload);
}
catch (Exception ex)
{
_logger.LogError(ex, $"Failed deserializing {nameof(AuthenticationState)}.");
}
}

return null;
});
return null;
}

return null;

static bool IsPostgresSerializationError(Exception ex) =>
ex.InnerException is PostgresException pex && pex.SqlState == PostgresErrorCodes.SerializationFailure;

Task<IDbContextTransaction> CreateTransaction() =>
_dbContext.Database.BeginTransactionAsync(System.Data.IsolationLevel.RepeatableRead);
_dbContext.Database.BeginTransactionAsync(System.Data.IsolationLevel.ReadCommitted);
}

public async Task SetAuthenticationState(HttpContext httpContext, AuthenticationState authenticationState)
Expand Down

0 comments on commit a3247b2

Please sign in to comment.