Новый Интерфейс IHostedLifecycleService в .NET 8
Вчера я писал про конкурентный запуск и остановку hosted-сервисов в .NET 8, однако этим нововведения для размещённых сервисов не ограничиваются.
В пространство имён Microsoft.Extensions.Hosting добавлен интерфейс IHostedLifecycleService. Он наследуется от IHostedService, расширяя его методами для новых событий жизненного цикла, которые происходят до или после существующих методов StartAsync и StopAsync соответственно:
- StartingAsync,
- StartedAsync,
- StoppingAsync,
- StoppedAsync.
Метод StartingAsync будет выполняться очень рано в жизненном цикле приложения, прежде чем StartAsync будет вызван для любого зарегистрированного размещённого сервиса. Это может использоваться для выполнения некоторых очень ранних проверок перед запуском приложения, таких как проверка критических требований или наличия зависимостей. Это позволит приложению потенциально завершаться сбоем при запуске до того, как какие-либо размещённые сервисы начнут выполнять свою основную рабочую нагрузку. Другие варианты использования включают «предварительный нагрев» и инициализацию синглтонов и других состояний, используемых приложением.
StartedAsync будет вызываться в реализациях после завершения всех методов StartAsync для зарегистрированных размещённых сервисов. Его можно использовать для проверки состояния или условий приложения непосредственно перед пометкой приложения как успешно запущенного.
StoppingAsync и StoppedAsync работают аналогично во время завершения работы приложения и предоставляют расширенные перехватчики для проверок до и после завершения работы.
Кроме того, в HostOptions добавлена новая опция StartupTimeout, позволяющая предоставить TimeSpan, который будет контролировать максимальное время, разрешённое для запуска всех размещённых сервисов. При установке в небесконечное (по умолчанию) значение токен отмены, передаваемый в события жизненного цикла запуска, будет отменяться по заданному тайм-ауту.
Использование интерфейса
Довольно распространённая работа перед запуском приложения — инициализация БД. В таких средах, как CI, нам может потребоваться создавать фиктивную БД и заполнить её тестовыми данными. Одним из возможных вариантов решения является использование размещённых сервисов. В .NET 8, если сервисы запускаются конкурентно, может возникнуть проблема, когда один сервис зависит от результатов работы другого (например, от наличия инициализированной БД). Поэтому мы можем использовать IHostedLifecycleService, чтобы инициализировать базу до того, как она будет использована каким-либо другим сервисом:
public class ServiceA : IHostedService,Здесь ServiceA реализует IHostedLifecycleService и инициализирует БД на самом раннем этапе жизненного цикла приложения, до любой из основных рабочих нагрузок. ServiceB, производный от BackgroundService, теперь может безопасно использовать БД, т.к. ExecuteAsync вызывается базовой реализацией StartAsync. Т.е. он не вызывается до тех пор, пока не будут завершены все методы StartingAsync для зарегистрированных сервисов. Также теперь не имеет значения, в каком порядке сервисы регистрируются в DI-контейнере:
IHostedLifecycleService
{
public Task StartingAsync(CancellationToken ct)
{
// инициализация БД
return Task.CompletedTask;
}
// реализация других методов
}
public class ServiceB : BackgroundService
{
protected override Task ExecuteAsync(
CancellationToken stoppingToken)
{
// использование БД
return Task.CompletedTask;
}
}
builder.Services.AddHostedService<ServiceB>();Источник: https://www.stevejgordon.co.uk/introducing-the-new-ihostedlifecycleservice-interface-in-dotnet-8
builder.Services.AddHostedService<ServiceA>();