Partilhar via


Referências de grãos

Antes de chamar um método em grão, você primeiro precisa de uma referência a esse grão. Uma referência de grão é um objeto proxy que implementa a mesma interface de grão que a classe de grão correspondente. Ele encapsula a identidade lógica (tipo e chave exclusiva) do grão de destino. As referências de grãos são usadas para fazer chamadas para o grão alvo. Cada referência de grão é para um único grão (uma única instância da classe de grãos), mas pode-se criar várias referências independentes para o mesmo grão.

Como uma referência de grão representa a identidade lógica do grão-alvo, ela é independente da localização física do grão e permanece válida mesmo após uma reinicialização completa do sistema. Os desenvolvedores podem usar referências de grão como qualquer outro objeto .NET. Ele pode ser passado para um método, usado como um valor de retorno de método e até mesmo salvo no armazenamento persistente.

Uma referência de grão pode ser obtida passando a identidade de um grão para o IGrainFactory.GetGrain<TGrainInterface>(Type, Guid) método, onde T é a interface do grão e key é a chave única do grão dentro do tipo.

A seguir estão exemplos de como obter uma referência de grão da IPlayerGrain interface definida acima.

De dentro de uma classe de grãos:

// This would typically be read from an HTTP request parameter or elsewhere.
Guid playerId = Guid.NewGuid();
IPlayerGrain player = GrainFactory.GetGrain<IPlayerGrain>(playerId);

Do código do Orleans cliente:

// This would typically be read from an HTTP request parameter or elsewhere.
Guid playerId = Guid.NewGuid();
IPlayerGrain player = client.GetGrain<IPlayerGrain>(playerId);

As referências de grãos contêm três informações:

  1. O tipo de grão, que identifica exclusivamente a classe de grãos.
  2. A chave de grão, que identifica exclusivamente uma instância lógica dessa classe de grão.
  3. A interface que a referência de grão deve implementar.

Nota

O tipo de grão e a chave formam a identidade do grão.

Observe que as chamadas acima para IGrainFactory.GetGrain aceitar apenas duas dessas três coisas:

  • A interface implementada pela referência IPlayerGrainde grão, .
  • A chave de grão, que é o valor de playerId.

Apesar de afirmar que uma referência de grão contém um tipo de grão, chave e interface, os exemplos só fornecidos Orleans com a chave e interface. Isso porque Orleans mantém um mapeamento entre interfaces de grãos e tipos de grãos. Quando você pede para a fábrica IShoppingCartGrainde grãos, Orleans consulta seu mapeamento para encontrar o tipo de grão correspondente para que ele possa criar a referência. Isso funciona quando há apenas uma implementação de uma interface de grão, mas se houver várias implementações, você precisará desambiguá-las na GetGrain chamada. Para obter mais informações, consulte a próxima seção, desambiguando a resolução de tipo de grão.

Nota

Orleans Gera tipos de implementação de referência de grão para cada interface de grão em seu aplicativo durante a compilação. Essas implementações de referência de grão herdam da Orleans.Runtime.GrainReference classe. GetGrain Retorna instâncias da implementação gerada Orleans.Runtime.GrainReference correspondentes à interface de grão solicitada.

Resolução de tipo de grão desambiguante

Quando há várias implementações de uma interface de grão, como no exemplo a seguir, Orleans tenta determinar a implementação pretendida ao criar uma referência de grão. Considere o exemplo a seguir, no qual há duas implementações da ICounterGrain interface:

public interface ICounterGrain : IGrainWithStringKey
{
    ValueTask<int> UpdateCount();
}

public class UpCounterGrain : ICounterGrain
{
    private int _count;

    public ValueTask<string> UpdateCount() => new(++_count); // Increment count
}

public class DownCounterGrain : ICounterGrain
{
    private int _count;

    public ValueTask<string> UpdateCount() => new(--_count); // Decrement count
}

A chamada a GetGrain seguir lançará uma exceção porque Orleans não sabe como mapear ICounterGrain inequivocamente para uma das classes de grãos.

// This will throw an exception: there is no unambiguous mapping from ICounterGrain to a grain class.
ICounterGrain myCounter = grainFactory.GetGrain<ICounterGrain>("my-counter");

Um System.ArgumentException testamento lançado com a seguinte mensagem:

Unable to identify a single appropriate grain type for interface ICounterGrain. Candidates: upcounter (UpCounterGrain), downcounter (DownCounterGrain)

A mensagem de erro informa qual implementação de Orleans grão tem que correspondem ao tipo de interface de grão solicitado, ICounterGrain. Ele mostra os nomes dos tipos de grãos (upcounter e downcounter), bem como as classes de grãos (UpCounterGrain e DownCounterGrain).

Nota

Os nomes de tipo de grão na mensagem upcounter de erro anterior e downcounter, são derivados dos nomes UpCounterGrain de classe de grão e DownCounterGrain respectivamente. Este é o comportamento padrão e Orleans pode ser personalizado adicionando um [GrainType(string)] atributo à classe grain. Por exemplo:

[GrainType("up")]
public class UpCounterGrain : IUpCounterGrain { /* as above */ }

Há várias maneiras de resolver essa ambiguidade detalhadas nas subseções a seguir.

