Note
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier les répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de changer de répertoire.
Conseil / Astuce
Ce contenu est un extrait du livre électronique 'Architecture des microservices .NET pour les applications .NET conteneurisées', disponible sur .NET Docs ou en tant que PDF téléchargeable gratuitement, lisible hors ligne.
Les tâches en arrière-plan et les travaux planifiés sont quelque chose que vous devrez peut-être utiliser dans n’importe quelle application, qu’elle suive ou non le modèle d’architecture des microservices. La différence lors de l’utilisation d’une architecture de microservices est que vous pouvez implémenter la tâche en arrière-plan dans un processus/conteneur distinct pour l’hébergement afin de pouvoir la mettre à l’échelle en fonction de vos besoins.
D’un point de vue générique, dans .NET, nous avons appelé ce type de tâches Hosted Services, car il s’agit de services/logiques que vous hébergez dans votre hôte/application/microservice. Notez que dans ce cas, le service hébergé signifie simplement une classe avec la logique de tâche en arrière-plan.
Étant donné que .NET Core 2.0, le framework fournit une nouvelle interface nommée IHostedService vous permettant d’implémenter facilement des services hébergés. L’idée de base est que vous pouvez inscrire plusieurs tâches en arrière-plan (services hébergés) qui s’exécutent en arrière-plan pendant que votre hôte web ou hôte est en cours d’exécution, comme illustré dans l’image 6-26.

