Come arrestare il servizio ASP.NET quando un servizio in background si arresta in modo anomalo

Come arrestare il servizio ASP.NET quando un servizio in background si arresta in modo anomalo

Quando un servizio in background genera un'eccezione in ExecuteAsync() e interrompe l'esecuzione, non accade nulla. Non vengono registrati errori e il servizio ASP.NET continua a essere eseguito.

Cosa succede se si desidera interrompere il servizio ASP.NET quando il servizio in background si arresta in modo anomalo?

Per farlo, dovrai gestire le eccezioni nel servizio in background e chiamare IHostApplicationLifetime.StopApplication(), in questo modo:

public class DatabaseLoggerService : BackgroundService
{
	private IHostApplicationLifetime HostApplicationLifetime;
	public DatabaseLoggerService(IHostApplicationLifetime hostApplicationLifetime)
	{
		HostApplicationLifetime = hostApplicationLifetime;
	}

	protected async override Task ExecuteAsync(CancellationToken stoppingToken)
	{
		while(!stoppingToken.IsCancellationRequested)
		{
			try
			{
				//Execute the important background activity in a try/catch
				await BulkInsert(stoppingToken);
			}
			catch(TaskCanceledException canceledEx)
			{
				//Service was stopped, so exit the loop
				return;
			}
			catch (Exception fatalException)
			{
				//Handle fatal exceptions appropriately based on your requirements
				//Then initiate a graceful shutdown
				HostApplicationLifetime.StopApplication();
				return;
			}
		}
	}
	//rest of class
}
Code language: C# (cs)

Nota:dopo aver avviato l'arresto, esci da ExecuteAsync() con "return" o "throw". StopApplication() alla fine interromperà il servizio in background, ma non è sempre immediato. Ciò significa che le condizioni del ciclo potrebbero essere ancora vere e il ciclo potrebbe continuare a essere eseguito. Non lasciare che questa sia una possibilità, esci dal metodo in modo esplicito.

La chiamata di HostApplicationLifetime.StopApplication() avvia un arresto regolare. Il framework chiamerà StopAsync() in tutti i servizi in background in esecuzione.

Non chiamare Environment.Exit(). Può sembrare che stia eseguendo un arresto regolare, ma non lo è. Se lo usi, potresti incorrere in problemi imprevisti. Utilizzare invece IHostApplicationLifetime.StopApplication().

Inietta la dipendenza IHostApplicationLifetime

Dovrai inserire la dipendenza IHostApplicationLifetime nel tuo servizio in background per poterlo utilizzare. IHostApplicationLifetime è registrato dal framework, quindi è sempre disponibile per l'uso.

Per iniettarlo in dipendenza, prima aggiungilo come parametro del costruttore nel tuo servizio in background:

public DatabaseLoggerService(IHostApplicationLifetime hostApplicationLifetime)
Code language: C# (cs)

Nella maggior parte degli scenari, non dovrai fare nulla di speciale. Puoi semplicemente registrare il tuo servizio in background utilizzando AddHostedService() e il framework risolverà automaticamente la dipendenza IHostApplicationLifetime:

public class Startup
{
	public void ConfigureServices(IServiceCollection services)
	{
		services.AddHostedService<DatabaseLoggerService>();
	   
	   //rest of method
	}
	
	//rest of class
}
Code language: C# (cs)

Se devi creare e registrare manualmente il servizio in background, ad esempio se lo stai passando come riferimento ai controller, dovrai risolvere manualmente il servizio IHostApplicationLifetime, in questo modo:

public class Startup
{
	public void ConfigureServices(IServiceCollection services)
	{
		services.AddSingleton<ILoggerService>(sp =>
		{
			var hostAppLifetime = sp.GetService<IHostApplicationLifetime>();
			return new DatabaseLoggerService(hostAppLifetime);
		});

		services.AddHostedService(sp => sp.GetService<ILoggerService>() as DatabaseLoggerService );
	   
	   //rest of method
	}
	
	//rest of class
}
Code language: C# (cs)