Services Worker dans .NET

Il existe de nombreuses raisons de créer des services de longue durée, tels que :

  • Le traitement de données gourmandes en ressources processeur.
  • La mise en file d’attente des éléments de travail en arrière-plan.
  • L’exécution d’une opération basée sur le temps selon une planification.

Le traitement du service en arrière-plan n’implique généralement pas d’interface utilisateur, mais les interfaces utilisateur peuvent être créées autour de celles-ci. Dans les premiers jours de .NET Framework, les développeurs Windows pouvaient créer des services Windows pour ces raisons. Maintenant, avec .NET, vous pouvez utiliser BackgroundService, qui est une implémentation de IHostedService, ou implémenter le vôtre.

Avec .NET, vous n’êtes plus limité à Windows. Vous pouvez développer des services en arrière-plan multiplateforme. Les services hébergés sont prêts pour la journalisation, la configuration et l’injection de dépendances. Ils font partie de la suite d’extensions de bibliothèques, ce qui signifie qu’ils sont fondamentaux pour toutes les charges de travail .NET qui fonctionnent avec l’hôte générique.

Important

L’installation du Kit de développement logiciel (SDK) .NET installe également Microsoft.NET.Sdk.Worker et le modèle Worker. En d’autres termes, après avoir installé le Kit de développement logiciel (SDK) .NET, vous pouvez créer un Worker à l’aide de la commande dotnet new worker. Si vous utilisez Visual Studio, le modèle est masqué jusqu’à ce que la charge de travail de développement web et l’ASP.NET facultatives soient installées.

Terminologie

De nombreux termes sont utilisés par erreur synonymes. Dans cette section, vous trouverez des définitions pour certains de ces termes afin de rendre leur intention plus évidente.

  • Service en arrière-plan : fait référence au type BackgroundService.
  • Service hébergé : implémentations de IHostedService, ou référence à IHostedService.
  • Service de longue durée : tout service qui s’exécute en continu.
  • Service Windows : infrastructure de service Windows, centrée à l’origine sur .NET Framework, mais désormais accessible via .NET.
  • Service de travail : fait référence au modèle de service Worker.

Modèle Service Worker

Le modèle de service Worker est disponible pour l’interface CLI .NET et Visual Studio. Pour plus d’informations, consultez CLI .NET, dotnet new worker: modèle. Le modèle se compose d’une classe Program et Worker.

using App.WorkerService;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<Worker>();

IHost host = builder.Build();
host.Run();

La classe Program précédente :

  • Crée un HostApplicationBuilder.
  • Appelle AddHostedService pour inscrire le Worker en tant que service hébergé.
  • Génère un IHost à partir du générateur.
  • Appelle Run sur l’instance host, qui exécute l’application.

Modèles par défaut

Le modèle Worker n’active pas le garbage collection (nettoyage de la mémoire) de serveurs par défaut, car il de nombreux facteurs jouent un rôle dans la détermination de sa nécessité. Tous les scénarios nécessitant des services de longue durée doivent prendre en compte les implications en termes de performances de cette valeur par défaut. Pour activer le nettoyage de la mémoire du serveur, ajoutez le nœud ServerGarbageCollection au fichier projet :

<PropertyGroup>
    <ServerGarbageCollection>true</ServerGarbageCollection>
</PropertyGroup>

Compromis et considérations

Activé(e) Disabled
Gestion efficace de la mémoire : récupère automatiquement la mémoire inutilisée pour éviter les fuites de mémoire et optimiser l’utilisation des ressources. Amélioration des performances en temps réel : évite les pauses ou interruptions potentielles causées par le garbage collection dans les applications sensibles à la latence.
Stabilité à long terme : permet de maintenir des performances stables dans les services à long terme en gérant la mémoire sur des périodes prolongées. Efficacité des ressources : peut conserver les ressources processeur et mémoire dans des environnements limités aux ressources.
Maintenance réduite : réduit le besoin de gestion manuelle de la mémoire, ce qui simplifie la maintenance. Contrôle de mémoire manuel : fournit un contrôle précis de la mémoire pour les applications spécialisées.
Comportement prévisible : contribue au comportement cohérent et prévisible de l’application. Adapté aux processus de courte durée : réduit la surcharge du garbage collection pour les processus de courte durée ou éphémères.

Pour plus d’informations sur les considérations relatives aux performances, consultez Nettoyage de la mémoire du serveur. Pour plus d’informations sur la configuration du nettoyage de la mémoire du serveur, consultez les exemples de Configuration de nettoyage de la mémoire du serveur.

Classe Worker

Quant à Worker, le modèle fournit une implémentation simple.

namespace App.WorkerService;

public sealed class Worker(ILogger<Worker> logger) : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
            await Task.Delay(1_000, stoppingToken);
        }
    }
}

La classe Worker précédente est une sous-classe de BackgroundService, qui implémente IHostedService. BackgroundService est un abstract class et nécessite que la sous-classe implémente BackgroundService.ExecuteAsync(CancellationToken). Dans l’implémentation du modèle, ExecuteAsync effectue une boucle une fois par seconde, journalise la date et l’heure jusqu’à ce que le processus soit signalé à annuler.

Fichier projet

Le modèle Worker dépend du fichier projet Sdk suivant :

<Project Sdk="Microsoft.NET.Sdk.Worker">

Pour plus d’informations, consultez Kits SDK de projet .NET.

Package NuGet