Figure 6-26. Utilisation d’IHostedService dans un hébergeur Web par opposition à un hébergeur
ASP.NET Core 1.x et 2.x prend en charge IWebHost pour les traitements en arrière-plan dans les applications web. .NET Core 2.1 et versions ultérieures prennent en charge les processus en arrière-plan IHost avec des applications console simples. Notez la différence entre WebHost et Host.
Une WebHost (classe de base implémentant IWebHost) dans ASP.NET Core 2.0 est l’artefact d’infrastructure que vous utilisez pour fournir des fonctionnalités de serveur HTTP à votre processus, par exemple lorsque vous implémentez une application web MVC ou un service d’API web. Il fournit toutes les nouvelles qualités d’infrastructure dans ASP.NET Core, ce qui vous permet d’utiliser l’injection de dépendances, d’insérer des intergiciels dans le pipeline de requête et similaires. Le WebHost utilise ces mêmes IHostedServices pour les tâches en arrière-plan.
Une Host (classe de base implémentant IHost) a été introduite dans .NET Core 2.1. En fait, un Host vous permet d’avoir une infrastructure similaire à celle que vous avez avec WebHost (injection de dépendances, services hébergés, etc.), mais dans ce cas, vous souhaitez simplement avoir un processus simple et plus léger en tant qu’hôte, sans rien lié aux fonctionnalités du serveur MVC, de l’API web ou du serveur HTTP.
Par conséquent, vous pouvez choisir de créer un processus hôte spécialisé avec IHost pour gérer les services hébergés et rien d’autre, tel qu'un microservice fait uniquement pour l'hébergement de IHostedServices, ou vous pouvez également étendre une application ASP.NET Core WebHost existante, comme une API Web ou une application MVC.
Chaque approche a des avantages et des inconvénients en fonction de vos besoins métier et d’extensibilité. La ligne inférieure est essentiellement que si vos tâches en arrière-plan n’ont rien à voir avec HTTP (IWebHost) vous devez utiliser IHost.
Enregistrement des services hébergés sur votre serveur web ou hébergeur.
Examinons plus en détail l’interface IHostedService , car son utilisation est assez similaire dans un WebHost ou dans un Host.
SignalR est un exemple d’artefact utilisant des services hébergés, mais vous pouvez également l’utiliser pour des choses beaucoup plus simples comme :
- Une tâche en arrière-plan interroge une base de données à la recherche de modifications.
- Tâche planifiée mettant à jour régulièrement un cache.
- Implémentation de QueueBackgroundWorkItem qui permet à une tâche d’être exécutée sur un thread d’arrière-plan.
- Traitement des messages à partir d’une file d’attente de messages en arrière-plan d’une application web tout en partageant des services courants tels que
ILogger. - Une tâche en arrière-plan a commencé avec
Task.Run().
Vous pouvez tout simplement déplacer l’une de ces actions vers une tâche en arrière-plan qui implémente IHostedService.
La manière dont vous ajoutez un ou plusieurs IHostedServices à votre WebHost ou Host se fait en les enregistrant via la méthode d'extension AddHostedService dans un ASP.NET Core WebHost (ou dans un Host en .NET Core 2.1 et versions ultérieures). En fait, vous devez inscrire les services hébergés au démarrage de l’application dans Program.cs.
//Other DI registrations;
// Register Hosted Services
builder.Services.AddHostedService<GracePeriodManagerService>();
builder.Services.AddHostedService<MyHostedServiceB>();
builder.Services.AddHostedService<MyHostedServiceC>();
//...
Dans ce code, le GracePeriodManagerService service hébergé est un code réel du microservice métier Ordering dans eShopOnContainers, tandis que les deux autres sont seulement deux exemples supplémentaires.
L’exécution IHostedService de tâche en arrière-plan est coordonnée avec la durée de vie de l’application (hôte ou microservice, par exemple). Vous inscrivez des tâches au démarrage de l’application et vous avez la possibilité d’effectuer une action ou d’effectuer un nettoyage approprié lorsque l’application s’arrête.
Sans utiliser IHostedService, vous pouvez toujours démarrer un thread d’arrière-plan pour exécuter n’importe quelle tâche. La différence se situe précisément au moment de l’arrêt de l’application, quand le thread est simplement tué sans avoir eu l’occasion d’exécuter des actions de nettoyage normales.
L'interface IHostedService
Lorsque vous enregistrez un IHostedService, .NET appelle les méthodes StartAsync() et StopAsync() de votre type IHostedService pendant le démarrage et l'arrêt de l'application, respectivement. Pour plus d’informations, consultez l’interface IHostedService.
Comme vous pouvez l’imaginer, vous pouvez créer plusieurs implémentations d’IHostedService et les inscrire dans Program.cs, comme indiqué précédemment. Tous ces services hébergés sont démarrés et arrêtés avec l’application/microservice.
En tant que développeur, vous êtes responsable de la gestion de l’action d’arrêt de vos services lorsque StopAsync() la méthode est déclenchée par l’hôte.
Implémentation d’IHostedService avec une classe de service hébergée personnalisée dérivée de la classe de base BackgroundService
Vous pouvez aller de l’avant et créer votre classe de service hébergé personnalisée à partir de zéro et implémenter le IHostedService, comme vous devez le faire lors de l’utilisation de .NET Core 2.0 et versions ultérieures.
Toutefois, étant donné que la plupart des tâches en arrière-plan ont des besoins similaires en ce qui concerne la gestion des jetons d’annulation et d’autres opérations classiques, il existe une classe de base abstraite pratique à partir de laquelle vous pouvez dériver, nommée BackgroundService (disponible depuis .NET Core 2.1).
Cette classe fournit le travail principal nécessaire à la configuration de la tâche en arrière-plan.
Le code suivant est la classe de base BackgroundService abstraite telle qu’implémentée dans .NET.
// Copyright (c) .NET Foundation. Licensed under the Apache License, Version 2.0.
/// <summary>
/// Base class for implementing a long running <see cref="IHostedService"/>.
/// </summary>
public abstract class BackgroundService : IHostedService, IDisposable
{
private Task _executingTask;
private readonly CancellationTokenSource _stoppingCts =
new CancellationTokenSource();
protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
public virtual Task StartAsync(CancellationToken cancellationToken)
{
// Store the task we're executing
_executingTask = ExecuteAsync(_stoppingCts.Token);
// If the task is completed then return it,
// this will bubble cancellation and failure to the caller
if (_executingTask.IsCompleted)
{
return _executingTask;
}
// Otherwise it's running
return Task.CompletedTask;
}
public virtual async Task StopAsync(CancellationToken cancellationToken)
{
// Stop called without start
if (_executingTask == null)
{
return;
}
try
{
// Signal cancellation to the executing method
_stoppingCts.Cancel();
}
finally
{
// Wait until the task completes or the stop token triggers
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite,
cancellationToken));
}
}
public virtual void Dispose()
{
_stoppingCts.Cancel();
}
}
Lorsque vous dérivez de la classe de base abstraite précédente, grâce à cette implémentation héritée, vous devez simplement implémenter la ExecuteAsync() méthode dans votre propre classe de service hébergé personnalisée, comme dans le code simplifié suivant à partir d’eShopOnContainers qui interroge une base de données et publie des événements d’intégration dans Event Bus si nécessaire.
public class GracePeriodManagerService : BackgroundService
{
private readonly ILogger<GracePeriodManagerService> _logger;
private readonly OrderingBackgroundSettings _settings;
private readonly IEventBus _eventBus;
public GracePeriodManagerService(IOptions<OrderingBackgroundSettings> settings,
IEventBus eventBus,
ILogger<GracePeriodManagerService> logger)
{
// Constructor's parameters validations...
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogDebug($"GracePeriodManagerService is starting.");
stoppingToken.Register(() =>
_logger.LogDebug($" GracePeriod background task is stopping."));
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogDebug($"GracePeriod task doing background work.");
// This eShopOnContainers method is querying a database table
// and publishing events into the Event Bus (RabbitMQ / ServiceBus)
CheckConfirmedGracePeriodOrders();
try {
await Task.Delay(_settings.CheckUpdateTime, stoppingToken);
}
catch (TaskCanceledException exception) {
_logger.LogCritical(exception, "TaskCanceledException Error", exception.Message);
}
}
_logger.LogDebug($"GracePeriod background task is stopping.");
}
.../...
}
Dans ce cas spécifique pour eShopOnContainers, il exécute une méthode d’application qui interroge une table de base de données à la recherche de commandes avec un état spécifique et lors de l’application de modifications, elle publie des événements d’intégration via le bus d’événements (sous elle peut utiliser RabbitMQ ou Azure Service Bus).
Bien sûr, vous pouvez exécuter n’importe quelle autre tâche en arrière-plan métier, à la place.
Par défaut, le jeton d’annulation est défini avec un délai d’expiration de 5 secondes, bien que vous puissiez modifier cette valeur lors de la génération de votre WebHost en utilisant l’extension UseShutdownTimeout du IWebHostBuilder. Cela signifie que notre service est censé être annulé dans les 5 secondes, sinon il sera arrêté plus brusquement.
Le code suivant changerait ce moment en 10 secondes.
WebHost.CreateDefaultBuilder(args)
.UseShutdownTimeout(TimeSpan.FromSeconds(10))
...
Diagramme de classes récapitulative
L’image suivante montre un résumé visuel des classes et interfaces impliquées lors de l’implémentation d’IHostedServices.

