2013-06-09 6 views
7

他の俳優のサービス層の俳優によって一般的に使用されているものがあるとします。たとえば、ドメインオブジェクト取り出し店や、レジストリサービス:Akka - コモン・サービスの俳優:識別または拡張

case class DomainObject(id: UUID) 

class Registry extends akka.actor.Actor { 
    def receive: Receive = { 
    case o: DomainObject => store(o) // save or update object 

    case id: UUID => sender ! retrieve(id) // retrieve object and send it back 
    } 
} 

を私は明示的にそれを使用する可能性のあるすべての関係者に、このようなレジストリのインスタンスを渡す必要はありません。その代わりに、私は彼らに何とか「位置づける」ことができるようにします。このため

私は2つの解決策を考えることができます:

  1. Identifyメッセージ:各レジストリユーザーの俳優は、いくつかの設定と、それに識別メッセージを送ったことができるから、レジストリの俳優の名前を知っています。 AgentIdentityメッセージが戻って受信された後、私たちは行ってもいいです:

    val registryName = ... // some name 
    val registryId = ... // some id 
    var registry = _ 
    
    def preStart() { 
        context.actorSelection(registryName) ! Identify(registryId) 
    } 
    
    def receive: Receive = { 
        case ActorIdentity(`registryId`, ref) => registry = ref 
    } 
    

    右のユーザ俳優初期化した後、システム等でレジストリは、すべてがあれば、我々が知らない段階がありますので、私はこの方法を好きではないし、したがって、私たちは今までに動作するかどうかわからない。

  2. アッカ拡張機能:

    :私は希望拡張機能を作成することができます。初期化時に、指定されたActor Systemでレジストリアクタのインスタンスを作成します。

    b。 Extensionの何らかの方法でこのアクタを必要とするユーザに返します。

    object RegistryKey extends ExtensionKey[RegistryExtension] 
    
    class RegistryExtesion(system: ExtendedActorSystem) extends RegistryKey { 
        val registry = system.actorOf(Props[Registry], "registry") 
    } 
    

質問は:どの方法が優れているとアッカExtesionsがすべてで、このために使用することができていますか?

+0

私はあなたが 'context.actorSelection(registryName)を意味だと思います! (registryId)を識別する '。 'actorFor'は2.2で廃止されましたが、別の解決策です。 – sourcedelica

+0

ええ、あなたは絶対に正しいです。メモリリーク。 :) – Seigert

答えて

3

あなたのレジストリの俳優が常に同じになるつもりである限り、拡張のアイデアは良いと思いますActorSystem

あるいは、(Remote Lookupから適応)actorSelectionを使用して:

class RegistryClient extends Actor { 
    val path = "/path/to/registry/actor" 
    context.setReceiveTimeout(3.seconds) 

    def sendIdentifyRequest(): Unit = 
    context.actorSelection(path) ! Identify(path) 

    def receive = { 
    case ActorIdentity(`path`, Some(ref)) ⇒ 
     context.setReceiveTimeout(Duration.Undefined) 
     context.become(active(ref)) 
    case ActorIdentity(`path`, None) ⇒ 
     throw new RuntimeException("Registry not found") 
    case ReceiveTimeout ⇒ sendIdentifyRequest() 
    } 

    def active(registry: ActorRef): Actor.Receive = { 
    // use the registry 
    } 
} 

これは、リモートまたはローカルのアクターのために動作します。

拡張ソリューションを見てみましょう。 Actors are created asynchronously。したがって、アクターが初期化に失敗した場合は、actorOfを呼び出すと、拡張コンストラクターが失敗することはありません。

アクターが初期化に失敗したことを知りたい場合は、askにアクターが応答し、Awaitに応答があります。アクターが応答しない場合、AwaitTimeoutExceptionを投げます。

class RegistryExtension(system: ExtendedActorSystem) extends Extension { 
    val registry = system.actorOf(Props[Registry], "registry") 
    implicit val timeout: Timeout = Timeout(500.millis) 
    val f = registry ? "ping" // Registry should case "ping" => "pong" 
    Await.result(f, 500.millis) // Will throw a TimeoutException if registry fails 
           // to respond 
} 

初めてRegistryExtension(system).registryを呼び出すときTimeoutExceptionがスローされます。

+0

はい、レジストリは常にそれを使用する俳優と同じシステムになります。 私の主な関心事は、エクステンションがフォールトトレランスでどのように動作するかです。 Extensionがレジストリアクタをインスタンス化できない場合、Extension .registryメソッドの呼び出し中にユーザアクター例外が発生するかどうかを確認します。 これはExtension initでエラーになりますか? – Seigert

+0

レジストリアクターの作成に失敗しました。 – sourcedelica

+0

私はシステムで混合アプローチを使用することに決めました:低結合またはリモート処理が必要な場合は「識別」、システムが動作するにはシステム内にあるべきアクターの場合は拡張が使用されます。 – Seigert

3

subcutのようなCake Patternまたは依存性注入ライブラリはどうですか。

デレク・ワイアットは、俳優をルックアップするために、彼の著書「アッカ同時実行」の代わりのあまりactorForを使用してDIを言及: http://www.artima.com/forums/flat.jsp?forum=289&thread=347118

+0

さて、今はプロジェクトの依存関係を最低限に保ちたいと思います。だから、私は他の俳優への俳優のDIのための別のライブラリが範囲外であると思います。 – Seigert

+1

ケーキパターンは特別な依存関係を必要としません。ちょうどコアScala。 – theon

+0

これは、Dependency Injectionが正しいツールである典型的なケースです。 import Springのようなヘビーウェイトを行う必要はありませんし、XMLをどこからでも使い始めることができます。レジストリのactor refは、それに依存するすべてのアクタのコンストラクタparamになります。アプリケーションの起動時に、アプリケーション全体に渡します。 – Rich

関連する問題