Проверка работоспособности с использованием DbContext, который все еще настраивается

#c# #asp.net-core #entity-framework-core #health-check

#c# #asp.net-core #entity-framework-core #проверка работоспособности

Вопрос:

Я создал пользовательскую проверку работоспособности, которая вызывает внедренную службу, и эта служба использует DbContext для запроса базы данных для получения некоторой информации. Когда я запустил свое приложение, я получаю следующую ошибку:

Была предпринята попытка использовать контекст во время его настройки. Экземпляр DbContext нельзя использовать внутри OnConfiguring, поскольку на данный момент он все еще настраивается. Это может произойти, если вторая операция запускается в этом контексте до завершения предыдущей операции. Не гарантируется потокобезопасность любых членов экземпляра.

Есть ли способ отложить проверку работоспособности до тех пор, пока DbContext не будет зарегистрирован где-нибудь при запуске?

Ниже приведена моя реализация проверки работоспособности.

 public class HealthCheck : IHealthCheck
{
    public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default(CancellationToken))
    {
        int userCount = dbService.GetUserCount();  // fails in the dbService here

        if (userCount > 0)
            return Task.FromResult(HealthCheckResult.Healthy("A healthy result."));

        return Task.FromResult(new HealthCheckResult(context.Registration.FailureStatus, "An unhealthy result."));
    }
}
 

Вот как он регистрируется при запуске после регистрации моего dbcontext через AddDbContext

 services.AddHealthChecks().AddCheck<HealthCheck>("user_health_check");
 

Комментарии:

1. Когда происходит сбой, загрузка приложения или когда вы запрашиваете конечную точку проверки работоспособности?

2. Как вы получаете свой контекст БД? Ограничена ли область действия службы? Есть ли у вас какие-либо одноэлементные службы, получающие контекст без создания новой области?

3. @SBI действительно оба — конечная точка проверки работоспособности запускается во время загрузки приложения — все в методе ConfigureServices при запуске

4. @JeremyLakeman Да, вводится контекст БД. Нет в одноэлементных службах.

5. Вы также можете изучить возможность использования MapWhen, чтобы ограничить активацию промежуточных программ проверки работоспособности только по запросу. Дополнительная информация здесь .

Ответ №1:

Возможно, вы сможете обойти это, добавив a DbContextCheck с пользовательским запросом? (документы)

Насколько я понимаю, вы можете сделать что-то вроде этого:

 services.AddHealthChecks()
        .AddDbContextCheck<YourDbContext>(customTestQuery:
            (db, cancel) => Task.FromResult(db.Users.Any()));
 

С учетом сказанного, у вас может возникнуть проблема параллелизма с тем, как используется ваш DbContext. Возможно, async выполняется вызов, который не await редактируется, или, может быть, что-то не так с настройкой времени жизни вашего контекста.

Не зная подробностей о том, как вы регистрируете и настраиваете свой dbcontext или как он вводится (или нет) в то, что выглядит как репозиторий ( DbService.GetUserCount() ) Я могу указать вам на некоторую дополнительную документацию об избежании проблем с потоками DbContext и надеюсь, что это полезно.

Комментарии:

1. Ожидать нечего, поскольку служба, использующая dbcontext, не является асинхронной. Что касается проверки AddDbContextCheck, это просто проверка, в порядке ли подключение к БД.

2. Что касается проблем с параллельными потоками dbcontext, я не думаю, что это происходит, поскольку 1) Я не получаю сообщение об ошибке такого типа с несколькими операциями, 2) все DbContexts являются DI’d 3) Я получаю больше сообщений об ошибке «невозможно использовать DbContext, поскольку он все еще настраивается»

3. Немного странно, что вам нужно что-то большее, чем это. Лучше всего протестировать соединение и, самое большее, выполнить быстрый возвращаемый запрос, например, select 1 * from dbo.Users чтобы доказать, что ваше приложение может подключаться и может запрашивать. Какие изменения вы надеетесь обнаружить, просматривая свой репозиторий?

4. Что ж, если вы можете протестировать соединение с помощью запроса, то почему бы не использовать dbcontext, а запрос немного более конкретный, чем select 1? Разве это не должно работать так же?

5. «Решение» (обходной путь, на самом деле) Я предложил использовать ваш dbcontext для выполнения запроса. Чего он не делает, так это использует для этого ваш репозиторий. Я согласен с вами, определенный вами тест, похоже, должен работать. Вы доказали, что получаете аргументы для проверки, как и ожидалось (отладка)? Может быть, посмотрите .AddTypeActivatedCheck(...) . Я немного подозреваю, что эта ошибка возникает у вас при запуске. Я не думаю, что проверяет exec при запуске. Предполагается, что они должны выполняться совместно с отображенной конечной точкой и ее параметрами.