Существует множество ресурсов, в которых обсуждается, как обрабатывать длительную инициализацию (например, миграцию базы данных) в ASP.Net Core WebApp (см. здесь или здесь , для пример). Текущий консенсус, по-видимому, заключается в том, чтобы выполнить такую инициализацию в Program.cs после того, как IWebHost был собран, но до его фактического запуска.
Это прекрасно работает при запуске WebApp в консоли или в IIS. Но при работе в качестве службы Windows у меня истекает 30-секундный тайм-аут ОС.
Вот некоторый код, который иллюстрирует проблему. Полный (но все же минимальный) пример можно найти здесь .
public class Program
{
public static void Main(string[] args)
{
var host = CreateWebHostBuilder(args).Build();
if (args.Contains("--initialize"))
LongRunningInitialization(host);
if (args.Contains("--console"))
host.Run();
else
host.RunAsService();
}
private static void LongRunningInitialization(IWebHost host)
{
var logger = host.Services.GetRequiredService<ILogger<Program>>();
logger.LogInformation("Doing long-running initialization (sleep for 35 seconds)");
Task.Delay(35000).Wait();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
public class Startup
{
public void Configure(IApplicationBuilder app)
=> app.Run(async (context) => await context.Response.WriteAsync("Hello World!"));
}
public class MyWebHostService : WebHostService
{
private readonly ILogger<MyWebHostService> Logger;
public MyWebHostService(IWebHost host)
: base(host)
{
AutoLog = true;
CanHandlePowerEvent = false;
CanHandleSessionChangeEvent = false;
CanPauseAndContinue = false;
CanShutdown = false;
CanStop = true;
ServiceName = "MyTestService";
Logger = host.Services.GetRequiredService<ILogger<MyWebHostService>>();
}
protected override void OnStarting(string[] args)
{
Logger.LogInformation("MyWebHostService.OnStarting");
// This doesn't help...
RequestAdditionalTime(60000);
base.OnStarting(args);
}
protected override void OnStarted()
{
Logger.LogInformation("MyWebHostService.OnStarted");
base.OnStarted();
}
}
public static class MyWebHostServiceExtensions
{
public static void RunAsService(this IWebHost host)
{
var myWebHostService = new MyWebHostService(host);
ServiceBase.Run(myWebHostService);
}
}
Если я зарегистрируюсь и запустлю этот сервис следующим образом:
sc.exe create MyTestService DisplayName= "My Test Service" binpath= "....\WindowsServiceStartupTest.dll --initialize"
sc.exe start MyTestService
Я получаю следующее сообщение об ошибке:
Служба не ответила на запрос запуска или управления своевременно.
Без длительной инициализации служба запускается нормально.
Обратите внимание, что в переопределении OnStarting
я пытаюсь увеличить время ожидания, но это не работает. Похоже, OnStarting
вызывается после длительной инициализации (слишком поздно).
Итак, мой вопрос: как правильно запустить длительную инициализацию для Windows Server WebApp? Есть ли способ запросить дополнительное время у ОС ранее в процессе запуска?