次の方法で共有


グレインを開発する

グレイン クラスを実装するコードを記述する前に、.NET Standard または .NET Core (推奨) または .NET Framework 4.6.1 以降を対象とする新しいクラス ライブラリ プロジェクトを作成します (依存関係が原因で .NET Standard または .NET Core を使用できない場合)。 同じクラス ライブラリ プロジェクトまたは 2 つの異なるプロジェクトでグレイン インターフェイスとグレイン クラスを定義して、インターフェイスを実装からより適切に分離できます。 どちらの場合も、プロジェクトはOrleans NuGet パッケージを参照する必要があります。

詳細な手順については、「Orleans」の「プロジェクトのセットアップ」セクションを参照してください。

グレイン インターフェイスとクラス

グレインは相互にやり取りし、それぞれのグレイン インターフェイスの一部として宣言されたメソッドを呼び出すことによって外部から呼び出されます。 グレイン クラスは、以前に宣言された 1 つ以上のグレイン インターフェイスを実装します。 グレイン インターフェイスのすべてのメソッドは、 Task ( void メソッドの場合)、 Task<TResult>、または ValueTask<TResult> ( T 型の値を返すメソッドの場合) を返す必要があります。

Orleans Presence Service サンプルからの抜粋を次に示します。

public interface IPlayerGrain : IGrainWithGuidKey
{
    Task<IGameGrain> GetCurrentGame();

    Task JoinGame(IGameGrain game);

    Task LeaveGame(IGameGrain game);
}

public class PlayerGrain : Grain, IPlayerGrain
{
    private IGameGrain _currentGame;

    // Game the player is currently in. May be null.
    public Task<IGameGrain> GetCurrentGame()
    {
       return Task.FromResult(_currentGame);
    }

    // Game grain calls this method to notify that the player has joined the game.
    public Task JoinGame(IGameGrain game)
    {
       _currentGame = game;

       Console.WriteLine(
           $"Player {GetPrimaryKey()} joined game {game.GetPrimaryKey()}");

       return Task.CompletedTask;
    }

   // Game grain calls this method to notify that the player has left the game.
   public Task LeaveGame(IGameGrain game)
   {
       _currentGame = null;

       Console.WriteLine(
           $"Player {GetPrimaryKey()} left game {game.GetPrimaryKey()}");

       return Task.CompletedTask;
   }
}

グレイン メソッドの応答タイムアウト

Orleans ランタイムを使用すると、グレイン メソッドごとに応答タイムアウトを適用できます。 グレイン メソッドがタイムアウト内に完了しない場合、ランタイムはTimeoutExceptionとスローします。 応答タイムアウトを適用するには、インターフェイスのグレイン メソッド定義に ResponseTimeoutAttribute を追加します。 クライアントとサイロの両方がタイムアウトを認識する必要があるため、グレイン クラスのメソッド実装ではなく、インターフェイス メソッド定義に属性を追加することが重要です。

前の PlayerGrain 実装を拡張し、次の例は、 LeaveGame メソッドに応答タイムアウトを適用する方法を示しています。

public interface IPlayerGrain : IGrainWithGuidKey
{
    Task<IGameGrain> GetCurrentGame();

    Task JoinGame(IGameGrain game);

    [ResponseTimeout("00:00:05")] // 5s timeout
    Task LeaveGame(IGameGrain game);
}

上記のコードは、 LeaveGame メソッドで応答タイムアウトを 5 秒に設定します。 ゲームを終了するときに、5 秒を超える時間がかかる場合は、 TimeoutException がスローされます。

応答タイムアウトの構成

個々のグレイン メソッドの応答タイムアウトと同様に、すべてのグレイン メソッドの既定の応答タイムアウトを構成できます。 グレイン メソッドの呼び出しは、指定された期間内に応答が受信されない場合にタイムアウトします。 既定では、この期間は 30 秒です。 既定の応答タイムアウトを構成できます。

Orleansの構成の詳細については、「クライアント構成」または「サーバー構成」を参照してください。

グレインメソッドの戻り値

グレイン インターフェースでT型の値をTask<T>として返すグレイン メソッドを定義します。 async キーワードでマークされていないグレイン メソッドの場合、戻り値が使用可能な場合は、通常、次のステートメントを使用して返します。

public Task<SomeType> GrainMethod1()
{
    return Task.FromResult(GetSomeType());
}

グレイン インターフェイスで値を返さないグレイン メソッド (実質的には void メソッド) を、 Taskを返すように定義します。 返される Task は、メソッドの非同期実行と完了を示します。 async キーワードでマークされていないグレイン メソッドの場合、"void" メソッドの実行が完了したら、特別な値Task.CompletedTask返す必要があります。

public Task GrainMethod2()
{
    return Task.CompletedTask;
}

asyncとしてマークされたグレイン メソッドは、値を直接返します。

public async Task<SomeType> GrainMethod3()
{
    return await GetSomeTypeAsync();
}

voidグレイン メソッドで、値を返さないasyncとしてマークされたものは、実行終了時に単に終了します。

public async Task GrainMethod4()
{
    return;
}

グレイン メソッドが別の非同期メソッド呼び出しから戻り値を受け取り (グレインに対する場合もあれば、そうでない場合もある)、その呼び出しに対してエラー処理を実行する必要がない場合は、その非同期呼び出しから受信した Task を単に返すことができます。

public Task<SomeType> GrainMethod5()
{
    Task<SomeType> task = CallToAnotherGrain();

    return task;
}

