堅牢でスケーラブルな分散アプリケーションのためのクロスプラットフォームフレームワーク Microsoft Orleans のチュートリアル Tutorial One - Creating a Minimal Orleans Application に従ってアプリケーションを実装する手順をメモっとく。
検証環境
- Visual Studio 2019 16.9.3
- インストール済みワークロード:.NET Core クロスプラットフォームの開発
- Orleans 3.4.2
プロジェクトをセットアップする
下記に示す4つのプロジェクトを作成する。
- Grain のインターフェイスを含む GrainInterfaces クラスライブラリプロジェクト
- Grain の実装を含む Grains クラスライブラリプロジェクト
- Silo をホストする Silo コンソールプロジェクト
- クライアントになる Client コンソールプロジェクト
本節のセットアップが完了するとソリューションは最終的に下記のようになる。
構造を作成する
Silo コンソールアプリケーションを作成する。ソリューション名は Orleans Basics にする。ターゲットフレームワークは .NET Core 3.1 にする。
ソリューションを右クリックして、「追加」から「新しいプロジェクト」を選択し、Client コンソールアプリケーションを作成する。ターゲットフレームワークは .NET Core 3.1 にする。
同様に、GrainInterfaces クラスライブラリを作成する。ターゲットフレームワークは .NET Standard 2.1 にする。
同様に、Grains クラスライブラリを作成する。ターゲットフレームワークは .NET Standard 2.1 にする。
デフォルトソースファイルを削除する
GrainInterfaces プロジェクトの Class1.cs ファイルと Grains プロジェクトの Class1.cs ファイルを削除する。
参照を追加する
Grains プロジェクトの依存関係を右クリックし、「プロジェクト参照の追加」を選択する。Grains プロジェクトが GrainInterfaces プロジェクトを参照するように設定する。
同様に、Silo プロジェクトが GrainInterfaces プロジェクトと Grains プロジェクトを参照するように設定する。
同様に、Client プロジェクトが GrainInterfaces プロジェクトを参照するように設定する。
NuGet パッケージを追加する
下記の表にあるとおり各プロジェクトに NuGet パッケージを追加する。
プロジェクト | NuGet パッケージ |
---|---|
Silo | Microsoft.Orleans.Server |
Silo | Microsoft.Extensions.Logging.Console |
Client | Microsoft.Extensions.Logging.Console |
Client | Microsoft.Orleans.Client |
GrainInterfaces | Microsoft.Orleans.Core.Abstractions |
GrainInterfaces | Microsoft.Orleans.CodeGenerator.MSBuild |
Grains | Microsoft.Orleans.CodeGenerator.MSBuild |
Grains | Microsoft.Orleans.Core.Abstractions |
Grains | Microsoft.Extensions.Logging.Abstractions |
例えば、Silo プロジェクトに Microsoft.Orleans.Server パッケージを追加するときは、Silo プロジェクトを右クリックし、「NuGet パッケージの管理」を選択する。「参照」タブを選択し、検索キーワードとして Microsoft.Orleans.Server を入力し、Microsoft.Orleans.Server パッケージを選択し、インストールをクリックする。
Grain インターフェイスを定義する
GrainInterfaces プロジェクトを右クリックし、「追加」から「新しい項目」を選択する。IHello インターフェイスを IHello.cs という名前で追加する。
IHello.cs を下記のように修正する。
using System.Threading.Tasks;
namespace OrleansBasics
{
public interface IHello : Orleans.IGrainWithIntegerKey
{
Task<string> SayHello(string greeting);
}
}
Grain クラスを定義する
Grains プロジェクトを右クリックし、「追加」から「新しい項目」を選択する。Grains プロジェクトに HelloGrain クラスを HelloGrain.cs という名前で追加する。
HelloGrain.cs を下記のように修正する。
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
namespace OrleansBasics
{
public class HelloGrain : Orleans.Grain, IHello
{
private readonly ILogger logger;
public HelloGrain(ILogger<HelloGrain> logger)
{
this.logger = logger;
}
Task<string> IHello.SayHello(string greeting)
{
logger.LogInformation($"\n SayHello message received: greeting = '{greeting}'");
return Task.FromResult($"\n Client said: '{greeting}', so HelloGrain says: Hello!");
}
}
}
Silo を作成する
Silo プロジェクトの Program.cs を下記のように修正する。
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Orleans;
using Orleans.Configuration;
using Orleans.Hosting;
namespace OrleansBasics
{
public class Program
{
public static int Main(string[] args)
{
return RunMainAsync().Result;
}
private static async Task<int> RunMainAsync()
{
try
{
var host = await StartSilo();
Console.WriteLine("\n\n Press Enter to terminate...\n\n");
Console.ReadLine();
await host.StopAsync();
return 0;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return 1;
}
}
private static async Task<ISiloHost> StartSilo()
{
// define the cluster configuration
var builder = new SiloHostBuilder()
.UseLocalhostClustering()
.Configure<ClusterOptions>(options =>
{
options.ClusterId = "dev";
options.ServiceId = "OrleansBasics";
})
.ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(HelloGrain).Assembly).WithReferences())
.ConfigureLogging(logging => logging.AddConsole());
var host = builder.Build();
await host.StartAsync();
return host;
}
}
}
Client を作成する
Client プロジェクトの Program.cs を下記のように修正する。
using Microsoft.Extensions.Logging;
using Orleans;
using Orleans.Configuration;
using System;
using System.Threading.Tasks;
namespace OrleansBasics
{
public class Program
{
static int Main(string[] args)
{
return RunMainAsync().Result;
}
private static async Task<int> RunMainAsync()
{
try
{
using (var client = await ConnectClient())
{
await DoClientWork(client);
Console.ReadKey();
}
return 0;
}
catch (Exception e)
{
Console.WriteLine($"\nException while trying to run client: {e.Message}");
Console.WriteLine("Make sure the silo the client is trying to connect to is running.");
Console.WriteLine("\nPress any key to exit.");
Console.ReadKey();
return 1;
}
}
private static async Task<IClusterClient> ConnectClient()
{
IClusterClient client;
client = new ClientBuilder()
.UseLocalhostClustering()
.Configure<ClusterOptions>(options =>
{
options.ClusterId = "dev";
options.ServiceId = "OrleansBasics";
})
.ConfigureLogging(logging => logging.AddConsole())
.Build();
await client.Connect();
Console.WriteLine("Client successfully connected to silo host \n");
return client;
}
private static async Task DoClientWork(IClusterClient client)
{
// example of calling grains from the initialized client
var friend = client.GetGrain<IHello>(0);
var response = await friend.SayHello("Good morning, HelloGrain!");
Console.WriteLine($"\n\n{response}\n\n");
}
}
}
アプリケーションを実行する
Silo プロジェクトを右クリックし、「デバッグ」から「新しいインスタンスの開始」を選択する。そうすると、下記のようなコンソールが表示され、大量の起動ログと共に Silo アプリケーションが起動する。
Silo アプリケーションを実行した状態で、折りたたまれているソリューションエクスプローラーにある Client プロジェクトを右クリックし、「デバッグ」から「新しいインスタンスの開始」を選択する。そうすると、下記のようなコンソールが表示され、Client アプリケーションが起動する。起動すると即座に Silo アプリケーションで動作している HelloGrain に SayHello メッセージを送信する。Client は "Good morning, HelloGrain!" をメッセージの引数として送信し、HelloGrain は "Hello!" と返信している。
Silo アプリケーションのコンソールにもログが記録され、"Good morning, HelloGrain!" という引数を伴う SayHello メッセージが届いたことを記録している。
今回は堅牢でスケーラブルな分散アプリケーションのためのクロスプラットフォームフレームワーク Microsoft Orleans のチュートリアル Tutorial One - Creating a Minimal Orleans Application に従ってアプリケーションを実装する手順について説明した。Orleans の有用性を示す実用的な例ではないので、今後は Orleans の実用性について理解を深めたい。
参考文献
https://github.com/dotnet/orleans
https://dotnet.github.io/orleans/