Microsoftの子会社であるMS Open Techが開発したActorFxは“非規範的な言語に依存しない動的分散オブジェクトのモデル”を提供するのが目的だ。モデルはふたつの部分に分割される。アクターとデータストレージだ。それぞれ、IActorとIActorStateというインターフェースで表される。
IActorStateを使った状態の管理
元々、IActorStateはとてもシンプルなインターフェースだった。本質的にはディクショナリと同じで、Set、Get、TryGet、Remove、Flushを公開している。Flushは非同期で行われ、変更をコミットする。規約により、変更はコミットされるまで“ローカルの副作用バリア”に保存され、コミットされると原子性を保ったまま永続ストレージに保存される。
この単純さには秘密が隠れている。IActorStateはアクティブなコードを含むあらゆるものを保存することができる。
アクターメソッド
アクターを使う前に、アクターに何ができるか教える必要がある。従来の.NETプログラミングとは違い、サーバに手動でコードを配置しただけではだめだ。代わりにIActor.AddAssemblyを使い実行時にメソッドをアクターにプッシュする。アセンブリはバイト配列として表現されるので転送してIActorState自体の内部に保存できる。
つまり各アクターは完全にカプセル化されたオブジェクトなのだ。クラスやプロトタイプからメソッドを継承せず、すべてのメソッドを自前で持つ。これらのメソッドは何度でも変更できる。同じ名前の新しいアセンブリをプッシュすればいいのだ。
アクターメソッドはアセンブリから一度に読み込まれるので、ActorMethod属性でタグ付けする必要がある。タグ付けされたメソッドはデリゲートパターン Func<IActorState, object[], object>に従わなければならない。
アクターにメッセージを送る
IActor.CallMethodはメッセージをアクターに伝えるために使われる。IActor.CallMethodは事前に追加されたアセンブリのメソッド名を表す文字列と配列のパラメータを受け取る。返却値の型はSystem.Objectだ。
IActor.CallMethodでメソッドが呼び出すとき、呼び出し側はクライアントIDとシーケンスナンバーを渡す。こうすることでアクターランタイムは重複リクエストを検知できる。クライアントIDとシーケンスナンバーの組み合わせが一意になるようにするのはクライアントの責任だ。
アクター同士のコミュニケーション
アクター同士はIActorProxyの一時的なインスタンスを使って通信する。このプロキシオブジェクトはひとつのアクターが他のアクターのCallMethodを呼び出せるようにする。
直接メソッドを呼び出せるようにするのに加え、プロキシは購読をセットアップするのにも使える。IObserverの修正版を元にして、アクターが発行したイベントによって購読側のアクターのメソッドが呼び出される。Subscribeメソッドの戻りのトークンの購読はDisposeメソッドを呼ぶことで購読をキャンセルできる。
シンプルなクライアント
ここまで紹介してきたのはアクターランタイムの実装についてだった。多くの開発者はFabricActorClientのようなクライアントを開発してこのランタイムを使うはずだ。次のコードはこのクライアントの主要なメソッドを記述している。
public class FabricActorClient
{
public FabricActorClient(Uri fabricUri, Uri actorUri, bool useGateway);
public bool AddAssembly(string assemblyName, byte[] assemblyBytes);
public Object CallMethod(string methodName, object[] parameters);
public IDisposable Subscribe(string eventType, IObserver<ActorEvent> eventObserver);
}
AddAssemblyが探すのはFunc<IActorState, object[], object>というシグネチャを持つ静的メソッドだということに注意してほしい。
ActorFxは現在アルファ版。CodePlexからダウンロードできる。ライセンスはApache License。