15. Services hébergés et travail en arrière-plan
Sections
Réglages de lecture
Voix naturelle enregistrée pour ce cours, la même dans tous les navigateurs.
Aucune voix pour cette langue dans ce navigateur.
Plus de voix
Code et termes techniques en anglais
Désactivé : la voix de la page lit tout, sans pause entre deux voix.
Aucune voix pour cette langue dans ce navigateur.
Plus de voix
D’autres voix : Microsoft Edge propose des voix naturelles en ligne, et Windows (Paramètres › Heure et langue › Voix), macOS et Android en installent d’autres.
Un IHostedService participe au cycle de vie de l’hôte. BackgroundService fournit la boucle ExecuteAsync, mais l’hôte reste propriétaire du démarrage, de la cancellation et de l’arrêt.
Prérequis
Section intitulée « Prérequis »Suivez d’abord l’injection de dépendances et les options ainsi que les channels. Vous devez déjà comprendre les durées de vie des services, les cancellation tokens et les flux asynchrones.
L’hôte possède le cycle de vie
Section intitulée « L’hôte possède le cycle de vie »L’expérience démarre un hôte, attend des gates de terminaison explicites, traite deux éléments, puis demande l’arrêt. Aucun Thread.Sleep : chaque attente est bornée à cinq secondes.
Dans .NET 10, tout BackgroundService.ExecuteAsync s’exécute sur un thread d’arrière-plan. Le travail qui doit finir avant le démarrage des autres services appartient au constructeur, à StartAsync ou à IHostedLifecycleService, pas avant le premier await d’ExecuteAsync.
Une file bornée est un contrat applicatif
Section intitulée « Une file bornée est un contrat applicatif »Le worker consomme un Channel<T> borné. BoundedChannelFullMode.Wait applique la backpressure quand la file est pleine. Une vraie API de soumission devrait attendre WriteAsync ; cette preuve utilise TryWrite, car sa capacité et ses deux écritures sont fixes.
AddHostedService enregistre le worker comme singleton. Une dépendance scoped doit donc être résolue dans un nouvel IServiceScope pour chaque élément. L’injecter dans le constructeur du worker créerait une dépendance captive.
== The host starts one singleton worker and the queue owns the workstartup observed: Truequeued results: C major@scope-1 | G major@scope-2fresh scope per item: Trueshutdown cancellation observed: TrueLes fautes relèvent d’une stratégie
Section intitulée « Les fautes relèvent d’une stratégie »La stratégie par défaut de l’hôte .NET 10 arrête l’application quand un BackgroundService lève une exception. La preuve fixe explicitement BackgroundServiceExceptionBehavior.StopHost, libère une gate de faute et observe ApplicationStopping :
== A BackgroundService fault stops its hostfault requested host stop: TrueArrêter l’hôte n’est pas une reprise. En production, il faut encore définir retry, dead-letter ou intervention opérateur pour le travail répétable sans danger.
Exécuter la preuve
Section intitulée « Exécuter la preuve »dotnet run --project code/csharp-advanced/Advanced -c Release -- l15La sortie vérifiée est expected/l15.txt.
Exercices
Section intitulée « Exercices »- Remplacer
TryWritepar une API asynchrone et prouver qu’un troisième élément attend quand les deux places sont occupées. - Ajouter un résultat d’échec par élément sans arrêter le worker singleton.
- Introduire un second consommateur et préciser quelle garantie d’ordre disparaît.
Solutions
- Renvoyer
ValueTask, attendreWriter.WriteAsyncet retenir les deux premiers éléments avec des gates. Libérer une gate puis vérifier que la troisième écriture termine, sans déduire un blocage d’un délai. - Capturer l’exception autour d’un seul élément, terminer son
TaskCompletionSourceavec un échec typé et continuer la boucle. Ne pas traiter la cancellation de l’hôte comme un échec métier. - Mettre
SingleReader = falseet lancer deux workers. Les lectures restent FIFO, mais l’ordre de fin dépend du traitement ; ajouter des numéros de séquence si l’aval doit réordonner.