@savva09
Начинающий .NET-ер

Как корректно завершить webapplication, чтобы вызвался и исполнился до конца IHostLifetime.ApplicationStopping.Register(mymethod)?

Мне нужно обработать завершение приложения. web api asp net core. В частности, отправить всем клиентам по сообщению. Сейчас я делаю это так:
IHostApplicationLifetime host = app.Services.GetRequiredService<IHostApplicationLifetime>();

host.ApplicationStopping.Register(NotifyUsers);

Проблема в том, что метод не успевает отработать. Процесс завершается раньше. Как я завершаю процесс? я пробовал крестик, ctrl+c, красный квадратик в vs. Но отправляется максимум одно сообщение на ctrl+c, и то не всегда.

Я пробовал делать
builder.WebHost.UseShutdownTimeout(TimeSpan.FromMinutes(5));

что разумеется очень много, но все равно не помогает.

Ответом на вопрос будет либо вариант альтернативного решения (я регистрирую не там), либо правильной командой завершения.

Для отправки сообщений используются сервисы из DI. Они также получаются из app.Services
  • Вопрос задан
  • 52 просмотра
Решения вопроса 1
@mvv-rus
Настоящий админ AD и ненастоящий программист
Для ответа на вопрос несколько не хватает информации - как у вас организована реакция на отмену IHostApplicationLifetime.ApplicationStoping (что и как делает регистрируемый callback при отмене), какие сервисы вы используете и как они реагируют на отмену того же маркера.
И IMHO информацию лучше собирать методом проб и ошибок. Самое первое, что вы можете попробовать - это такой вариант. Во-первых, нужно зарегистрировать свой callback последним. А для этого нужно вызвать конструкторы всех сервисов в надежде, чо если они и регистрируют callback на этот маркер, то делают это у себя в конструкторах и только потом регистрировать свой callback (если вы эти сервисы получаете путем внедрения зависимостей через конструктор, это получится автоматически). Во-вторых, нужно выполнить всю работу в своем callback синхронно, в частности, если сообщения отправляются сервисами асинхронно, то подождать завершение каждого (Tasl.WaitAll вам в помощь), а не ждать каждый через await (или явно - используя ContinueWith - но сейчас так никто не делает).
Идея рассчитана на то, что реализация IHostApplicationLifeTime отменяет (ЕМНИПпроверено в исходниках) этот маркер простым Cancel и ждет завершения отмены (и в документации об этом ожидании смутно упомянуто, т.е., это не хак, зависящий от реализации) , а Cancel вызывает все зарегистрированные callback синхронно, в порядке, обратном регистрации (это ЕМНИП тоже документированнное поведение).
Попробуйте для начала так, прежде чем применять более крутые меры (например, подменять реализации IHostLifeTime и IHostApplicationLifetime(UPD: погорячился, эту реализацию подменять нельзя, там обязан быть класс ApplicationLifetime) - технически это реально, но лучше такое оставить на потом).
Если не прокатит, я ответ постараюсь продолжить.

PS По поводу способов закрытия приложения. AFAIK остановка через "красный квадратик" в VS и закрытие окна консоли вызывает просто уничтожение процесса, и это не перехватывается (могу ошибаться, конечно). А вот закрытие по Ctrl+C отлично перехватывается ConsoleLifeTime (обычно испольуемая для консольных приложений реализация IHostLifetime), так что именно этот способ закрытия можно считать штатным. А вообще по жизни, 100% срабатывающих способов реакции на прекращение работы приложения нет - ибо прекращение может быть вызвано такой причной, как пропадание питания (особенно - если вследствие перерубания кабелей топором ;-) ).
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы