Megosztás a következőn keresztül:


Háttérfeladatok implementálása mikroszolgáltatásokban az IHostedService és a BackgroundService osztály használatával

Jótanács

Ez a tartalom egy részlet a '.NET Microservices Architecture for Containerized .NET Applications' című eBook-ból, amely elérhető a .NET Docs oldalon, vagy ingyenesen letölthető PDF formátumban, amely offline módban is olvasható.

.NET mikroszolgáltatások architektúrája konténerizált .NET alkalmazásokhoz e-könyv borító miniatűr.

A háttérfeladatokat és az ütemezett feladatokat minden alkalmazásban használnia kell, függetlenül attól, hogy az követi-e a mikroszolgáltatás-architektúra mintáját. A mikroszolgáltatás-architektúra használatakor az a különbség, hogy a háttérfeladatot egy külön folyamatban/tárolóban implementálhatja üzemeltetésre, hogy igény szerint le- vagy felskálázhassa azt.

Általánosságban véve a .NET-ben az ilyen típusú feladatokat üzemeltetett szolgáltatásoknak nevezzük, mivel ezek olyan szolgáltatások vagy logikák, amelyeket a gazdagépen, alkalmazáson vagy mikroszolgáltatáson belül üzemeltetünk. Vegye figyelembe, hogy ebben az esetben a üzemeltetett szolgáltatás egyszerűen egy háttérfeladat-logikával rendelkező osztályt jelent.

A .NET Core 2.0 óta a keretrendszer egy új interfészt biztosít, amely segít az üzemeltetett szolgáltatások egyszerű megvalósításában. Az alapötlet az, hogy több háttérfeladatot és hosztolt szolgáltatást regisztrálhat, amelyek a háttérben futnak, miközben a webkiszolgáló vagy szerver működik, ahogyan az a 6–26. képen látható.

Az ASP.NET Core IWebHost és a .NET Core IHost összehasonlítása.

6–26. ábra. Az IHostedService használata webes fogadó vs gazdagépen.

ASP.NET Core 1.x és 2.x támogatja IWebHost a webalkalmazások háttérfolyamatait. A .NET Core 2.1 és újabb verziói támogatják IHost a háttérfolyamatokat egyszerű konzolalkalmazásokkal. Figyelje meg a különbséget a WebHost és a Host között.

Az WebHost az ASP.NET Core 2.0-ban használható alaposztály, amely implementálja IWebHost, és ezáltal infrastruktúra-összetevőként szolgál HTTP-kiszolgálói funkciók biztosításához a munkafolyamathoz, például MVC-webalkalmazás vagy web API-szolgáltatás implementálása esetén. Ez biztosítja a ASP.NET Core összes új infrastruktúra-jóságát, lehetővé téve a függőséginjektálás használatát, köztes szoftverek beszúrását a kérelemfolyamatba és hasonlókat. A WebHost ezeket a IHostedServices használja a háttérfeladatokhoz.

Az Host (alaposztály, amely implementálja IHost) bevezetésre került a .NET Core 2.1-ben. Alapvetően egy Host lehetővé teszi, hogy hasonló infrastruktúrával rendelkezzen, mint amilyen WebHost esetén van (függőséginjektálás, üzemeltetett szolgáltatások stb.), de ebben az esetben csak egy egyszerűbb és könnyebb háttérfolyamattal szeretne dolgozni, az MVC-vel, Web API-val vagy HTTP szerver funkciókkal kapcsolatos összefüggések nélkül.

Ezért választhat, és létrehozhat egy speciális gazdagépfolyamatot IHost az üzemeltetett szolgáltatások kezeléséhez, és semmi mást, például egy olyan mikroszolgáltatást, amelyet csak a IHostedServicesszolgáltatás üzemeltetésére hoztak létre, vagy kiterjeszthet egy meglévő ASP.NET Core-t WebHost, például egy meglévő ASP.NET Core Web API-t vagy MVC-alkalmazást.

