Compartir a través de


Servicios de grano

Los servicios de grano son servicios particionados a los que se puede acceder de forma remota para respaldar la funcionalidad de grano. Cada instancia de un servicio de grano es responsable de algunos conjuntos de granos. Esos granos pueden obtener una referencia al servicio de granos actualmente responsable de servirlos mediante un GrainServiceClient.

Existen servicios para apoyar casos donde la responsabilidad de servicio debe ser distribuida alrededor del clúster Orleans. Por ejemplo, Orleans los recordatorios se implementan mediante servicios de grano: cada silo controla las operaciones de recordatorio para un subconjunto de granos y notifica esos granos cuando se activan sus recordatorios.

Configuras servicios de granos en silos. Se inicializan cuando se inicia el silo, antes de que el silo complete la inicialización. No se recolectan cuando están inactivos; en su lugar, sus tiempos de vida se extienden por la duración del silo mismo.

Crear un servicio de granos

Un GrainService es un grano especial: no tiene ninguna identidad estable y se ejecuta en cada silo desde el inicio hasta el apagado. La implementación de una IGrainService interfaz implica varios pasos.

  1. Defina la interfaz de comunicación de servicio específica. Cree la interfaz de un GrainService utilizando los mismos principios que se usan para construir una interfaz de grano.

    public interface IDataService : IGrainService
    {
        Task MyMethod();
    }
    
  2. Cree el DataService servicio de grano. Resulta útil saber que también puede insertar un IGrainFactory para que pueda realizar llamadas de grano desde su 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. Cree una interfaz para el GrainServiceClient<TGrainService>GrainServiceClient que otros granos usarán para conectarse al GrainService.

    public interface IDataServiceClient : IGrainServiceClient<IDataService>, IDataService
    {
    }
    
  4. Cree el cliente de servicio de grano. Los clientes suelen actuar como servidores proxy para los servicios específicos que tienen como destino, por lo que normalmente se agrega un método para cada método en el servicio de destino. Estos métodos deben obtener una referencia al servicio de grano de destino para que puedan llamar a él. La clase base GrainServiceClient<T> proporciona varias sobrecargas del método GetGrainService que pueden devolver una referencia de grano correspondiente a un GrainId, un hash numérico (uint), o un SiloAddress. Las últimas dos sobrecargas son para los casos avanzados en los que desea usar un mecanismo diferente para asignar la responsabilidad a los hosts o direccionar directamente a un host. En el siguiente código de ejemplo, definimos una propiedad, GrainService, que devuelve el IDataService del grano que llama a DataServiceClient. Para ello, usamos la GetGrainService(GrainId) sobrecarga junto con la CurrentGrainReference propiedad .

    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();
    }
    
  5. Inserta el cliente de servicio de intervalo de agregación en los otros intervalos que lo necesitan. No se garantiza que GrainServiceClient tenga acceso a GrainService en el silo local. Tu comando podría enviarse a GrainService en cualquier silo del clúster.

    public class MyNormalGrain: Grain<NormalGrainState>, INormalGrain
    {
        readonly IDataServiceClient _dataServiceClient;
    
        public MyNormalGrain(
            IGrainActivationContext grainActivationContext,
            IDataServiceClient dataServiceClient) =>
                _dataServiceClient = dataServiceClient;
    }
    
  6. Configure el servicio de grano y el cliente del servicio de grano en el silo. Debe hacerlo para que el silo comience GrainService.

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

Notas adicionales

Hay un método de extensión, GrainServicesSiloBuilderExtensions.AddGrainService, que se usa para registrar servicios de granos.

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

El silo obtiene los IGrainService tipos del proveedor de servicios al iniciar (consulte orleans/src/Orleans.Runtime/Silo/Silo.cs):

var grainServices = this.Services.GetServices<IGrainService>();

Se debe hacer referencia al paquete NuGet Microsoft.Orleans.Runtime en el proyecto GrainService.

El proyecto Orleans debe hacer referencia al paquete NuGet .

Para que esto funcione, debe registrar tanto el servicio como su cliente. La salida tendrá un aspecto similar a este:

var builder = new HostBuilder()
    .UseOrleans(c =>
    {
        c.AddGrainService<DataService>()  // Register GrainService
        .ConfigureServices(services =>
        {
            // Register Client of GrainService
            services.AddSingleton<IDataServiceClient, DataServiceClient>();
        });
    })