Partilhar via


Serviços de cereais

Os serviços de grãos são acessíveis remotamente, serviços particionados para suportar a funcionalidade de grãos. Cada instância de um serviço de grãos é responsável por algum conjunto de grãos. Esses grãos podem obter uma referência ao serviço de grãos atualmente responsável por atendê-los usando um GrainServiceClient.

Os serviços de grãos existem para apoiar os casos em que a responsabilidade pela prestação de serviços aos grãos deve ser distribuída no Orleans cluster. Por exemplo, Orleans os Lembretes são implementados usando serviços de grãos: cada silo lida com operações de lembrete para um subconjunto de grãos e notifica esses grãos quando seus lembretes são acionados.

Você configura serviços de grãos em silos. Eles inicializam quando o silo inicia, antes que o silo conclua a inicialização. Eles não são coletados quando ociosos; em vez disso, a sua vida útil prolonga-se pela vida útil do próprio silo.

Criar um serviço de grãos

A GrainService é um grão especial: não possui uma identidade estável e está presente em todos os silos desde a inicialização até ao encerramento. A implementação de uma IGrainService interface envolve várias etapas.

  1. Defina a interface de comunicação do serviço de grão. Construa a interface de um GrainService usando os mesmos princípios que utiliza para construir uma interface granular.

    public interface IDataService : IGrainService
    {
        Task MyMethod();
    }
    
  2. Crie o DataService serviço de grãos. É útil saber que também é possível injetar um IGrainFactory para fazer chamadas de grãos a partir do teu 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. Crie uma interface para o GrainServiceClient<TGrainService>GrainServiceClient que outros grãos usarão para se conectar ao GrainService.

    public interface IDataServiceClient : IGrainServiceClient<IDataService>, IDataService
    {
    }
    
  4. Crie o cliente de serviço de grãos. Os clientes normalmente atuam como proxies para os serviços de grain que eles visam, então você geralmente adiciona um método para cada método no serviço de destino. Esses métodos precisam obter uma referência ao serviço de grãos alvo para que possam chamá-lo. A classe base GrainServiceClient<T> fornece várias sobrecargas do método GetGrainService que podem retornar uma referência de grain correspondente a um GrainId, um hash numérico (uint) ou um SiloAddress. As duas últimas sobrecargas destinam-se a casos avançados em que se pretende usar um mecanismo diferente para mapear responsabilidades para os hosts ou endereçar um host diretamente. No código de exemplo abaixo, definimos uma propriedade, GrainService, que devolve o IDataService para o grain que faz a chamada de DataServiceClient. Para isso, usamos a GetGrainService(GrainId) sobrecarga em conjunto com o CurrentGrainReference imóvel.

    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();
    }
    
  5. Injete o cliente de serviço de grãos nos outros grãos que precisam. O GrainServiceClient não tem garantia de aceder ao GrainService no silo local. Seu comando pode ser enviado para o GrainService em qualquer silo no cluster.

    public class MyNormalGrain: Grain<NormalGrainState>, INormalGrain
    {
        readonly IDataServiceClient _dataServiceClient;
    
        public MyNormalGrain(
            IGrainActivationContext grainActivationContext,
            IDataServiceClient dataServiceClient) =>
                _dataServiceClient = dataServiceClient;
    }
    
  6. Configure o serviço de grão e o cliente de serviço de grão no silo. Você precisa fazer isso para que o silo inicie o GrainService.

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

Notas adicionais

Há um método de extensão, GrainServicesSiloBuilderExtensions.AddGrainServiceusado para registrar serviços de grãos.

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

O silo busca IGrainService tipos do provedor de serviços ao iniciar (consulte orleans/src/Orleans.Runtime/Silo/Silo.cs):

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

A Microsoft.Orleans. O pacote NuGet de tempo de execução deve ser referenciado GrainService pelo projeto.

A Microsoft.Orleans. O pacote NuGet OrleansRuntime deve ser referenciado GrainService pelo projeto.

Para que isso funcione, você deve registrar tanto o serviço quanto seu cliente. O código tem a seguinte aparência:

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