Desambiguando tipos de grãos usando interfaces de marcador exclusivas

A maneira mais clara de desambiguar esses grãos é dar-lhes interfaces de grãos únicas. Por exemplo, se adicionarmos a interface IUpCounterGrain à UpCounterGrain classe e adicionarmos a interface IDownCounterGrain à DownCounterGrain classe, como no exemplo a seguir, podemos resolver a referência de grão correta passando IUpCounterGrain ou IDownCounterGrain para a GetGrain<T> chamada em vez de passar o tipo ambíguo ICounterGrain .

public interface ICounterGrain : IGrainWithStringKey
{
    ValueTask<int> UpdateCount();
}

// Define unique interfaces for our implementations
public interface IUpCounterGrain : ICounterGrain, IGrainWithStringKey {}
public interface IDownCounterGrain : ICounterGrain, IGrainWithStringKey {}

public class UpCounterGrain : IUpCounterGrain
{
    private int _count;

    public ValueTask<string> UpdateCount() => new(++_count); // Increment count
}

public class DownCounterGrain : IDownCounterGrain
{
    private int _count;

    public ValueTask<string> UpdateCount() => new(--_count); // Decrement count
}

Para criar uma referência a qualquer grão, considere o seguinte código:

// Get a reference to an UpCounterGrain.
ICounterGrain myUpCounter = grainFactory.GetGrain<IUpCounterGrain>("my-counter");

// Get a reference to a DownCounterGrain.
ICounterGrain myDownCounter = grainFactory.GetGrain<IDownCounterGrain>("my-counter");

Nota

No exemplo anterior, você criou duas referências de grão com a mesma chave, mas tipos de grãos diferentes. O primeiro, armazenado na myUpCounter variável, é uma referência ao grão com o id upcounter/my-counter. O segundo, armazenado na myDownCounter variável, é uma referência ao grão com o id downcounter/my-counter. É a combinação de tipo de grão e chave de grão que identificam exclusivamente um grão. Portanto, myUpCounter e myDownCounter referem-se a diferentes grãos.

Desambiguando tipos de grãos fornecendo um prefixo de classe de grão

Você pode fornecer um prefixo de nome de classe de grão para , por IGrainFactory.GetGrainexemplo:

ICounterGrain myUpCounter = grainFactory.GetGrain<ICounterGrain>("my-counter", grainClassNamePrefix: "Up");
ICounterGrain myDownCounter = grainFactory.GetGrain<ICounterGrain>("my-counter", grainClassNamePrefix: "Down");

Especificando a implementação de grão padrão usando a convenção de nomenclatura

Ao desambiguar várias implementações da mesma interface Orleans de grão, selecionará uma implementação usando a convenção de retirar um 'I' à esquerda do nome da interface. Por exemplo, se o nome da interface for ICounterGrain e houver duas implementações, CounterGrain e DownCounterGrain, Orleans escolherá CounterGrain quando solicitado uma referência a ICounterGrain, como no exemplo a seguir:

/// This will refer to an instance of CounterGrain, since that matches the convention.
ICounterGrain myUpCounter = grainFactory.GetGrain<ICounterGrain>("my-counter");

Especificando o tipo de grão padrão usando um atributo

O Orleans.Metadata.DefaultGrainTypeAttribute atributo pode ser adicionado a uma interface grain para especificar o tipo grain da implementação padrão para essa interface, como no exemplo a seguir:

[DefaultGrainType("up-counter")]
public interface ICounterGrain : IGrainWithStringKey
{
    ValueTask<int> UpdateCount();
}

[GrainType("up-counter")]
public class UpCounterGrain : ICounterGrain
{
    private int _count;

    public ValueTask<string> UpdateCount() => new(++_count); // Increment count
}

[GrainType("down-counter")]
public class DownCounterGrain : ICounterGrain
{
    private int _count;

    public ValueTask<string> UpdateCount() => new(--_count); // Decrement count
}
/// This will refer to an instance of UpCounterGrain, due to the [DefaultGrainType("up-counter"')] attribute
ICounterGrain myUpCounter = grainFactory.GetGrain<ICounterGrain>("my-counter");

Desambiguando tipos de grãos, fornecendo o id de grão resolvido

Algumas sobrecargas de IGrainFactory.GetGrain aceitar um argumento do tipo Orleans.Runtime.GrainId. Ao usar essas sobrecargas, não precisa mapear de um tipo de interface para um tipo de grão e, portanto, Orleans não há ambiguidade a ser resolvida. Por exemplo:

public interface ICounterGrain : IGrainWithStringKey
{
    ValueTask<int> UpdateCount();
}

[GrainType("up-counter")]
public class UpCounterGrain : ICounterGrain
{
    private int _count;

    public ValueTask<string> UpdateCount() => new(++_count); // Increment count
}

[GrainType("down-counter")]
public class DownCounterGrain : ICounterGrain
{
    private int _count;

    public ValueTask<string> UpdateCount() => new(--_count); // Decrement count
}
// This will refer to an instance of UpCounterGrain, since "up-counter" was specified as the grain type
// and the UpCounterGrain uses [GrainType("up-counter")] to specify its grain type.
ICounterGrain myUpCounter = grainFactory.GetGrain<ICounterGrain>(GrainId.Create("up-counter", "my-counter"));