Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Tipp
Dieser Inhalt ist ein Auszug aus dem eBook .NET Microservices Architecture for Containerized .NET Applications, verfügbar auf .NET Docs oder als kostenlose herunterladbare PDF, die offline gelesen werden kann.
Hintergrundaufgaben und geplante Aufträge sind etwas, das Sie möglicherweise in einer beliebigen Anwendung verwenden müssen, unabhängig davon, ob sie dem Microservices-Architekturmuster folgt. Der Unterschied bei der Verwendung einer Microservices-Architektur besteht darin, dass Sie die Hintergrundaufgabe in einem separaten Prozess/Container für das Hosting implementieren können, damit Sie sie je nach Bedarf nach unten/oben skalieren können.
Aus allgemeiner Sicht haben wir in .NET diese Art von Aufgaben als gehostete Dienste bezeichnet, da sie Dienste/Logik sind, die Sie in Ihrem Host/Anwendung/Microservice hosten. Beachten Sie, dass der gehostete Dienst in diesem Fall einfach eine Klasse mit der Hintergrundaufgabenlogik bedeutet.
Seit .NET Core 2.0 stellt das Framework eine neue Schnittstelle IHostedService bereit, die Ihnen hilft, gehostete Dienste einfach zu implementieren. Die grundlegende Idee ist, dass Sie mehrere Hintergrundprozesse (verwaltete Dienste) registrieren können, die im Hintergrund laufen, während Ihr Webserver oder Host ausgeführt wird, wie in Abbildung 6-26 dargestellt.
Abbildung 6-26. Verwenden von IHostedService in einem WebHost im Vergleich zu einem Host
ASP.NET Core 1.x und 2.x unterstützen IWebHost
für Hintergrundprozesse in Web-Apps. .NET Core 2.1 und höhere Versionen unterstützen IHost
für Hintergrundprozesse in einfachen Konsolen-Apps. Beachten Sie den Unterschied zwischen WebHost
und Host
.
Eine WebHost
(Basisklasse implementieren IWebHost
) in ASP.NET Core 2.0 ist das Infrastrukturartefakt, das Sie zum Bereitstellen von HTTP-Serverfeatures für Ihren Prozess verwenden, z. B. wenn Sie eine MVC-Web-App oder einen Web-API-Dienst implementieren. Diese Klasse enthält in ASP.NET Core alle neuen Infrastrukturfunktionen, sodass Sie u. a. die Abhängigkeitsinjektion verwenden und in Anforderungspipelines Middleware einfügen können. Der WebHost
verwendet genau diese IHostedServices
für Hintergrundaufgaben.
Eine Host
(Basisklasse, die IHost
implementiert) wurde in .NET Core 2.1 eingeführt. Mit Host
können Sie eine ähnliche Infrastruktur wie mit WebHost
(Dependency Injection, gehostete Dienste usw.) verwenden. Der Unterschied besteht darin, dass Sie einen einfacheren und schlankeren Prozess für den Host verwenden und auf Verknüpfungen mit MVC, einer Web-API oder HTTP-Serverfunktionen verzichten.
Daher können Sie entweder einen speziellen Hostprozess mit IHost
erstellen, um die gehosteten Dienste zu verwalten und sonst nichts, einen solchen Microservice, der nur für das Hosting der IHostedServices
erstellt wurde, oder Sie können alternativ eine vorhandene ASP.NET Core WebHost
erweitern, wie z. B. eine vorhandene ASP.NET Core Web-API oder MVC-App.
Jeder Ansatz hat Je nach Geschäfts- und Skalierbarkeitsbedarf Vor- und Nachteile. Die untere Linie ist im Wesentlichen, dass, wenn Ihre Hintergrundaufgaben nichts mit HTTP (IWebHost
) zu tun haben, sie verwenden IHost
sollten.
Registrieren gehosteter Dienste bei Ihrem Webhoster oder Host
Lassen Sie uns eine detaillierte Analyse der IHostedService
Schnittstelle durchführen, da deren Verwendung in einem WebHost
oder in einem Host
ziemlich ähnlich ist.
SignalR ist ein Beispiel für ein Element, das gehostete Dienste nutzt, aber Sie können es auch für viel einfachere Dinge verwenden, wie:
- Eine Hintergrundaufgabe, die eine Datenbank abfragt, um nach Änderungen zu suchen.
- Eine geplante Aufgabe, die regelmäßig einen Cache aktualisiert.
- Eine Implementierung von QueueBackgroundWorkItem, mit der eine Aufgabe in einem Hintergrundthread ausgeführt werden kann.
- Verarbeitung von Nachrichten aus einer Nachrichtenwarteschlange im Hintergrund einer Web-App, während dabei allgemeine Dienste wie z. B.
ILogger
genutzt werden. - Eine Hintergrundaufgabe wurde gestartet mit
Task.Run()
.
Sie können grundsätzlich jede dieser Aktionen an eine Hintergrundaufgabe auslagern, die IHostedService
implementiert.
Die Art, wie Sie eines oder mehrere IHostedServices
in Ihr WebHost
oder Host
einfügen, besteht darin, sie über die AddHostedService-Erweiterungsmethode in einem ASP.NET Core WebHost
(oder in einer Host
ab .NET Core 2.1) zu registrieren. Grundsätzlich müssen Sie die gehosteten Dienste innerhalb des Anwendungsstarts in Program.cs registrieren.
//Other DI registrations;
// Register Hosted Services
builder.Services.AddHostedService<GracePeriodManagerService>();
builder.Services.AddHostedService<MyHostedServiceB>();
builder.Services.AddHostedService<MyHostedServiceC>();
//...
Der Code für den gehosteten Dienst GracePeriodManagerService
entspricht dem Code aus dem Microservice für Bestellungen in eShopOnContainers. Bei den anderen beiden Diensten handelt es sich hingegen nur um zwei zusätzliche Beispiele.
Die Ausführung des IHostedService
-Hintergrundtasks wird mit der Lebensdauer der Anwendung (also des Hosts oder des Microservices) koordiniert. Die Tasks werden registriert, wenn die Anwendung gestartet und eine ordnungsgemäße Aktion ausgeführt oder wenn die Anwendung beendet wird und dabei Ressourcen bereinigt werden.
Ohne Verwendung IHostedService
können Sie immer einen Hintergrundthread starten, um eine beliebige Aufgabe auszuführen. Zum Beendigungszeitpunkt der Anwendung würde der Thread dann einfach beendet werden, und ordnungsgemäße Aktionen zur Bereinigung von Ressourcen könnten nicht ausgeführt werden.
Die IHostedService-Schnittstelle
Wenn Sie ein IHostedService
registrieren, ruft .NET die Methoden StartAsync()
und StopAsync()
Ihres IHostedService
-Typs während des Starts und Stops der Anwendung auf. Weitere Informationen finden Sie in der IHostedService-Schnittstelle.
Wie Sie sich vorstellen können, können Sie mehrere Implementierungen von IHostedService erstellen und alle in Program.cs registrieren, wie zuvor gezeigt. Alle gehosteten Dienste werden gestartet und zusammen mit der Anwendung/Microservice beendet.
Als Entwickler sind Sie dafür verantwortlich, die Stoppaktion Ihrer Dienste zu behandeln, wenn die Methode StopAsync()
vom Host ausgelöst wird.
Implementieren von IHostedService mit einer benutzerdefinierten gehosteten Dienstklasse, die von der BackgroundService-Basisklasse abgeleitet wird
Sie können ihre benutzerdefinierte gehostete Dienstklasse von Grund auf neu erstellen und implementieren IHostedService
, wie Sie dies tun müssen, wenn Sie .NET Core 2.0 und höher verwenden.
Da die meisten Hintergrundaufgaben jedoch ähnliche Anforderungen hinsichtlich der Verwaltung von Abbruchtoken und anderen typischen Vorgängen haben, gibt es eine bequeme abstrakte Basisklasse, von der Sie ableiten können ( BackgroundService
verfügbar seit .NET Core 2.1).
Diese Klasse fasst die wesentlichen Aufgaben zusammen, die zum Einrichten der Hintergrundtasks erforderlich sind.
Der nächste Code ist die abstrakte BackgroundService-Basisklasse, die in .NET implementiert ist.
// 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();
}
}
Wenn Sie von der vorherigen abstrakten Basisklasse ableiten, müssen Sie dank der geerbten Implementierung einfach die ExecuteAsync()
-Methode in Ihrer eigenen benutzerdefinierten gehosteten Dienstklasse implementieren, wie im folgenden vereinfachten Code von eShopOnContainers, der eine Datenbank abfragt und bei Bedarf Integrationsereignisse in den Ereignisbus veröffentlicht.
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.");
}
.../...
}
Im Fall von eShopOnContainers wird eine Anwendungsmethode ausgeführt, durch die eine Datenbanktabelle abgefragt wird. Diese sucht nach Bestellungen mit einem bestimmten Zustand. Beim Übernehmen von Änderungen werden Integrationsereignisse über den Ereignisbus veröffentlicht (im Hintergrund kann RabbitMQ oder Azure Service Bus verwendet werden).
Natürlich können Sie stattdessen alle anderen Geschäftlichen Hintergrundaufgaben ausführen.
Standardmäßig ist das Abbruch-Token mit einem Timeout von 5 Sekunden eingestellt, aber Sie können diesen Wert ändern, wenn Sie WebHost
mithilfe der UseShutdownTimeout
Erweiterung von IWebHostBuilder
erstellen. Der Dienst muss also innerhalb von fünf Sekunden beendet werden, da er ansonsten sofort beendet wird.
Der folgende Code würde diese Zeit in 10 Sekunden ändern.
WebHost.CreateDefaultBuilder(args)
.UseShutdownTimeout(TimeSpan.FromSeconds(10))
...
Zusammenfassungsklassendiagramm
Die folgende Abbildung zeigt eine visuelle Zusammenfassung der Klassen und Schnittstellen, die bei der Implementierung von IHostedServices beteiligt sind.
Abbildung 6-27. Klassendiagramm mit mehreren Klassen und Schnittstellen im Zusammenhang mit IHostedService
Klassendiagramm: IWebHost und IHost können viele Dienste hosten, die von BackgroundService erben, wodurch IHostedService implementiert wird.
Überlegungen zur Bereitstellung und wesentliche Erkenntnisse
Es ist wichtig zu beachten, dass sich die Art und Weise, wie Sie Ihre ASP.NET Core WebHost
oder .NET Host
bereitstellen, auf die endgültige Lösung auswirken kann. Wenn Sie WebHost
beispielsweise auf IIS oder in der regulären Azure App Service-Lösung bereitstellen, kann der Host durch den Neustart eines Anwendungspools heruntergefahren werden. Wenn Sie Ihren Host jedoch als Container in einem Orchestrator wie Kubernetes bereitstellen, können Sie die garantierte Anzahl von Liveinstanzen Ihres Hosts steuern. Darüber hinaus könnten Sie andere Ansätze in der Cloud berücksichtigen, die speziell für diese Szenarien wie Azure Functions erstellt wurden. Wenn Der Dienst immer ausgeführt werden muss und auf einem Windows Server bereitgestellt wird, können Sie einen Windows-Dienst verwenden.
Auch wenn eine WebHost
-Instanz in einem Anwendungspool bereitgestellt würde, müssten andere Szenarios wie das Leeren oder nochmalige Auffüllen des speicherinternen Anwendungscaches berücksichtigt werden.
Die IHostedService
Schnittstelle bietet eine bequeme Möglichkeit, Hintergrundaufgaben in einer ASP.NET Core-Webanwendung (in .NET Core 2.0 und höheren Versionen) oder in einem beliebigen Prozess/Host (ab .NET Core 2.1 mit IHost
) zu starten. Ihr Hauptvorteil besteht darin, dass Sie bei einem ordnungsgemäßen Abbruch den Code Ihrer Hintergrundaufgaben bereinigen können, wenn der Host heruntergefahren wird.
Weitere Ressourcen
Erstellen eines geplanten Vorgangs in ASP.NET Core/Standard 2.0
https://blog.maartenballiauw.be/post/2017/08/01/building-a-scheduled-cache-updater-in-aspnet-core-2.htmlImplementieren von IHostedService in ASP.NET Core 2.0
https://www.stevejgordon.co.uk/asp-net-core-2-ihostedserviceGenericHost-Beispiel mit ASP.NET Core 2.1
https://github.com/aspnet/Hosting/tree/release/2.1/samples/GenericHostSample