Identité de grain
Les grains dans chaque Orleans ont un seul et unique identificateur défini par l’utilisateur qui se compose de deux parties :
- Nom du type de grain qui identifie de façon unique la classe de grain.
- Clé de grain qui identifie de façon unique une instance logique de cette classe de grain.
Le type de grain et la clé sont tous deux représentés sous forme de chaînes lisibles par l’homme dans Orleans et, par convention, l’identité de grain est écrite avec le type de grain et la clé séparés par un caractère /
. Par exemple, shoppingcart/bob65
représente le type de grain nommé shoppingcart
avec une clé bob65
.
Il est rare de construire directement des identités de grain. Il est plus courant de créer des références de grain en utilisant Orleans.IGrainFactory à la place.
Les sections suivantes évoquent les noms de type de grain et les clés de grain de manière plus approfondie.
Noms de type de grain
Orleans crée un nom de type de grain à votre place en fonction de votre classe d’implémentation de grain en supprimant le suffixe « Grain » du nom de la classe, s’il est présent, et en convertissant la chaîne résultante en sa représentation en minuscules. Par exemple, une classe nommée ShoppingCartGrain
reçoit le nom d type de grain shoppingcart
. Il est recommandé que les noms et les clés de type de grain se composent uniquement de caractères imprimables tels que des caractères alphanumériques (a
-z
,A
-Z
et0
-9
) et des symboles tels que -
, _
, @
, =
. Il est possible que d’autres caractères puissent ou non être pris en charge et ils nécessitent souvent un traitement spécial lors de l’impression dans des journaux ou apparaissent en tant qu’identificateurs dans d’autres systèmes tels que des bases de données.
Vous pouvez également utiliser l’attribut Orleans.GrainTypeAttribute pour personnaliser le nom du type de grain de la classe de grain à laquelle il est attaché, comme dans l’exemple suivant :
[GrainType("cart")]
public class ShoppingCartGrain : IShoppingCartGrain
{
// Add your grain implementation here
}
Dans l’exemple précédent, la classe de grain, ShoppingCartGrain
a un nom de type de grain de cart
. Chaque grain ne peut avoir qu’un seul nom de type de grain.
Pour les grains génériques, l’arité générique doit être incluse dans le nom du type de grain. Par exemple, considérons la classe DictionaryGrain<K, V>
suivante :
[GrainType("dict`2")]
public class DictionaryGrain<K, V> : IDictionaryGrain<K, V>
{
// Add your grain implementation here
}
La classe de grain a deux paramètres génériques, donc un accès grave `
suivi de l’arité générique, 2, est ajouté à la fin du nom du type de grain, dict
pour créer le nom du type de grain dict`2
, comme spécifié dans l’attribut sur la classe de grain, [GrainType("dict`2")]
.
Clés de grain
Pour des raisons pratiques, Orleans expose des méthodes qui permettent de construire des clés de grain à partir d’un Guid ou d’un Int64, en plus d’un String. La clé primaire est limitée au type de grain. Par conséquent, l’identité complète d’un grain est formée à partir du type du grain et de sa clé.
L’appelant du grain décide quel schéma utiliser. Les options sont :
Étant donné que les données sous-jacentes sont identiques, les schémas peuvent être utilisés indifféremment : ils sont encodés en tant que chaînes.
Les situations nécessitant une instance de grain singleton peuvent utiliser une valeur fixe connue, comme "default"
. Il s’agit simplement d’une convention, mais en respectant cette convention, il devient évident sur le site de l’appelant qu’un grain singleton est utilisé.
Utilisation d’identificateurs globaux uniques (GUID) en tant que clés
System.Guid rend des clés utiles lorsque le caractère aléatoire et l’unicité globale sont souhaités, par exemple lors de la création d’un travail dans un système de traitement des travaux. Vous n’avez pas besoin de coordonner l’allocation de clés, ce qui pourrait introduire un point de défaillance unique dans le système, ni d’un verrou côté système sur une ressource susceptible de présenter un goulot d’étranglement. Il existe une très faible probabilité de conflit des GUID. Ils représentent donc un choix courant lors de l’architecture d’un système qui doit allouer des identificateurs aléatoires.
Référencement d’un grain par GUID dans le code client :
var grain = grainFactory.GetGrain<IExample>(Guid.NewGuid());
Récupération de la clé primaire à partir du code de grain :
public override Task OnActivateAsync()
{
Guid primaryKey = this.GetPrimaryKey();
return base.OnActivateAsync();
}
Utilisation d’entiers comme clés
Il est également possible d’utiliser un entier long, ce qui se justifie si le grain est conservé dans une base de données relationnelle, où les index numériques sont préférés aux GUID.
Référencement d’un grain par un entier long dans le code client :
var grain = grainFactory.GetGrain<IExample>(1);
Récupération de la clé primaire à partir du code de grain :
public override Task OnActivateAsync()
{
long primaryKey = this.GetPrimaryKeyLong();
return base.OnActivateAsync();
}
Utilisation de chaînes comme clés
Il est également possible d’utiliser une chaîne (String).
Référencement d’un grain par String dans le code client :
var grain = grainFactory.GetGrain<IExample>("myGrainKey");
Récupération de la clé primaire à partir du code de grain :
public override Task OnActivateAsync()
{
string primaryKey = this.GetPrimaryKeyString();
return base.OnActivateAsync();
}
Utilisation de clés composées
Si votre système n’est pas bien adapté aux GUID ou aux longs, vous pouvez opter pour une clé primaire composée, laquelle vous permet de référencer un grain à l’aide d’un GUID ou d’un long combiné à une chaîne.
Vous pouvez hériter de votre interface de l’interface IGrainWithGuidCompoundKey ou IGrainWithIntegerCompoundKey comme ceci :
public interface IExampleGrain : Orleans.IGrainWithIntegerCompoundKey
{
Task Hello();
}
Dans le code client, un deuxième argument est ainsi ajouté à la méthode IGrainFactory.GetGrain de la fabrique de grain :
var grain = grainFactory.GetGrain<IExample>(0, "a string!", null);
Pour accéder à la clé composée du grain, nous pouvons appeler une surcharge au niveau de la méthode GrainExtensions.GetPrimaryKey (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;
}
}
Raison pour laquelle les grains utilisent des identificateurs logiques
Dans les environnements orientés vers un objet, tels que .NET, l’identité d’un objet est difficile à distinguer d’une référence à celui-ci. Quand un objet est créé en utilisant le mot clé new
, la référence que vous obtenez représente tous les aspects de son identité, à l’exception de ceux qui mappent l’objet à une entité externe qu’il représente. Orleans est conçu pour les systèmes distribués. Dans les systèmes distribués, les références d’objet ne peuvent pas représenter l’identité d’instance, car les références sont généralement limitées à un espace d’adressage unique du processus. Orleans utilise des identificateurs logiques pour éviter cette limitation. Le grain utilise des identificateurs logiques afin que les références de grain restent valides pendant la durée de vie des processus et soient portables d’un processus à un autre, ce qui leur permet de les stocker et les récupérer ultérieurement ou d’être envoyées vers un autre processus dans l’application, tout en faisant toujours référence à la même entité : le grain pour lequel la référence a été créée.