粮食服务是可远程访问的分隔服务,用于支持粮食功能。 每个粒子服务实例负责管理一组粒子。 这些谷物可以通过使用 a GrainServiceClient
来引用当前负责为它们提供服务的粮食服务。
粮食服务旨在支持在Orleans群集周围分担粒度服务责任的情况。 例如,Orleans 提醒是使用粒子服务实现的:每个 Silo 处理部分粒子的提醒操作,并在提醒触发时通知这些粒子。
在筒仓上配置谷物服务。 它们在筒仓启动时就会初始化,在筒仓完成初始化之前。 空闲时不会收集它们;相反,它们的生存期会延长到仓库本身的存续期。
创建谷物服务
A GrainService 是一种特殊的“Grain”:它没有固定的身份,并在从启动到关闭的每个系统模块中运行。 实现 IGrainService 接口涉及几个步骤。
定义 grain 服务通信接口。 构建
GrainService
的接口时,请使用与构建粒度接口相同的原则。public interface IDataService : IGrainService { Task MyMethod(); }
创建
DataService
grain 服务。 知道你可以注入一个IGrainFactory,以便可以从GrainService
调用grain。[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 { }
创建 grain 服务客户端。 客户端通常作为它们目标颗粒服务的代理,因此通常会为目标服务的每个方法添加一个对应的方法。 这些方法需要获取对目标粒度服务的引用,以便它们可以调用它。 基础
GrainServiceClient<T>
类提供了多种方法GetGrainService
的重载,这些重载可以返回与GrainId
、数值哈希 (uint
) 或SiloAddress
相对应的颗粒引用。 后两个重载适用于想要使用不同的机制将责任映射到主机或直接处理主机的复杂情况。 在下面的示例代码中,我们定义了一个属性GrainService
,它返回调用DataServiceClient
的 grain 的IDataService
。 为此,我们将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(); }
将 grain 服务客户端注入到需要它的其他 grain。
GrainServiceClient
没有保证能在本地侧仓库访问GrainService
。 你的命令可能会发送到群集中任何 silo 上的GrainService
。public class MyNormalGrain: Grain<NormalGrainState>, INormalGrain { readonly IDataServiceClient _dataServiceClient; public MyNormalGrain( IGrainActivationContext grainActivationContext, IDataServiceClient dataServiceClient) => _dataServiceClient = dataServiceClient; }
在 silo 中配置 grain 服务和 grain 服务客户端。 你需要执行此操作,以便筒仓启动
GrainService
。(ISiloHostBuilder builder) => builder.ConfigureServices( services => services.AddGrainService<DataService>() .AddSingleton<IDataServiceClient, DataServiceClient>());
附加说明
有一种扩展方法, GrainServicesSiloBuilderExtensions.AddGrainService用于注册粒度服务。
services.AddSingleton<IGrainService>(
serviceProvider => GrainServiceFactory(grainServiceType, serviceProvider));
孤岛在启动时从服务提供商获取 IGrainService
类型(见 orleans/src/Orleans.Runtime/Silo/Silo.cs):
var grainServices = this.Services.GetServices<IGrainService>();
Microsoft.Orleans.Runtime NuGet 包应由 GrainService
项目引用。
Microsoft.Orleans.OrleansRuntime NuGet 包应由 GrainService
项目引用。
为了使此功能正常运行,您必须同时注册服务及其客户端。 代码与以下内容类似:
var builder = new HostBuilder()
.UseOrleans(c =>
{
c.AddGrainService<DataService>() // Register GrainService
.ConfigureServices(services =>
{
// Register Client of GrainService
services.AddSingleton<IDataServiceClient, DataServiceClient>();
});
})