同様に、 void グレイン メソッドは、別の呼び出しによって返された Task を、待機せずに返すことができます。

public Task GrainMethod6()
{
    Task task = CallToAsyncAPI();
    return task;
}

ValueTask<T> は、 Task<T>の代わりに使用できます。

グレインリファレンス

グレイン参照は、対応するグレイン クラスと同じグレイン インターフェイスを実装するプロキシ オブジェクトです。 ターゲット グレインの論理 ID (型と一意キー) をカプセル化します。 グレイン参照を使用して、ターゲット グレインを呼び出します。 各グレイン参照は 1 つのグレイン (グレイン クラスの 1 つのインスタンス) を指しますが、同じグレインへの複数の独立した参照を作成できます。

グレイン参照はターゲット グレインの論理 ID を表しているため、グレインの物理的な場所とは無関係であり、システムの再起動が完了しても有効なままです。 他の .NET オブジェクトと同様に、グレイン参照を使用できます。 メソッドに渡したり、メソッドの戻り値として使用したり、永続的なストレージに保存したりできます。

グレイン参照を取得するには、グレインの ID を IGrainFactory.GetGrain<TGrainInterface>(Type, Guid) メソッドに渡します。ここで、 T はグレイン インターフェイスであり、 key はその型内のグレインの一意のキーです。

次の例は、前に定義した IPlayerGrain インターフェイスのグレイン参照を取得する方法を示しています。

グレインクラスの内部から:

IPlayerGrain player = GrainFactory.GetGrain<IPlayerGrain>(playerId);

クライアントコードOrleansから。

IPlayerGrain player = client.GetGrain<IPlayerGrain>(playerId);

グレイン参照の詳細については、 グレインリファレンス記事を参照してください。

グレイン メソッドの呼び出し

Orleans プログラミング モデルは、非同期プログラミングに基づいています。 前の例のグレイン参照を使用して、グレイン メソッドの呼び出しを実行する方法を次に示します。

// Invoking a grain method asynchronously
Task joinGameTask = player.JoinGame(this);

// The await keyword effectively makes the remainder of the
// method execute asynchronously at a later point
// (upon completion of the Task being awaited) without blocking the thread.
await joinGameTask;

// The next line will execute later, after joinGameTask has completed.
players.Add(playerId);

2 つ以上の Tasksを結合できます。 結合操作により、すべての構成Taskが完了したときに解決される新しいTasksが作成されます。 このパターンは、グレインが複数の計算を開始し、すべての計算が完了するのを待ってから続行する必要がある場合に便利です。 たとえば、多くのパーツで構成された Web ページを生成するフロントエンド グレインは、複数のバックエンド呼び出し (各パーツに 1 つずつ) を行い、結果ごとに Task を受け取る場合があります。 その後、グレインはこれらすべての Tasksの結合を待つことになります。 結合された Task が解決されると、個々の Tasks が完了し、Web ページの書式設定に必要なすべてのデータが受信されます。

例:

List<Task> tasks = new List<Task>();
Message notification = CreateNewMessage(text);

foreach (ISubscriber subscriber in subscribers)
{
    tasks.Add(subscriber.Notify(notification));
}

// WhenAll joins a collection of tasks, and returns a joined
// Task that will be resolved when all of the individual notification Tasks are resolved.
Task joinedTask = Task.WhenAll(tasks);

await joinedTask;

// Execution of the rest of the method will continue
// asynchronously after joinedTask is resolve.

エラー伝達

グレイン メソッドが例外をスローすると、 Orleans は必要に応じてその例外をホスト間で呼び出し元スタックに伝達します。 これを意図したとおりに機能させるには、例外を Orleansでシリアル化できる必要があります。また、例外を処理するホストは、例外の種類を使用できる必要があります。 例外の種類が使用できない場合、 Orleans は Orleans.Serialization.UnavailableExceptionFallbackExceptionのインスタンスとして例外をスローし、元の例外のメッセージ、型、スタック トレースを保持します。

グレイン メソッドからスローされた例外は、例外が Orleans.Storage.InconsistentStateExceptionから継承されない限り、グレインを非アクティブ化しません。 ストレージ操作は、グレインのメモリ内の状態がデータベース内の状態と一致していないことを検出すると、 InconsistentStateException をスローします。 InconsistentStateExceptionの特別な処理とは別に、この動作は.NET オブジェクトから例外をスローするのと似ています。例外によってオブジェクトが破棄されることはありません。

仮想メソッド

グレイン クラスは、必要に応じて、 OnActivateAsyncOnDeactivateAsync 仮想メソッドをオーバーライドできます。 Orleans ランタイムは、クラスの各グレインのアクティブ化と非アクティブ化時にこれらのメソッドを呼び出します。 これにより、グレイン コードで追加の初期化操作とクリーンアップ操作を実行できるようになります。 OnActivateAsyncによってスローされた例外は、アクティブ化プロセスを失敗させます。

OnActivateAsync (オーバーライドされた場合) は常にグレイン アクティブ化プロセスの一部として呼び出されますが、OnDeactivateAsyncはすべての状況 (たとえば、サーバーの障害やその他の異常なイベントの場合) に呼び出されるとは限りません。 このため、アプリケーションは、状態変更の永続化などの重要な操作を実行するために OnDeactivateAsync に依存しないようにする必要があります。 ベスト エフォート操作にのみ使用します。

こちらも参照ください