Une application basée sur le modèle Worker utilise le SDK Microsoft.NET.Sdk.Worker et a une référence de package explicite au package Microsoft.Extensions.Hosting.

Conteneurs et adaptabilité du cloud

Avec la plupart des charges de travail .NET modernes, les conteneurs sont une option viable. Quand vous créez un service de longue durée à partir du modèle Worker dans Visual Studio, vous pouvez choisir la prise en charge de Docker. Cela crée un fichier Dockerfile qui conteneurise votre application .NET. Un Dockerfile est un ensemble d’instructions pour générer une image. Pour les applications .NET, le fichier Dockerfile se trouve généralement à la racine du répertoire à côté d’un fichier de solution.

# See https://aka.ms/containerfastmode to understand how Visual Studio uses this
# Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/runtime:8.0 AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["background-service/App.WorkerService.csproj", "background-service/"]
RUN dotnet restore "background-service/App.WorkerService.csproj"
COPY . .
WORKDIR "/src/background-service"
RUN dotnet build "App.WorkerService.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "App.WorkerService.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "App.WorkerService.dll"]

Les étapes Dockerfile précédentes sont les suivantes :

  • La définition de l’image de base à partir de mcr.microsoft.com/dotnet/runtime:8.0 comme alias base.
  • La modification du répertoire de travail en /app.
  • La définition de l’alias build à partir de l’image mcr.microsoft.com/dotnet/sdk:8.0 .
  • La modification du répertoire de travail sur /src.
  • La copie des contenus et la publication de l’application .NET :
    • L’application est publiée à l’aide de la commande dotnet publish.
  • Le relai de l’image du Kit de développement logiciel (SDK) .NET à partir de mcr.microsoft.com/dotnet/runtime:8.0 (l’alias base).
  • La copie de la sortie de build publiée à partir de /publish.
  • La définition du point d’entrée, qui délègue à dotnet App.BackgroundService.dll.

Conseil

Le MCR dans mcr.microsoft.com signifie « Microsoft Container Registry » et est le catalogue de conteneurs syndiqué de Microsoft à partir du hub Docker officiel. L’article du Catalogue de conteneurs syndiqué Microsoft contient des détails supplémentaires.

Lorsque vous ciblez Docker en tant que stratégie de déploiement pour votre service Worker .NET, voici quelques points à prendre en compte dans le fichier projet :

<Project Sdk="Microsoft.NET.Sdk.Worker">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>true</ImplicitUsings>
    <RootNamespace>App.WorkerService</RootNamespace>
    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
  </ItemGroup>
</Project>

Dans le fichier projet précédent, l’élément <DockerDefaultTargetOS> spécifie Linux comme cible. Pour cibler des conteneurs Windows, utilisez Windows. Le package NuGet Microsoft.VisualStudio.Azure.Containers.Tools.Targets est automatiquement ajouté en tant que référence de package lorsque la prise en charge de Docker est sélectionnée à partir du modèle.

Pour plus d’informations sur Docker avec .NET, consultez Tutoriel : Conteneuriser une application .NET. Pour plus d’informations sur le déploiement sur Azure, consultez Tutoriel : Déployer un service Worker sur Azure.

Important

Si vous souhaitez tirer parti des Secrets utilisateur avec le modèle Worker, vous devez référencer explicitement le package NuGet Microsoft.Extensions.Configuration.UserSecrets.

Extensibilité du service hébergé

L'interface IHostedService définit deux méthodes :

Ces deux méthodes servent de méthodes de cycle de vie : elles sont appelées respectivement lors du démarrage de l’hôte et de l’arrêt des événements.

Notes

En cas de substitution de méthodes StartAsync ou StopAsync, vous devez appeler et await la méthode de classe base pour vous assurer que le service démarre et/ou s’arrête correctement.

Important

L’interface sert de contrainte de paramètre de type générique sur la méthode d’extension AddHostedService<THostedService>(IServiceCollection), ce qui signifie que seules les implémentations sont autorisées. Vous êtes libre d’utiliser le BackgroundService fourni avec une sous-classe ou d’implémenter entièrement le vôtre.

Complétion du signal

Dans les scénarios les plus courants, vous n’avez pas besoin de signaler explicitement l’achèvement d’un service hébergé. Lorsque l’hôte démarre les services, ils sont conçus pour s’exécuter jusqu’à ce que l’hôte soit arrêté. Dans certains scénarios, toutefois, vous devrez peut-être signaler l’achèvement de l’ensemble de l’application hôte une fois le service terminé. Pour signaler l’achèvement, tenez compte de la classe Worker suivante :

namespace App.SignalCompletionService;

public sealed class Worker(
    IHostApplicationLifetime hostApplicationLifetime,
    ILogger<Worker> logger) : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // TODO: implement single execution logic here.
        logger.LogInformation(
            "Worker running at: {Time}", DateTimeOffset.Now);

        await Task.Delay(1_000, stoppingToken);

        // When completed, the entire app host will stop.
        hostApplicationLifetime.StopApplication();
    }
}

Dans le code précédent, la méthode ExecuteAsync n’effectue pas de boucle, et quand elle est terminée, elle appelle IHostApplicationLifetime.StopApplication().

Important

Cela signale à l’hôte qu’il doit s’arrêter, et sans cet appel à StopApplication, l’hôte continuera à s’exécuter indéfiniment.

Pour plus d'informations, consultez les pages suivantes :

Voir aussi