Serviços de Grãos
Os Serviços de Grãos são serviços particionados e acessíveis remotamente para suportar os grãos de funcionalidade. Cada instância de um serviço de grãos é responsável por algum conjunto de grãos e esses grãos podem obter uma referência ao serviço de grãos que atualmente é responsável por atendê-los usando um GrainServiceClient
.
Os Serviços de Grãos existem para dar suporte aos casos em que a responsabilidade pela manutenção dos grãos deve ser distribuída ao redor do Orleans cluster. Por exemplo, Orleans os Lembretes são implementados usando serviços de grãos: cada silo é responsável por lidar com operações de lembrete para um subconjunto de grãos e notificar esses grãos quando seus lembretes são acionados.
Os Serviços de Grão são configurados em silos e são inicializados quando o silo é iniciado, antes que o silo conclua a inicialização. Eles não são coletados quando ociosos e, em vez disso, têm vidas que se estendem pela vida útil do próprio silo.
Criar um GrainService
A GrainService é um grão especial, que não tem identidade estável e funciona em todos os silos desde a inicialização até o desligamento. Há várias etapas envolvidas na implementação de uma IGrainService interface.
Defina a interface de comunicação do serviço de grão. A interface de um
GrainService
é construída usando os mesmos princípios que você usaria para construir a interface de um grão.public interface IDataService : IGrainService { Task MyMethod(); }
Crie o
DataService
serviço de grãos. É bom saber que você também pode injetar um IGrainFactory para que você possa fazer chamadas de grãos do seuGrainService
.[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; } }
Crie uma interface para o GrainServiceClient<TGrainService>
GrainServiceClient
a ser usado por outros grãos para se conectar aoGrainService
.public interface IDataServiceClient : IGrainServiceClient<IDataService>, IDataService { }
Crie o cliente de serviço de grãos. Os clientes normalmente atuam como proxies para os serviços de grãos que eles segmentam, então você geralmente adicionará um método para cada método no serviço de destino. Esses métodos precisarão obter uma referência ao serviço de grãos que eles visam para que possam chamá-lo. A
GrainServiceClient<T>
classe base fornece várias sobrecargas do método que podem retornar uma referência deGetGrainService
grão correspondente a umGrainId
, um hash numérico (uint
) ou umSiloAddress
. As duas últimas sobrecargas são para casos avançados em que um desenvolvedor deseja usar um mecanismo diferente para mapear a responsabilidade para hosts ou deseja abordar um host diretamente. Em nosso código de exemplo abaixo, definimos uma propriedade,GrainService
, que retorna oIDataService
para o grão que está chamando oDataServiceClient
. Para isso, usamos aGetGrainService(GrainId)
sobrecarga em conjunto com oCurrentGrainReference
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(); }
Crie o cliente de serviço de grão real. Ele praticamente atua apenas como um proxy para o serviço de dados. Infelizmente, você tem que digitar manualmente todos os mapeamentos de método, que são apenas simples one-liners.
public class DataServiceClient : GrainServiceClient<IDataService>, IDataServiceClient { public DataServiceClient(IServiceProvider serviceProvider) : base(serviceProvider) { } public Task MyMethod() => GrainService.MyMethod(); }
Injete o cliente de serviço de grãos nos outros grãos que precisam. O
GrainServiceClient
não é garantido para acessar o siloGrainService
local. Seu comando pode ser enviado para oGrainService
em qualquer silo no cluster.public class MyNormalGrain: Grain<NormalGrainState>, INormalGrain { readonly IDataServiceClient _dataServiceClient; public MyNormalGrain( IGrainActivationContext grainActivationContext, IDataServiceClient dataServiceClient) => _dataServiceClient = dataServiceClient; }
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 no GrainServicesSiloBuilderExtensions.AddGrainService qual é usado 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: orleans/src/Orleans. Tempo de execução/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 isto funcione tem de registar tanto o serviço como o 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>();
});
})