Службы зерна
Службы зерна являются удаленными, секционированными службами для поддержки функциональных возможностей. Каждый экземпляр службы зерна отвечает за некоторый набор зерна, и эти зерна могут получить ссылку на службу зерна, которая в настоящее время отвечает за обслуживание их с помощью GrainServiceClient
.
Службы зерна существуют для поддержки случаев, когда ответственность за обслуживание зерна должна распространяться по всему кластеру Orleans . Например, Orleans напоминания реализуются с помощью служб зерна: каждый сило отвечает за обработку операций напоминания за подмножество зерна и уведомляет эти зерна при срабатывании напоминаний.
Службы зерна настраиваются на оси и инициализируются при запуске silo, прежде чем silo завершит инициализацию. Они не собираются при бездействии и вместо этого имеют время существования, которые расширяются в течение всего времени существования самого сило.
Создание службы GrainService
Это GrainService специальное зерно; тот, который не имеет стабильного удостоверения, и работает в каждом сило от запуска до завершения работы. При реализации IGrainService интерфейса необходимо выполнить несколько шагов.
Определите интерфейс обмена данными службы зерна. Интерфейс
GrainService
создается с помощью того же принципа, что и для создания интерфейса зерна.public interface IDataService : IGrainService { Task MyMethod(); }
DataService
Создайте службу зерна. Хорошо знать, что вы также можете внедрить так IGrainFactory , чтобы вы могли делать зерна вызовы от вашего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; } }
Создайте интерфейс для использования другими зернами для GrainServiceClient<TGrainService>
GrainServiceClient
подключения к немуGrainService
.public interface IDataServiceClient : IGrainServiceClient<IDataService>, IDataService { }
Создайте клиент службы зерна. Клиенты обычно используют прокси-серверы для целевых служб, поэтому обычно добавляется метод для каждого метода в целевой службе. Эти методы должны получить ссылку на службу зерна, на которую они нацелены, чтобы они могли вызывать ее. Базовый
GrainServiceClient<T>
класс предоставляет несколько перегрузокGetGrainService
метода, который может возвращать ссылку на зерно, соответствующуюGrainId
числовому хэшу (uint
) или aSiloAddress
. Последние две перегрузки предназначены для сложных случаев, когда разработчик хочет использовать другой механизм для сопоставления ответственности с узлами или хочет напрямую обратиться к узлу. В приведенном ниже примере кода мы определим свойство,GrainService
которое возвращаетIDataService
для зерна, вызывающего объектDataServiceClient
. Для этого мы используем перегрузкуGetGrainService(GrainId)
вместе со свойством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(); }
Создайте фактический клиент службы зерна. Он в значительной степени выступает в качестве прокси-сервера для службы данных. К сожалению, необходимо вручную ввести все сопоставления методов, которые просто простые однострочный.
public class DataServiceClient : GrainServiceClient<IDataService>, IDataServiceClient { public DataServiceClient(IServiceProvider serviceProvider) : base(serviceProvider) { } public Task MyMethod() => GrainService.MyMethod(); }
Вставить клиент службы зерна в другие зерна, необходимые ему. Доступ
GrainServiceClient
кGrainService
локальному сило не гарантируется. Ваша команда может быть отправленаGrainService
в любой узел в кластере.public class MyNormalGrain: Grain<NormalGrainState>, INormalGrain { readonly IDataServiceClient _dataServiceClient; public MyNormalGrain( IGrainActivationContext grainActivationContext, IDataServiceClient dataServiceClient) => _dataServiceClient = dataServiceClient; }
Настройте клиент службы зерна и службы зерна в silo. Это необходимо сделать так, чтобы сило начнется
GrainService
.(ISiloHostBuilder builder) => builder.ConfigureServices( services => services.AddGrainService<DataService>() .AddSingleton<IDataServiceClient, DataServiceClient>());
Дополнительные примечания
Существует метод расширения, в GrainServicesSiloBuilderExtensions.AddGrainService котором используется для регистрации служб зерна.
services.AddSingleton<IGrainService>(
serviceProvider => GrainServiceFactory(grainServiceType, serviceProvider));
При запуске silo извлекает IGrainService
типы из поставщика услуг: orleans/src/Orleans. Среда выполнения/Silo/Silo.cs
var grainServices = this.Services.GetServices<IGrainService>();
Microsoft .Orleans. Пакет NuGet среды выполнения должен ссылаться на GrainService
проект.
Microsoft .Orleans. Пакет NuGet OrleansRuntime должен ссылаться на GrainService
проект.
Чтобы это работало, необходимо зарегистрировать как службу, так и его клиент. Код выглядит примерно так:
var builder = new HostBuilder()
.UseOrleans(c =>
{
c.AddGrainService<DataService>() // Register GrainService
.ConfigureServices(services =>
{
// Register Client of GrainService
services.AddSingleton<IDataServiceClient, DataServiceClient>();
});
})