Minden megközelítésnek vannak előnyei és hátrányai az üzleti és skálázhatósági igényektől függően. A lényeg az, hogy ha a háttérfeladatoknak semmi köze a HTTP-hez (IWebHost) akkor érdemes használni IHost.

Hosztolt szolgáltatások regisztrálása a WebHostban vagy a hoston

Vizsgáljuk meg részletesebben a IHostedService felületet, mivel a használata meglehetősen hasonló egy WebHost vagy egy Host.

A SignalR egy példa egy üzemeltetett szolgáltatásokat használó összetevőre, de sokkal egyszerűbb dolgokhoz is használhatja, például:

  • Egy háttérfeladat, amely egy adatbázist kérdez le, és módosításokat keres.
  • Ütemezett feladat, amely időnként frissíti a gyorsítótárat.
  • A QueueBackgroundWorkItem implementációja, amely lehetővé teszi a tevékenységek háttérszálon való végrehajtását.
  • Üzenetek feldolgozása egy üzenetsorból egy webalkalmazás háttérfolyamata során, közös szolgáltatásokat megosztva, mint például a ILogger.
  • Egy háttérfeladat elkezdődött Task.Run()-val.

Lehetőség van ezen műveletek kiszervezésére egy háttérfeladatba, ami implementálja a IHostedService.

Egy vagy több IHostedServices-t úgy adhat hozzá a WebHost és Host elemekhez, hogy regisztrálja őket az ASP.NET Core AddHostedService bővítménymetódusán keresztül (vagy egy WebHost-ben, a .NET Core 2.1 vagy újabb verzióban). Alapvetően regisztrálnia kell a hosztolt szolgáltatásokat az alkalmazásindításkor a Program.cs fájlban.

//Other DI registrations;

// Register Hosted Services
builder.Services.AddHostedService<GracePeriodManagerService>();
builder.Services.AddHostedService<MyHostedServiceB>();
builder.Services.AddHostedService<MyHostedServiceC>();
//...

Ebben a kódban a GracePeriodManagerService üzemeltetett szolgáltatás valódi kód az eShopOnContainers rendelési üzleti mikroszolgáltatásából, míg a másik kettő csak két további minta.

A IHostedService háttérfeladat végrehajtása az alkalmazás élettartamával (gazdagép vagy mikroszolgáltatás) van összehangolva. A feladatokat az alkalmazás indításakor regisztrálhatja, és az alkalmazás leállításakor lehetősége van némi kecses műveletre vagy törlésre.

A IHostedService használata nélkül elindíthat egy háttérszálat bármely feladat futtatásához. A különbség pontosan az alkalmazás leállítási idején van, amikor a szál egyszerűen megszakítható anélkül, hogy lehetősége lenne kíméletes tisztítási műveleteket végrehajtani.

Az IHostedService felület

Amikor regisztrál egy IHostedService, a .NET az alkalmazás indításakor meghívja a StartAsync() típus StopAsync() és leállításakor a IHostedService metódusait. További részletekért lásd az IHostedService felületét.

Ahogy elképzelheti, az IHostedService több implementációját is létrehozhatja, és mindegyiket regisztrálhatja a Program.cs-ben a korábbi példák szerint. Az összes üzemeltetett szolgáltatás az alkalmazással/mikroszolgáltatással együtt elindul és le lesz állítva.

Fejlesztőként Ön felelős a szolgáltatások leállítási műveletének kezeléséért, amikor a gazdagép aktiválja a StopAsync() metódust.

Az IHostedService implementálása a BackgroundService alaposztályból származó egyéni üzemeltetett szolgáltatásosztálysal

.NET Core 2.0 és újabb verzióinak használatakor az alapoktól létrehozhatja az egyéni hostolt szolgáltatási osztályt, és implementálhatja azt IHostedService.

Mivel azonban a legtöbb háttérfeladatnak hasonló igényei vannak a lemondási jogkivonatok kezelése és más tipikus műveletek tekintetében, van egy kényelmes, absztrakt alaposztály, amelyből származtatható, elnevezve BackgroundService (a .NET Core 2.1 óta érhető el).