Figure 6-27. Diagramme de classes montrant les plusieurs classes et interfaces associées à IHostedService
Diagramme de classes : IWebHost et IHost peuvent héberger de nombreux services, qui héritent de BackgroundService, qui implémente IHostedService.
Considérations relatives au déploiement et points à prendre en compte
Il est important de noter que la façon dont vous déployez votre ASP.NET Core WebHost ou .NET Host peut avoir un impact sur la solution finale. Par exemple, si vous déployez votre WebHost sur IIS ou sur un Azure App Service normal, votre hôte peut être arrêté en raison des recyclages de pools d’applications. Toutefois, si vous déployez votre hôte en tant que conteneur dans un orchestrateur comme Kubernetes, vous pouvez contrôler le nombre assuré d’instances actives de votre hôte. En outre, vous pouvez envisager d’autres approches dans le cloud en particulier pour ces scénarios, comme Azure Functions. Enfin, si vous avez besoin que le service s’exécute à tout moment et que vous déployez sur un serveur Windows, vous pouvez utiliser un service Windows.
Toutefois, même pour un WebHost déployé dans un pool d’applications, il existe des scénarios tels que le repeuplement ou le vidage du cache en mémoire de l’application, qui sont toujours applicables.
L’interface IHostedService offre un moyen pratique de démarrer des tâches en arrière-plan dans une application web ASP.NET Core (dans .NET Core 2.0 et versions ultérieures) ou dans n’importe quel processus/hôte (à partir de .NET Core 2.1 avec IHost). Le principal avantage est le suivant : grâce à l’annulation normale, vous pouvez nettoyer le code de vos tâches en arrière-plan quand l’hôte s’arrête.
Ressources supplémentaires
Création d’une tâche planifiée dans ASP.NET Core/Standard 2.0
https://blog.maartenballiauw.be/post/2017/08/01/building-a-scheduled-cache-updater-in-aspnet-core-2.htmlImplémentation d’IHostedService dans ASP.NET Core 2.0
https://www.stevejgordon.co.uk/asp-net-core-2-ihostedserviceExemple GenericHost utilisant ASP.NET Core 2.1
https://github.com/aspnet/Hosting/tree/release/2.1/samples/GenericHostSample