Compartir a través de


Identidad de los granos

Los granos de Orleans tienen cada uno un identificador único y particular definido por el usuario que consta de dos partes:

  1. El nombre del tipo de grano, que identifica de forma única la clase de grano.
  2. La clave de grano, que identifica de forma única una instancia lógica de esa clase de grano.

El tipo y la clave de grano se representan como cadenas legibles en Orleans y, por convención, la identidad de grano se escribe con el tipo y la clave de grano separados por un carácter /. Por ejemplo, shoppingcart/bob65 representa el tipo de grano denominado shoppingcart con una clave bob65.

No es habitual construir identidades de grano directamente. En su lugar, es más común crear referencias de grano mediante Orleans.IGrainFactory.

En las secciones siguientes, se describen los nombres de tipos y claves de grano con más detalle.

Nombres de tipos de grano

Orleans crea un nombre de tipo de grano para usted basado en la clase de implementación del grano quitando el sufijo "Grano" del nombre de clase, si está presente, y convirtiendo la cadena resultante en su representación en minúsculas. Por ejemplo, a un nombre de clase ShoppingCartGrain se le asignará el nombre de tipo de grano shoppingcart. Se recomienda que los nombres de tipo de grano y las claves de grano solo contengan caracteres imprimibles, como caracteres alfanuméricos (a-z, A-Z y 0-9) y símbolos como -, _, @ y =. Otros caracteres podrían ser compatibles o no y, a menudo, necesitarán tratamiento especial cuando se impriman en registros o aparezcan como identificadores en otros sistemas, como bases de datos.

Como alternativa, el atributo Orleans.GrainTypeAttribute se puede usar para personalizar el nombre del tipo de grano para la clase de grano a la que esté asociado, como en el ejemplo siguiente:

[GrainType("cart")]
public class ShoppingCartGrain : IShoppingCartGrain
{
    // Add your grain implementation here
}

En el ejemplo anterior, la clase de grano ShoppingCartGrain tiene un nombre de tipo de grano de cart. Cada grano solo puede tener un nombre de tipo de grano.

Para los granos genéricos, la aridad genérica debe incluirse en el nombre del tipo de grano. Por ejemplo, considere la siguiente clase DictionaryGrain<K, V>:

[GrainType("dict`2")]
public class DictionaryGrain<K, V> : IDictionaryGrain<K, V>
{
    // Add your grain implementation here
}

La clase de grano tiene dos parámetros genéricos, por lo que se agrega una tilde invertida ` seguida de la aridad genérica 2 al final del nombre del tipo de grano, dict para crear el nombre del tipo de grano dict`2, tal y como se especifica en el atributo de la clase de grano, [GrainType("dict`2")].

Claves de grano

Para mayor comodidad, Orleans expone métodos que permiten la construcción de claves de grano a partir de Guid o Int64, además de String. La clave principal tiene como ámbito el tipo de grano. Por lo tanto, la identidad completa de un grano se forma a partir del tipo del grano y su clave.

El autor de la llamada del grano decide qué esquema se debe usar. Las opciones son:

Dado que los datos subyacentes son los mismos, los esquemas se pueden usar indistintamente: todos están codificados como cadenas.

Las situaciones que requieren una instancia de grano singleton pueden usar un valor fijo conocido, como "default". Esto es simplemente una convención, pero al cumplir esta convención, queda claro en el sitio del autor de la llamada que un grano singleton está en uso.

Uso de identificadores únicos globales (GUID) como claves

System.Guid haga claves útiles cuando desee aleatoriedad y unicidad global, como al crear un nuevo trabajo en un sistema de procesamiento de trabajos. No es necesario coordinar la asignación de claves, lo que podría introducir un único punto de error en el sistema o un bloqueo del lado del sistema en un recurso que podría presentar un cuello de botella. Hay una probabilidad muy baja de que los GUID entren en colisión, por lo que son una opción común al diseñar sistemas que necesiten asignar identificadores aleatorios.

Hacer referencia a un detalle por GUID en el código de cliente:

var grain = grainFactory.GetGrain<IExample>(Guid.NewGuid());

Recuperar la clave principal del código de grano:

public override Task OnActivateAsync()
{
    Guid primaryKey = this.GetPrimaryKey();
    return base.OnActivateAsync();
}

Uso de enteros como claves

También hay disponible un entero largo, lo que tendría sentido si el grano se conserva en una base de datos relacional, donde se prefieren los índices numéricos sobre los GUID.

Hacer referencia a un grano por un entero largo en el código de cliente:

var grain = grainFactory.GetGrain<IExample>(1);

Recuperar la clave principal del código de grano:

public override Task OnActivateAsync()
{
    long primaryKey = this.GetPrimaryKeyLong();
    return base.OnActivateAsync();
}

Uso de cadenas como claves

También hay disponible una cadena.

Hacer referencia a un detalle por GUID en el código de cliente:

var grain = grainFactory.GetGrain<IExample>("myGrainKey");

Recuperar la clave principal del código de grano:

public override Task OnActivateAsync()
{
    string primaryKey = this.GetPrimaryKeyString();
    return base.OnActivateAsync();
}

Uso de claves compuestas

Si tiene un sistema que no se ajusta bien con GUID o longs, puede optar por una clave principal compuesta, lo que le permite usar una combinación de un GUID o una cadena para hacer referencia a un grano.

Puede heredar la interfaz de IGrainWithGuidCompoundKey o IGrainWithIntegerCompoundKey de la siguiente manera:

public interface IExampleGrain : Orleans.IGrainWithIntegerCompoundKey
{
    Task Hello();
}

En el código de cliente, esto agrega un segundo argumento al método IGrainFactory.GetGrain en el generador de granos:

var grain = grainFactory.GetGrain<IExample>(0, "a string!", null);

Para acceder a la clave compuesta en el grano, podemos llamar a una sobrecarga en el método GrainExtensions.GetPrimaryKey (el GrainExtensions.GetPrimaryKeyLong):

public class ExampleGrain : Orleans.Grain, IExampleGrain
{
    public Task Hello()
    {
        long primaryKey = this.GetPrimaryKeyLong(out string keyExtension);
        Console.WriteLine($"Hello from {keyExtension}");

        Task.CompletedTask;
    }
}

Por qué los granos usan identificadores lógicos

En entornos orientados a objetos, como .NET, la identidad de un objeto es difícil de distinguir de una referencia al mismo. Cuando se crea un objeto con la palabra clave new, la referencia que se obtiene representa todos los aspectos de su identidad, excepto aquellos que asignan el objeto a alguna entidad externa que representa. Orleans está diseñado para sistemas distribuidos. En los sistemas distribuidos, las referencias a objetos no pueden representar la identidad de instancia, ya que las referencias a objetos se limitan al espacio de direcciones de un solo proceso. Orleans usa identificadores lógicos para evitar esta limitación. Los granos usan identificadores lógicos, por lo que las referencias de grano permanecen válidas en toda la duración del proceso y son portátiles de un proceso a otro, lo que permite almacenarlas y recuperarlas posteriormente o enviarlas a través de una red a otro proceso de la aplicación, todo ello mientras se sigue haciendo referencia a la misma entidad: el grano para el que se creó la referencia.