Grain 服务

Grain 服务是远程可访问的分区服务,用于支持功能 grain。 grain 服务的每个实例都负责一些 grain 集,这些 grain 可以获取对 grain 服务的引用,该服务当前负责通过使用 GrainServiceClient 来维护它们。

grain 服务的存在是为了支持应围绕 Orleans 群集分散维护 grain 的责任的情况。 例如,Orleans 提醒是使用 grain 服务实现的:每个 silo 负责处理一部分 grain 的提醒操作,并在提醒触发时通知这些 grain。

grain 服务在 silo 上配置,并在 silo 启动时(在 silo 完成初始化之前)初始化。 它们不会在空闲时收集,而是具有延长 silo 本身生存期的生存期。

创建 GrainService

GrainService 是一种特殊的 grain;这种 grain 没有稳定的标识,并且在每个 silo 中运行(从启动到关闭)。 实现 IGrainService 接口时涉及几个步骤。

  1. 定义 grain 服务通信接口。 GrainService 的接口是使用你要用于构建 grain 的接口的相同原则构建的。

    public interface IDataService : IGrainService
    {
        Task MyMethod();
    }
    
  2. 创建 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;
        }
    }
    
  3. GrainServiceClient<TGrainService>GrainServiceClient 创建一个接口,供其他 grain 用来连接到 GrainService

    public interface IDataServiceClient : IGrainServiceClient<IDataService>, IDataService
    {
    }
    
  1. 创建 grain 服务客户端。 客户端通常充当它们所面向的 grain 服务的代理,因此通常会在目标服务上为每个方法添加一个方法。 这些方法需要获取对它们所面向的 grain 服务的引用,以便可以调用该服务。 GrainServiceClient<T> 基类提供了 GetGrainService 方法的多个重载,该方法可以返回对应于 GrainId、数值哈希 (uint) 或 SiloAddress 的 grain 引用。 后两个重载适用于开发人员希望使用不同的机制将责任映射到主机或想要直接处理主机的高级情况。 在下面的示例代码中,我们定义了一个属性 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();
    }
    
  1. 创建实际的 grain 服务客户端。 它几乎只是充当数据服务的代理。 遗憾的是,必须手动键入所有方法映射,这些映射只是简单的单行内容。

    public class DataServiceClient : GrainServiceClient<IDataService>, IDataServiceClient
    {
        public DataServiceClient(IServiceProvider serviceProvider)
            : base(serviceProvider)
        {
        }
    
        public Task MyMethod() => GrainService.MyMethod();
    }
    
  1. 将 grain 服务客户端注入到需要它的其他 grain。 不能保证 GrainServiceClient 一定访问本地 silo 上的 GrainService。 你的命令可能会发送到群集中任何 silo 上的 GrainService

    public class MyNormalGrain: Grain<NormalGrainState>, INormalGrain
    {
        readonly IDataServiceClient _dataServiceClient;
    
        public MyNormalGrain(
            IGrainActivationContext grainActivationContext,
            IDataServiceClient dataServiceClient) =>
                _dataServiceClient = dataServiceClient;
    }
    
  2. 在 silo 中配置 grain 服务和 grain 服务客户端。 你需要执行此操作,以便该 silo 将启动 GrainService

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

附加说明

用于注册 grain 服务的 GrainServicesSiloBuilderExtensions.AddGrainService 上有一个扩展方法。

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

silo 在启动时从服务提供商提取 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>();
        });
    })