다음을 통해 공유


곡물 참조

곡물에서 메서드를 호출하기 전에 먼저 해당 곡물에 대한 참조가 필요합니다. 곡물 참조는 해당 그레인 클래스와 동일한 곡물 인터페이스를 구현하는 프록시 개체입니다. 대상 그레인의 논리적 정체성(형식 및 고유 키)을 캡슐화합니다. 곡물 참조를 사용하여 대상 곡물을 호출합니다. 각 곡물 참조는 단일 곡물(곡물 클래스의 단일 인스턴스)을 가리키지만 동일한 곡물에 대한 여러 독립 참조를 만들 수 있습니다.

곡물 참조는 대상 곡물의 논리적 ID를 나타내므로 곡물의 물리적 위치와 독립적이며 전체 시스템을 다시 시작한 후에도 유효한 상태로 유지됩니다. 다른 .NET 개체와 같은 곡물 참조를 사용할 수 있습니다. 메서드에 전달하고, 메서드 반환 값으로 사용하고, 영구 스토리지에 저장할 수도 있습니다.

곡물의 ID를 메서드에 전달하여 곡물 IGrainFactory.GetGrain<TGrainInterface>(Type, Guid) 참조를 얻을 수 있습니다. 여기서 T 는 곡물 인터페이스이며 key 해당 형식 내에서 곡물의 고유 키입니다.

다음 예제에서는 이전에 정의된 IPlayerGrain 인터페이스에 대한 그레인 참조를 얻는 방법을 보여 줍니다.

곡물 클래스 내에서:

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

클라이언트 코드에서 Orleans :

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

곡물 참조에는 다음 세 가지 정보가 포함됩니다.

  1. 곡물 클래스를 고유하게 식별하는 곡물 형식입니다.
  2. 해당 그레인 클래스의 논리적 인스턴스를 고유하게 식별하는 곡물 입니다.
  3. 그레인 참조가 구현해야 하는 인터페이스 입니다.

비고

곡물 형식그레인 ID를 형성합니다.

위의 호출 IGrainFactory.GetGrain 은 다음 세 가지 중 두 가지만 수락했습니다.

  • 그레인 참조에 의해 구현된 인터페이스 입니다 IPlayerGrain.
  • 그레인의 값인 입니다 playerId.

곡물 참조에 곡물 형식, 인터페이스가 포함되어 있다고 명시되어 있음에도 불구하고, 예제에는 Orleans와 인터페이스만 제공되었습니다. 이는 Orleans 곡물 인터페이스와 그레인 형식 간의 매핑을 유지 관리하기 때문입니다. 그레인 팩토리에 요청하면 IShoppingCartGrain이 해당 매핑을 참조하여 해당 곡물 유형을 찾아 참조를 생성합니다. 이는 곡물 인터페이스의 구현이 하나뿐인 경우에 작동합니다. 그러나 여러 구현이 있는 경우 호출에서 GetGrain 명확하게 구분해야 합니다. 자세한 내용은 다음 섹션인 곡물 형식 확인 해제를 참조하세요.

비고

Orleans 는 컴파일 중에 애플리케이션의 각 곡물 인터페이스에 대한 곡물 참조 구현 형식을 생성합니다. 이러한 그레인 참조 구현은 Orleans.Runtime.GrainReference 클래스에서 상속됩니다. GetGrain 는 요청된 Orleans.Runtime.GrainReference 곡물 인터페이스에 해당하는 생성된 구현의 인스턴스를 반환합니다.

알갱이 종류 해석

다음 예제 Orleans 와 같이 곡물 인터페이스의 여러 구현이 있는 경우 곡물 참조를 만들 때 의도한 구현을 확인하려고 시도합니다. ICounterGrain 인터페이스에 대한 두 가지 구현이 있는 다음 예제를 고려해봅시다.

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
}

다음 GetGrain 호출은 Orleans이(가) ICounterGrain를 그레인 클래스 중 하나로 명확하게 매핑하는 방법을 알지 못하기 때문에 예외를 발생시킵니다.

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

다음 메시지가 포함된 System.ArgumentException이 발생합니다.

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

오류 메시지는 요청된 곡물 인터페이스 형식Orleans과 ICounterGrain 일치하는 곡물 구현을 알려줍니다. 그레인 유형 이름(upcounterdowncounter)과 그레인 클래스(UpCounterGrainDownCounterGrain)를 보여 줍니다.

비고

이전 오류 메시지 upcounter 의 그레인 형식 이름 및 downcounter, 각각 그레인 클래스 이름 UpCounterGrainDownCounterGrain 에서 파생됩니다. Orleans 내의 기본 동작이며, 그레인 클래스에 [GrainType(string)] 속성을 추가하여 사용자 지정할 수 있습니다. 다음은 그 예입니다.

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

이 모호성을 해결하는 방법에는 여러 가지가 있으며, 다음 하위 섹션에 자세히 설명되어 있습니다.

고유한 표식 인터페이스를 사용하여 곡물 형식 구분

이러한 곡물을 명확하게 구분하는 가장 명확한 방법은 고유한 곡물 인터페이스를 제공하는 것입니다. 예를 들어, 다음 예제와 같이 IUpCounterGrain 인터페이스를 UpCounterGrain 클래스에 추가하고 IDownCounterGrain 인터페이스를 DownCounterGrain 클래스에 추가하는 경우, 모호한 IUpCounterGrain 형식 대신 IDownCounterGrain 또는 GetGrain<T>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
}

두 곡물에 대한 참조를 만들려면 다음 코드를 고려합니다.

// 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");

비고

앞의 예제에서는 동일한 키와 다른 곡물 형식을 사용하여 두 개의 곡물 참조를 만들었습니다. 변수에 myUpCounter 저장된 첫 번째는 ID upcounter/my-counter를 사용하여 그레인을 참조합니다. 변수에 myDownCounter 저장된 두 번째 변수는 ID downcounter/my-counter를 사용하여 그레인을 참조합니다. 곡물 유형 과 곡물 의 조합은 곡물을 고유하게 식별합니다. 따라서 myUpCountermyDownCounter 다른 곡물을 참조합니다.

곡물 클래스 접두사를 제공하여 곡물 형식을 명확하게 구분

예를 들어 IGrainFactory.GetGrain에 곡물 클래스 이름의 접두사를 제공할 수 있습니다.

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

명명 규칙을 사용하여 기본 곡물 구현 지정

동일한 그레인 인터페이스의 여러 구현을 명확하게 구별할 때, Orleans는 인터페이스 이름에서 선행 'I'를 제거하는 규칙을 사용하여 구현을 선택합니다. 예를 들어, 인터페이스 이름이 ICounterGrain이고 두 가지 구현 CounterGrainDownCounterGrain가 있을 때, Orleans은/는 CounterGrain에 대한 참조를 요청받을 경우 ICounterGrain를 선택하는 다음 예를 들 수 있습니다.

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

특성을 사용하여 기본 곡물 형식 지정

다음 예제와 같이 그레인 인터페이스에 특성을 추가하여 Orleans.Metadata.DefaultGrainTypeAttribute 해당 인터페이스에 대한 기본 구현의 곡물 형식을 지정할 수 있습니다.

[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");

확인된 곡물 ID를 제공하여 곡물 형식을 명확하게 구분

형식 IGrainFactory.GetGrain의 인수를 수락하는 일부 Orleans.Runtime.GrainId 오버로드가 있습니다. 이러한 오버로드를 Orleans 사용하는 경우 인터페이스 형식에서 그레인 형식으로 매핑할 필요가 없으므로 해결할 모호성이 없습니다. 다음은 그 예입니다.

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"));