精細度服務

精細度服務可從遠端存取,可分割服務以支援功能精細度。 每個精細度服務的執行個體都負責一組精細度,而這些精細度可以藉由使用 GrainServiceClient,取得目前負責為其提供服務之精細度服務的參考。

「精細度服務」存在,以支援負責服務的精細度應分散在 Orleans 叢集周圍的案例。 例如,Orleans Reminders 是使用精細度服務來實作:每個定址接收器都會負責處理一部分精細度的提醒作業,並在提醒引發時通知這些精細度。

精細度服務會在定址接收器上設定,在定址接收器啟動時並且在定址接收器完成初始化之前初始化。 閒置時不會收集,而是擁有會針對定址接收器本身延長的存留期。

建立 GrainService

GrainService 是特殊的精細度;沒有穩定的身分識別,並在每個定址接收器中執行,從啟動到關機。 實作 IGrainService 介面時牽涉到數個步驟。

  1. 定義精細度服務通訊介面。 GrainService 的介面是使用您用來建置精細度介面的相同原則所建置。

    public interface IDataService : IGrainService
    {
        Task MyMethod();
    }
    
  2. 建立 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;
        }
    }
    
  3. 建立 GrainServiceClient<TGrainService>GrainServiceClient 的介面,讓其他精細度用來連線到 GrainService

    public interface IDataServiceClient : IGrainServiceClient<IDataService>, IDataService
    {
    }
    
  1. 建立精細度服務用戶端。 用戶端通常會作為其目標精細度服務的 Proxy,因此您通常會在目標服務上為每個方法新增方法。 這些方法需要取得其目標精細度服務的參考,以便進行呼叫。 GrainServiceClient<T> 基底類別提供 GetGrainService 方法的數個多載,此方法可以傳回對應至 GrainId 的精細度參考、數值雜湊 (uint) 或 SiloAddress。 後面兩個多載適用於開發人員想要使用不同機制將責任對應至主機,或想要直接定址主機的進階案例。 在下方的範例程式碼中,我們會定義 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();
    }
    
  1. 建立實際的精細度服務用戶端。 這只是作為資料服務的 Proxy。 可惜的是,您必須手動輸入所有方法對應,這只是簡單的單行程式碼。

    public class DataServiceClient : GrainServiceClient<IDataService>, IDataServiceClient
    {
        public DataServiceClient(IServiceProvider serviceProvider)
            : base(serviceProvider)
        {
        }
    
        public Task MyMethod() => GrainService.MyMethod();
    }
    
  1. 將精細度服務用戶端插入其他需要該用戶端的精細度。 GrainServiceClient 不保證可以在本機定址接收器上存取 GrainService。 您的命令可能會傳送至叢集中任何定址接收器上的 GrainService

    public class MyNormalGrain: Grain<NormalGrainState>, INormalGrain
    {
        readonly IDataServiceClient _dataServiceClient;
    
        public MyNormalGrain(
            IGrainActivationContext grainActivationContext,
            IDataServiceClient dataServiceClient) =>
                _dataServiceClient = dataServiceClient;
    }
    
  2. 在定址接收器中設定精細度服務和精細度服務用戶端。 您需要這樣做,定址接收器才會啟動 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>();
        });
    })