Usługi ziarna

Usługi ziarna są zdalnie dostępne, partycjonowane usługi do obsługi funkcji ziarna. Każde wystąpienie usługi ziarna jest odpowiedzialne za jakiś zestaw ziarna, a te ziarna mogą uzyskać odwołanie do usługi ziarna, która jest obecnie odpowiedzialna za ich obsługę przy użyciu .GrainServiceClient

Usługi ziarna istnieją do obsługi przypadków, w których odpowiedzialność za ziarna obsługi powinny być dystrybuowane wokół klastra Orleans . Na przykład Orleans przypomnienia są implementowane przy użyciu usług ziarna: każdy silos jest odpowiedzialny za obsługę operacji przypomnienia dla podzbioru ziarna i powiadamianie tych ziarna, gdy ich przypomnienia są wyzwalane.

Usługi ziarna są konfigurowane na silosach i są inicjowane podczas uruchamiania silosu, zanim silos zakończy inicjowanie. Nie są zbierane w przypadku bezczynności i zamiast tego mają okresy istnienia, które rozciągają się na okres istnienia samego silosu.

Tworzenie usługi GrainService

A GrainService to specjalne ziarno, które nie ma stabilnej tożsamości i działa w każdym silosie od uruchomienia do zamknięcia. Podczas implementowania interfejsu IGrainService jest zaangażowanych kilka kroków.

  1. Zdefiniuj interfejs komunikacyjny usługi ziarna. Interfejs obiektu GrainService jest tworzony przy użyciu tych samych zasad, których można użyć do tworzenia interfejsu ziarna.

    public interface IDataService : IGrainService
    {
        Task MyMethod();
    }
    
  2. Utwórz usługę DataService ziarna. Dobrze jest wiedzieć, że możesz również wstrzyknąć element , IGrainFactory aby można było wykonywać wywołania ziarna z poziomu obiektu GrainService.

    [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;
        }
    }
    
  3. Utwórz interfejs, GrainServiceClient<TGrainService>GrainServiceClient który ma być używany przez inne ziarna, aby nawiązać połączenie z elementem GrainService.

    public interface IDataServiceClient : IGrainServiceClient<IDataService>, IDataService
    {
    }
    
  1. Utwórz klienta usługi ziarna. Klienci zazwyczaj działają jako serwery proxy dla usług ziarna, których dotyczą, więc zwykle dodaje się metodę dla każdej metody w usłudze docelowej. Te metody będą musiały uzyskać odwołanie do usługi ziarna, której dotyczą, aby mogły do niego wywołać. Klasa GrainServiceClient<T> bazowa udostępnia kilka przeciążeń GetGrainService metody, które mogą zwracać odwołanie ziarna odpowiadające GrainIdwartości , wartości skrótu liczbowego (uint) lub SiloAddress. Dwa ostatnie przeciążenia dotyczą zaawansowanych przypadków, w których deweloper chce użyć innego mechanizmu do mapowania odpowiedzialności na hosty lub chce bezpośrednio rozwiązać problem hosta. W poniższym przykładowym kodzie definiujemy właściwość , GrainServicektóra zwraca IDataService wartość dla ziarna wywołującego DataServiceClientelement . W tym celu używamy GetGrainService(GrainId) przeciążenia w połączeniu z właściwością CurrentGrainReference .

    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();
    }
    
  1. Utwórz rzeczywistego klienta usługi ziarna. To prawie działa jako serwer proxy dla usługi danych. Niestety, należy ręcznie wpisać wszystkie mapowania metod, które są po prostu prostymi wierszami.

    public class DataServiceClient : GrainServiceClient<IDataService>, IDataServiceClient
    {
        public DataServiceClient(IServiceProvider serviceProvider)
            : base(serviceProvider)
        {
        }
    
        public Task MyMethod() => GrainService.MyMethod();
    }
    
  1. Wstrzyknąć klienta usługi ziarna do innych ziarna, które go potrzebują. Nie GrainServiceClient ma gwarancji dostępu GrainService do lokalnego silosu. Polecenie może być potencjalnie wysyłane do GrainService dowolnego silosu w klastrze.

    public class MyNormalGrain: Grain<NormalGrainState>, INormalGrain
    {
        readonly IDataServiceClient _dataServiceClient;
    
        public MyNormalGrain(
            IGrainActivationContext grainActivationContext,
            IDataServiceClient dataServiceClient) =>
                _dataServiceClient = dataServiceClient;
    }
    
  2. Skonfiguruj klienta usługi ziarna i usługi ziarna w silosie. Należy to zrobić, aby silos uruchamiał GrainServiceelement .

    (ISiloHostBuilder builder) =>
        builder.ConfigureServices(
            services => services.AddGrainService<DataService>()
                                .AddSingleton<IDataServiceClient, DataServiceClient>());
    

Dodatkowe uwagi

Istnieje metoda rozszerzenia, na GrainServicesSiloBuilderExtensions.AddGrainService której jest używana do rejestrowania usług ziarna.

services.AddSingleton<IGrainService>(
    serviceProvider => GrainServiceFactory(grainServiceType, serviceProvider));

Silos pobiera IGrainService typy od dostawcy usług podczas uruchamiania: orlean/src/Orleans. Środowisko uruchomieniowe/silo/Silo.cs

var grainServices = this.Services.GetServices<IGrainService>();

Microsoft .Orleans. Pakiet NuGet środowiska uruchomieniowegoGrainService powinien być przywołyny przez projekt.

Microsoft .Orleans.OrleansPakiet NuGet środowiska uruchomieniowegoGrainService powinien być przywołyny przez projekt.

Aby to zadziałało, musisz zarejestrować zarówno usługę, jak i jej klienta. Kod wygląda następująco:

var builder = new HostBuilder()
    .UseOrleans(c =>
    {
        c.AddGrainService<DataService>()  // Register GrainService
        .ConfigureServices(services =>
        {
            // Register Client of GrainService
            services.AddSingleton<IDataServiceClient, DataServiceClient>();
        });
    })