Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Aanbeveling
Deze inhoud is een fragment uit het eBook, .NET Microservices Architecture for Containerized .NET Applications, beschikbaar op .NET Docs of als een gratis downloadbare PDF die offline kan worden gelezen.
              
              
              
              
            
Achtergrondtaken en geplande taken zijn iets wat u mogelijk moet gebruiken in elke toepassing, ongeacht of deze het patroon van de microservicesarchitectuur volgt. Het verschil bij het gebruik van een microservicesarchitectuur is dat u de achtergrondtaak in een afzonderlijk proces/container voor hosting kunt implementeren, zodat u deze omlaag/omhoog kunt schalen op basis van uw behoeften.
Vanuit een algemeen oogpunt hebben we in .NET dit type taken gehoste services genoemd, omdat het services/logica zijn die u host in uw host/toepassing/microservice. In dit geval betekent de gehoste service niets meer dan een klasse met de achtergrondtaaklogica.
Sinds .NET Core 2.0 biedt het framework een nieuwe interface met de naam IHostedService, waarmee u eenvoudig gehoste services kunt implementeren. Het basisidee is dat u meerdere achtergrondtaken (gehoste diensten) kunt registreren die op de achtergrond worden uitgevoerd, terwijl uw webhoster of host actief is, zoals te zien in afbeelding 6-26.
              
              
            
Afbeelding 6-26. IHostedService gebruiken in een WebHost versus een Host
ASP.NET Core 1.x- en 2.x-ondersteuning IWebHost voor achtergrondprocessen in web-apps. .NET Core 2.1 en latere versies ondersteunen IHost voor achtergrondprocessen met eenvoudige console-apps. Let op het verschil tussen WebHost en Host.
Een WebHost (basisklasse implementeren IWebHost) in ASP.NET Core 2.0 is het infrastructuurartefact dat u gebruikt om HTTP-serverfuncties te bieden aan uw proces, zoals wanneer u een MVC-web-app of web-API-service implementeert. Het biedt alle nieuwe infrastructuurfunctionaliteiten in ASP.NET Core, waardoor u afhankelijkheidsinjectie kunt gebruiken, middlewares kunt invoegen in de aanvraagpijplijn en meer. De WebHost gebruikt dezelfde IHostedServices voor achtergrondtaken.
Een Host (basisklasse die IHost implementeert) werd geïntroduceerd in .NET Core 2.1. In principe kunt u met een Host een vergelijkbare infrastructuur creëren zoals wat u heeft met WebHost (afhankelijkheidsinjectie, gehoste services, enzovoort), maar in dit geval wilt u gewoon een eenvoudig en lichter proces als host, zonder betrekking tot MVC-, web-API- of HTTP-serverfuncties.
Daarom kunt u kiezen en een gespecialiseerd hostproces maken met IHost om de gehoste services af te handelen en niets anders, zoals een microservice die alleen is gemaakt voor het hosten van de IHostedServices, of u kunt ook een bestaande ASP.NET Core WebHost uitbreiden, zoals een bestaande ASP.NET Core Web API of MVC-app.
Elke benadering heeft voor- en nadelen, afhankelijk van uw bedrijfs- en schaalbaarheidsbehoeften. Het belangrijkste punt is dat u IWebHost moet gebruiken als uw achtergrondtaken niets te maken hebben met HTTP (IHost).
Gehoste services registreren in uw WebHost of Host
Laten we verder inzoomen op de IHostedService interface, omdat het gebruik ervan vergelijkbaar is in een WebHost of in een Host.
SignalR is een voorbeeld van een artefact met gehoste services, maar u kunt dit ook gebruiken voor veel eenvoudigere zaken zoals:
- Een achtergrondtaak peilt een database die op zoek is naar wijzigingen.
 - Een geplande taak die regelmatig een cache bijwerkt.
 - Een implementatie van QueueBackgroundWorkItem waarmee een taak kan worden uitgevoerd op een achtergrondthread.
 - Berichten uit een wachtrij op de achtergrond van een web-app verwerken terwijl men algemene services zoals 