Ez az osztály biztosítja a háttérfeladat beállításához szükséges fő munkát.

A következő kód a .NET-ben implementált absztrakt BackgroundService alaposztály.

// 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();
    }
}

Ha az előző absztrakt alaposztályból származik, az örökölt implementációnak köszönhetően csak saját egyéni üzemeltetett szolgáltatásosztályban kell implementálnia a ExecuteAsync() metódust, ahogyan az alábbi egyszerűsített kódban az eShopOnContainerstől, amely lekérdez egy adatbázist, és szükség esetén közzéteszi az integrációs eseményeket az Event Busban.

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.");
    }

    .../...
}

Ebben a konkrét esetben az eShopOnContainers esetében egy olyan alkalmazásmetódus végrehajtása, amely egy adott állapotú megrendeléseket kereső adatbázistáblát kérdez le, és a módosítások alkalmazásakor az eseménybuszon keresztül teszi közzé az integrációs eseményeket (alatta lehet a RabbitMQ vagy az Azure Service Bus).

Természetesen bármilyen más üzleti háttérfeladatot is futtathat helyette.

Alapértelmezés szerint a törlési token 5 másodperces időkorláttal van beállítva, bár ezt az értéket megváltoztathatja a WebHostUseShutdownTimeout kiterjesztésének IWebHostBuilderlétrehozásakor. Ez azt jelenti, hogy szolgáltatásunk várhatóan 5 másodpercen belül lemondásra kerül, különben sokkal hirtelenebbül leállítják.

Az alábbi kód ezt az időt 10 másodpercre módosítaná.

WebHost.CreateDefaultBuilder(args)
    .UseShutdownTimeout(TimeSpan.FromSeconds(10))
    ...

Összefoglaló osztálydiagram

Az alábbi képen az IHostedServices megvalósítása során érintett osztályok és felületek vizuális összegzése látható.

Diagram, amely azt mutatja, hogy az IWebHost és az IHost számos szolgáltatást üzemeltethet.

6–27. ábra. Az IHostedService-hez kapcsolódó osztályok és felületek osztálydiagramja

Osztálydiagram: Az IWebHost és az IHost számos szolgáltatást üzemeltethet, amelyek öröklődnek a BackgroundService szolgáltatástól, amely implementálja az IHostedService szolgáltatást.

Üzembe helyezési szempontok és tanulságok

Fontos megjegyezni, hogy a ASP.NET Core WebHost vagy a .NET Host üzembe helyezése hatással lehet a végső megoldásra. Például, ha az IIS-en vagy egy szokásos Azure App Service-en üzemelteti a WebHost alkalmazást, előfordulhat, hogy a gazdagép leáll az alkalmazáskészletek újrahasznosítása miatt. Ha azonban tárolóként helyezi üzembe a gazdagépet egy olyan vezénylőben, mint a Kubernetes, szabályozhatja a gazdagép biztonságos élő példányainak számát. Emellett a felhőben más megközelítéseket is megfontolhat, különösen ezekhez a forgatókönyvekhez, például az Azure Functionshez. Végül, ha a szolgáltatásnak folyamatosan futnia kell, és Windows Serveren van üzembe helyezve, használhat windowsos szolgáltatást.

De még egy WebHost alkalmazáskészletben üzembe helyezett alkalmazás esetében is vannak olyan forgatókönyvek, mint például az alkalmazás memóriabeli gyorsítótárának újratöltése vagy kiürítése, amely továbbra is alkalmazható lenne.

A IHostedService felület kényelmes módot kínál háttérfeladatok indítására egy ASP.NET Core-webalkalmazásban (.NET Core 2.0-s és újabb verziókban), vagy bármilyen folyamat/gazdagép esetében (a .NET Core 2.1-től IHostkezdve). A fő előnye az a lehetőség, hogy a kecses lemondással megtisztíthatja a háttérfeladatok kódját, amikor maga a gazdagép leáll.

További erőforrások