Graindienste
Graindienste sind remote zugängliche, partitionierte Dienste zur Unterstützung der Funktionalitätsgrains. Jede Instanz eines Graindiensts ist verantwortlich für einige Grains, und diese Grains können einen Verweis auf den Graindienst abrufen, der derzeit für die Wartung mithilfe eines GrainServiceClient
-Elements verantwortlich ist.
Graindienste werden in Szenarios verwendet, in denen die Verantwortung für die Verwaltung von Grains um den Orleans-Cluster herum verteilt werden sollte. Beispielsweise werden Orleans-Erinnerungen mithilfe von Graindiensten implementiert: Jeder Silo ist für die Verarbeitung von Erinnerungsvorgängen für eine Teilmenge von Grains verantwortlich und benachrichtigt diese Grains, wenn die entsprechenden Erinnerungen ausgelöst werden.
Graindienste werden für Silos konfiguriert und beim Start des Silos initialisiert, bevor die Siloinitialisierung abgeschlossen ist. Sie werden nicht erfasst, wenn sie sich im Leerlauf befinden, und ihre Lebensdauer verlängert sich stattdessen um die Lebensdauer des Silos selbst.
Erstellen einer GrainService-Klasse
Eine GrainService-Klasse ist ein spezielles Grain, das keine stabile Identität aufweist und vom Start bis zum Herunterfahren in jedem Silo ausgeführt wird. Bei der Implementierung einer IGrainService-Schnittstelle sind mehrere Schritte erforderlich.
Definieren Sie die Kommunikationsschnittstelle des Graindiensts. Die Schnittstelle einer
GrainService
-Klasse wird mit den gleichen Prinzipien erstellt, die Sie zum Erstellen der Schnittstelle eines Grains verwenden würden.public interface IDataService : IGrainService { Task MyMethod(); }
Erstellen Sie den
DataService
-Graindienst. Sie sollten wissen, dass Sie auch eine IGrainFactory-Schnittstelle einfügen können, um Grainaufrufe über dieGrainService
-Klasse durchzuführen.[Reentrant] public class DataService : GrainService, IDataService { readonly IGrainFactory _grainFactory; public DataService( IServiceProvider services, GrainId id, Silo silo, ILoggerFactory loggerFactory, IGrainFactory grainFactory) : base(id, silo, loggerFactory) { _grainFactory = grainFactory; } public override Task Init(IServiceProvider serviceProvider) => base.Init(serviceProvider); public override Task Start() => base.Start(); public override Task Stop() => base.Stop(); public Task MyMethod() { // TODO: custom logic here. return Task.CompletedTask; } }
[Reentrant] public class DataService : GrainService, IDataService { readonly IGrainFactory _grainFactory; public DataService( IServiceProvider services, IGrainIdentity id, Silo silo, ILoggerFactory loggerFactory, IGrainFactory grainFactory) : base(id, silo, loggerFactory) { _grainFactory = grainFactory; } public override Task Init(IServiceProvider serviceProvider) => base.Init(serviceProvider); public override Task Start() => base.Start(); public override Task Stop() => base.Stop(); public Task MyMethod() { // TODO: custom logic here. return Task.CompletedTask; } }
Erstellen Sie eine Schnittstelle für die GrainServiceClient<TGrainService>-Klasse
GrainServiceClient
, die von anderen Grains zum Herstellen einer Verbindung mit derGrainService
-Klasse verwendet werden soll.public interface IDataServiceClient : IGrainServiceClient<IDataService>, IDataService { }
Erstellen Sie den Graindienstclient. Clients fungieren in der Regel als Proxys für die Graindienste, die sie zum Ziel haben, sodass Sie in der Regel eine Methode für jede Methode für den Zieldienst hinzufügen. Diese Methoden müssen einen Verweis auf den Graindienst abrufen, auf den sie ausgelegt sind, damit sie ihn aufrufen können. Die Basisklasse
GrainServiceClient<T>
stellt mehrere Überladungen derGetGrainService
-Methode bereit, die einen Grainverweis zurückgeben können, der einerGrainId
, einem numerischen Hash (uint
) oder einerSiloAddress
entspricht. Die letzten beiden Überladungen gelten für erweiterte Szenarios, in denen Entwickler*innen einen anderen Mechanismus verwenden möchten, um Hosts die Verantwortung zu übertragen oder einen Host direkt zu adressieren. Im folgenden Beispielcode definieren Sie die EigenschaftGrainService
, dieIDataService
für das Grain zurückgibt, das denDataServiceClient
aufruft. Dazu verwenden Sie die ÜberladungGetGrainService(GrainId)
in Verbindung mit derCurrentGrainReference
-Eigenschaft.public class DataServiceClient : GrainServiceClient<IDataService>, IDataServiceClient { public DataServiceClient(IServiceProvider serviceProvider) : base(serviceProvider) { } // For convenience when implementing methods, you can define a property which gets the IDataService // corresponding to the grain which is calling the DataServiceClient. private IDataService GrainService => GetGrainService(CurrentGrainReference.GrainId); public Task MyMethod() => GrainService.MyMethod(); }
Erstellen Sie den tatsächlichen Graindienstclient. Er fungiert einfach als Proxy für den Datendienst. Leider müssen Sie manuell alle Methodenzuordnungen eingeben, die nur aus einer einfachen Zeile bestehen.
public class DataServiceClient : GrainServiceClient<IDataService>, IDataServiceClient { public DataServiceClient(IServiceProvider serviceProvider) : base(serviceProvider) { } public Task MyMethod() => GrainService.MyMethod(); }
Implementieren Sie den Graindienstclient in die anderen Grains, die ihn benötigen. Es ist nicht garantiert, dass der
GrainServiceClient
auf dieGrainService
-Klasse im lokalen Silo zugreifen kann. Ihr Befehl wurde möglicherweise an eine beliebigeGrainService
-Klasse für ein beliebiges Silo im Cluster gesendet.public class MyNormalGrain: Grain<NormalGrainState>, INormalGrain { readonly IDataServiceClient _dataServiceClient; public MyNormalGrain( IGrainActivationContext grainActivationContext, IDataServiceClient dataServiceClient) => _dataServiceClient = dataServiceClient; }
Konfigurieren Sie den Graindienst und den Graindienstclient im Silo. Sie müssen dies tun, damit der Silo die
GrainService
-Klasse startet.(ISiloHostBuilder builder) => builder.ConfigureServices( services => services.AddGrainService<DataService>() .AddSingleton<IDataServiceClient, DataServiceClient>());
Zusätzliche Hinweise
Es gibt eine Erweiterungsmethode für GrainServicesSiloBuilderExtensions.AddGrainService, mit der Graindienste registriert werden.
services.AddSingleton<IGrainService>(
serviceProvider => GrainServiceFactory(grainServiceType, serviceProvider));
Das Silo ruft aus dem Dienstanbieter IGrainService
-Typen auf, wenn orleans/src/Orleans.Runtime/Silo/Silo.cs gestartet wird.
var grainServices = this.Services.GetServices<IGrainService>();
Das GrainService
-Projekt sollte auf das NuGet-Paket Microsoft.Orleans.Runtime verweisen.
Das GrainService
-Projekt sollte auf das Microsoft.Orleans.OrleansRuntime-NuGet-Paket verweisen.
Damit dies funktioniert, müssen Sie sowohl den Dienst als auch den entsprechenden Client registrieren. Der Code sieht ungefähr wie folgt aus:
var builder = new HostBuilder()
.UseOrleans(c =>
{
c.AddGrainService<DataService>() // Register GrainService
.ConfigureServices(services =>
{
// Register Client of GrainService
services.AddSingleton<IDataServiceClient, DataServiceClient>();
});
})