ILoggerdeelt. - Er is een achtergrondtaak gestart met 
Task.Run(). 
U kunt deze acties in principe overdragen naar een achtergrondtaak die IHostedService uitvoert.
De manier waarop u een of meerdere IHostedServices in uw WebHost of Host toevoegt, is door ze te registreren via de AddHostedService extensiemethode in een ASP.NET Core WebHost (of in een Host in .NET Core 2.1 en hoger). In principe moet u de gehoste services registreren bij het opstarten van de toepassing in Program.cs.
//Other DI registrations;
// Register Hosted Services
builder.Services.AddHostedService<GracePeriodManagerService>();
builder.Services.AddHostedService<MyHostedServiceB>();
builder.Services.AddHostedService<MyHostedServiceC>();
//...
In die code is de GracePeriodManagerService gehoste service echte code van de Order business microservice in eShopOnContainers, terwijl de andere twee slechts twee extra voorbeelden zijn.
De IHostedService uitvoering van de achtergrondtaak wordt gecoördineerd met de levensduur van de toepassing (host of microservice, voor dat geval). U registreert taken wanneer de toepassing wordt gestart en u hebt de mogelijkheid om een goede actie uit te voeren of op te schonen wanneer de toepassing wordt afgesloten.
Zonder gebruik IHostedServicekunt u altijd een achtergrondthread starten om een taak uit te voeren. Het verschil is bij het afsluiten van de app wanneer die thread wordt gedood zonder dat de mogelijkheid heeft om zorgvuldige opschoonacties uit te voeren.
De IHostedService-interface
Wanneer u IHostedService registreert in .NET, worden de StartAsync() en StopAsync() methoden van uw IHostedService-type aangeroepen tijdens het starten en stoppen van de toepassing. Zie de interface IHostedService voor meer informatie.
Zoals u zich kunt voorstellen, kunt u meerdere implementaties van IHostedService maken en ze registreren in Program.cs, zoals eerder wordt weergegeven. Alle gehoste services worden gestart en gestopt samen met de toepassing/microservice.
Als ontwikkelaar bent u verantwoordelijk voor het afhandelen van de stopactie van uw services wanneer StopAsync() de methode wordt geactiveerd door de host.
IHostedService implementeren met een aangepaste gehoste serviceklasse die is afgeleid van de baseklasse BackgroundService
U kunt uw aangepaste gehoste serviceklasse helemaal zelf maken en de IHostedService, zoals u moet doen wanneer u .NET Core 2.0 en hoger gebruikt, implementeren.
Aangezien de meeste achtergrondtaken echter vergelijkbare behoeften hebben met betrekking tot het beheer van annuleringstokens en andere typische bewerkingen, is er een handige abstracte basisklasse die u kunt afleiden van, benoemd BackgroundService (beschikbaar sinds .NET Core 2.1).
Deze klasse biedt het belangrijkste werk dat nodig is om de achtergrondtaak in te stellen.
De volgende code is de abstracte Base-klasse BackgroundService, zoals geïmplementeerd in .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();
    }
}
Wanneer u afleidt van de vorige abstracte basisklasse, hoeft u dankzij die geërfde implementatie alleen de ExecuteAsync()-methode te implementeren in uw eigen aangepaste gehoste serviceklasse, zoals in de volgende vereenvoudigde code van eShopOnContainers die een database peilt en integratiegebeurtenissen publiceert in de Event Bus wanneer nodig.
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.");
    }
    .../...
}
In dit specifieke geval voor eShopOnContainers voert het een toepassingsmethode uit die een query uitvoert op een databasetabel die op orders zoekt met een specifieke status en bij het toepassen van wijzigingen, worden integratie-gebeurtenissen gepubliceerd via de gebeurtenisbus (eronder kan RabbitMQ of Azure Service Bus worden gebruikt).
U kunt natuurlijk ook elke andere zakelijke achtergrondtaak uitvoeren.
Standaard wordt het annuleringstoken ingesteld met een time-out van 5 seconden, hoewel u deze waarde kunt wijzigen bij het bouwen van uw WebHost met behulp van de UseShutdownTimeout extensie van de IWebHostBuilder. Dit betekent dat onze service naar verwachting binnen 5 seconden wordt geannuleerd, anders wordt deze abrupt beëindigd.
Met onderstaande code wordt die tijd gewijzigd in 10 seconden.
WebHost.CreateDefaultBuilder(args)
    .UseShutdownTimeout(TimeSpan.FromSeconds(10))
    ...
Overzichtsklassediagram
In de volgende afbeelding ziet u een visueel overzicht van de klassen en interfaces die betrokken zijn bij het implementeren van IHostedServices.
              
              
            
Afbeelding 6-27. Klassediagram met de meerdere klassen en interfaces met betrekking tot IHostedService
Klassediagram: IWebHost en IHost kunnen veel services hosten, die overnemen van BackgroundService, waarmee IHostedService wordt geïmplementeerd.
Overwegingen en aandachtspunten bij de implementatie
Het is belangrijk te weten dat de manier waarop u uw ASP.NET Core WebHost of .NET Host implementeert, van invloed kan zijn op de uiteindelijke oplossing. Als u bijvoorbeeld uw WebHost op IIS of een gewone Azure App Service implementeert, kan uw host worden afgesloten vanwege recyclen van de applicatiepool. Maar als u uw host als een container implementeert in een orchestrator zoals Kubernetes, kunt u het verzekerde aantal live-exemplaren van uw host beheren. Daarnaast kunt u andere benaderingen in de cloud overwegen die speciaal zijn gemaakt voor deze scenario's, zoals Azure Functions. Als u wilt dat de service voortdurend wordt uitgevoerd en op een Windows Server wordt geïmplementeerd, kunt u een Windows-service gebruiken.
Maar zelfs voor een WebHost die in een app-pool is geïmplementeerd, zijn er scenario's zoals het opnieuw vullen of leegmaken van de in-memory cache van de applicatie die nog steeds van toepassing zijn.
De IHostedService interface biedt een handige manier om achtergrondtaken te starten in een ASP.NET Core-webtoepassing (in .NET Core 2.0 en latere versies) of in een proces/host (beginnend in .NET Core 2.1 met IHost). Het belangrijkste voordeel is de mogelijkheid die u krijgt met de geleidelijke annulering om de code van uw achtergrondtaken op te schonen wanneer de host zelf wordt afgesloten.
Aanvullende bronnen
Een geplande taak maken in ASP.NET Core/Standard 2.0
https://blog.maartenballiauw.be/post/2017/08/01/building-a-scheduled-cache-updater-in-aspnet-core-2.htmlIHostedService implementeren in ASP.NET Core 2.0
https://www.stevejgordon.co.uk/asp-net-core-2-ihostedserviceGenericHost-voorbeeld met ASP.NET Core 2.1
https://github.com/aspnet/Hosting/tree/release/2.1/samples/GenericHostSample