Я получаю временный сбой с MySQL и MariaDB

Я работаю над простым веб-API, который использует MySQL в качестве базы данных. Это довольно просто:

      var builder = WebApplication.CreateBuilder(args);
builder
    .Services
    .AddDbContext<RequestContext>(options =>
    {
        options
            .UseMySql(builder.Configuration["ConnectionStrings:Requests"], new MySqlServerVersion(new Version()))
            .EnableSensitiveDataLogging()
            .EnableDetailedErrors();
    })
var app = builder.Build();
app
    .UseHsts()
    .UseHttpsRedirection()
    .UseDefaultFiles();
app
    .Use(async (HttpContext context, Func<Task> next) =>
    {
        context.Request.EnableBuffering();
        context.Request.Body.Position = 0;
        await next();
        var db = context.RequestServices.GetRequiredService<RequestContext>();
        string headers = string.Join("\r\n", context.Request.Headers.Select(r => $"{r.Key} = {r.Value}"));
        string body = await new StreamReader(context.Request.Body).ReadToEndAsync();
        var rec = new Request()
        {
            Host = context.Request.Host.Host,
            Port = context.Connection.LocalPort,
            IPAddress = context.Connection.RemoteIpAddress ?? IPAddress.None,
            Url = context.Request.GetEncodedUrl(),
            Method = context.Request.Method,
            Headers = headers,
            Body = body,
            Valid = context.Response.StatusCode < 400
        };
        db.Requests.Add(rec);
        await db.SaveChangesAsync();
    });
... (Several endpoints after this.) ...

Идея проста. Это метод промежуточного программного обеспечения, который записывает все запросы в базу данных как «Действительный» или «Недействительный», в зависимости от кода состояния в ответе. Этот API может получать около 10 запросов в час, поэтому он должен работать. За исключением того, что это не...

      MySqlException: Connect Timeout expired.
MySqlConnector.MySqlConnection.CreateSessionAsync(ConnectionPool pool, int startTickCount, Activity activity, Nullable<IOBehavior> ioBehavior, CancellationToken cancellationToken) in MySqlConnection.cs
System.Threading.Tasks.ValueTask<TResult>.get_Result()
MySqlConnector.MySqlConnection.OpenAsync(Nullable<IOBehavior> ioBehavior, CancellationToken cancellationToken) in MySqlConnection.cs
MySqlConnector.MySqlConnection.Open() in MySqlConnection.cs
Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnection(bool errorsExpected)
Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternal(bool errorsExpected)
Microsoft.EntityFrameworkCore.Storage.RelationalConnection.Open(bool errorsExpected)
Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlRelationalConnection.Open(bool errorsExpected)
Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlDatabaseCreator+<>c__DisplayClass18_0.<Exists>b__0(DateTime giveUp)
Microsoft.EntityFrameworkCore.ExecutionStrategyExtensions+<>c__DisplayClass12_0<TState, TResult>.<Execute>b__0(DbContext _, TState s)
Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.Execute<TState, TResult>(TState state, Func<DbContext, TState, TResult> operation, Func<DbContext, TState, ExecutionResult<TResult>> verifySucceeded)

Это одно из исключений, которые я получаю, если я их получаю. Иногда действие выполняется, но в базу данных ничего не записывается. И иногда я получаю этот тайм-аут, который также включает эту строку:

      InvalidOperationException: An exception has been raised that is likely due to a transient failure. Consider enabling transient error resiliency by adding 'EnableRetryOnFailure()' to the 'UseMySql' call.

Проблема в том, что я использую ту же базу данных в консольном приложении, где она прекрасно работает. И быстро. Но в этом веб-API, используя ту же строку подключения, я просто получаю это исключение или не записываю никаких записей. И теперь я в тупике.
Я делаю что-то не так, но это ведение журнала запросов является требованием для этого проекта. Что еще более раздражает, этот проект был впервые разработан в .NET 6.0 с EF6 и Pomelo 6.0.2. Но ему нужно перейти на .NET 7, поэтому я использую EF7 и Pomelo 7.0.0-silver.1, и он снова и снова дает сбой. Ситуация становится настолько плохой, что я всерьез подумываю вернуться к .NET 6.0 со старой структурой EF6.
Ошибки, похоже, находятся в пакете Pomelo и в пакете MySqlConnector, который нужен Pomelo.
Кстати, добавлениев UseMySql() просто замедляет его сбой. И я не знаю, почему производительность в моем веб-API такая плохая, в то время как у меня нет проблем в моем консольном приложении...

1 ответ

Если вы получаете всего несколько запросов в час, вы также можете сделать

      connect
perform the inserts and any related actions
disconnect

Предположение: время ожидания соединения истекло, но пакет скрывает эту ошибку более загадочным «EnableRetryOnFailure». Автоматическое повторное подключение может привести к испорченным транзакциям.

Другие вопросы по тегам