Dela via


Grain Services

Grain Services är fjärranslutna, partitionerade tjänster för stöd för funktionsintervall. Varje instans av en korntjänst ansvarar för vissa uppsättningar korn och dessa korn kan få en referens till korntjänsten som för närvarande ansvarar för att underhålla dem med hjälp av en GrainServiceClient.

Grain Services finns för att stödja fall där ansvaret för att underhålla korn bör distribueras runt Orleans klustret. Påminnelser implementeras till exempel Orleans med hjälp av spannmålstjänster: varje silo ansvarar för att hantera påminnelseåtgärder för en delmängd korn och meddela dessa korn när deras påminnelser utlöses.

Grain Services konfigureras på silor och initieras när silon startar, innan silon slutför initieringen. De samlas inte in när de är inaktiva och har i stället livslängder som sträcker sig över silons livslängd.

Skapa en GrainService

A GrainService är ett särskilt korn, ett som inte har någon stabil identitet och körs i varje silo från start till avstängning. Det finns flera steg när du implementerar ett IGrainService gränssnitt.

  1. Definiera kommunikationsgränssnittet för korntjänsten. Gränssnittet för en GrainService skapas med samma principer som du skulle använda för att skapa gränssnittet för ett korn.

    public interface IDataService : IGrainService
    {
        Task MyMethod();
    }
    
  2. DataService Skapa korntjänsten. Det är bra att veta att du också kan mata in en IGrainFactory så att du kan göra korn samtal från din 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. Skapa ett gränssnitt som GrainServiceClient<TGrainService>GrainServiceClient ska användas av andra korn för att ansluta till GrainService.

    public interface IDataServiceClient : IGrainServiceClient<IDataService>, IDataService
    {
    }
    
  1. Skapa korntjänstklienten. Klienter fungerar vanligtvis som proxyservrar för de korntjänster som de riktar in sig på, så du lägger vanligtvis till en metod för varje metod i måltjänsten. Dessa metoder måste hämta en referens till den korntjänst som de riktar in sig på så att de kan anropa den. Basklassen GrainServiceClient<T> innehåller flera överlagringar av GetGrainService metoden som kan returnera en kornreferens som motsvarar en GrainId, en numerisk hash (uint) eller en SiloAddress. De två senare överlagringarna gäller avancerade fall där en utvecklare vill använda en annan mekanism för att mappa ansvar till värdar eller vill adressera en värd direkt. I vår exempelkod nedan definierar vi en egenskap, GrainService, som returnerar IDataService för kornet som anropar DataServiceClient. För att göra det använder vi överlagringen GetGrainService(GrainId) tillsammans med CurrentGrainReference egenskapen .

    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. Skapa klienten för den faktiska korntjänsten. Det fungerar i stort sett bara som en proxy för datatjänsten. Tyvärr måste du manuellt skriva in alla metodmappningar, som bara är enkla one-liners.

    public class DataServiceClient : GrainServiceClient<IDataService>, IDataServiceClient
    {
        public DataServiceClient(IServiceProvider serviceProvider)
            : base(serviceProvider)
        {
        }
    
        public Task MyMethod() => GrainService.MyMethod();
    }
    
  1. Mata in korntjänstklienten i de andra kornen som behöver den. GrainServiceClient Är inte garanterat att komma åt på GrainService den lokala silo. Kommandot kan eventuellt skickas till GrainService på valfri silo i klustret.

    public class MyNormalGrain: Grain<NormalGrainState>, INormalGrain
    {
        readonly IDataServiceClient _dataServiceClient;
    
        public MyNormalGrain(
            IGrainActivationContext grainActivationContext,
            IDataServiceClient dataServiceClient) =>
                _dataServiceClient = dataServiceClient;
    }
    
  2. Konfigurera korntjänst- och korntjänstklienten i silon. Du måste göra detta så att silon startar GrainService.

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

Ytterligare kommentarer

Det finns en tilläggsmetod GrainServicesSiloBuilderExtensions.AddGrainService som används för att registrera spannmålstjänster.

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

Silon hämtar typerna IGrainService från tjänstleverantören vid start: orleans/src/Orleans.Runtime/Silo/Silo.cs

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

Microsoft .Orleans. NuGet-paketet Runtime ska refereras till GrainService av projektet.

Microsoft .Orleans. OrleansRuntime NuGet-paketet ska refereras av GrainService projektet.

För att detta ska fungera måste du registrera både tjänsten och dess klient. Koden ser ut ungefär så här:

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