2016-05-24 2 views
0

私はakkaアクターシステムには新しく、アクター内の共通ロジックを実行するためのベストプラクティスは何か迷っていました。akkaシステム - アクター間で共通ロジックを実行するベストプラクティス

class MyActor @Inject()(eventBus: EventBus) extends Actor{ 
    eventBus.subscribe(context.self, Topics.TimeoffPolicy) 
    override def receive: Receive = { 
     case Foo(name:String) => { 
      foo(name) 
      bar(name) 
     } 
     case Bar(name:String) => { 
      bar(name) 
     } 
     case a: Any => log.warning(f"unknown message actor ${a.toString}") 
    } 
} 

class MyActor @Inject()(eventBus: EventBus) extends Actor{ 
    eventBus.subscribe(context.self, Topics.TimeoffPolicy) 
    override def receive: Receive = { 
     case Foo(name:String) => { 
      //Need to execute foo related logic, and then Bar related logic 
     } 
     case Bar(name:String) => { 
      //Need to execute bar related logic 
     } 
     case a: Any => log.warning(f"unknown message actor ${a.toString}") 
    } 
} 

だから、1つのオプションの方法に共通ロジックを抽出し、このようにはFooを扱うときにそれを呼び出すことです:私は、次の俳優を持って

: だからここは一例です

その他のオプションは、自分宛にメッセージを送信することです。

class MyActor @Inject()(eventBus: EventBus) extends Actor{ 
    eventBus.subscribe(context.self, Topics.TimeoffPolicy) 
    override def receive: Receive = { 
     case Foo(name:String) => { 
      foo() 
      self ! Bar(name) 
     } 
     case Bar(name:String) => { 
      bar(name) 
     } 
     case a: Any => log.warning(f"unknown message actor ${a.toString}") 
    } 
} 

ここでは、メッセージを送信し、すべてのメッセージ処理でカプセル化されたロジックを保つことは理にかなっていますが、メソッドに共通のロジックを抽出して呼び出すのはエラープルーニングが少ないと思います。何がお勧めですか?

アクター間で共通のロジックがある場合、イベントバスを介して他のアクターにメッセージを送信して起動するので、actor1はfooを実行し、もう1つはbarを実行します。 第2のオプションは、同じロジックを別のクラスに抽出し、そのクラスを両方のアクターに注入することです。つまり、fooとbarを実行するには、アクター間の通信がありません。

あなたはどう思いますか?

答えて

1

どちらのアプローチも私には正当だと思われますが、私は共有ロジック内の他のアクタを呼び出すかどうかによって2つの方法のどちらかを選択します。基本的に、同期ロジックはメソッドを抽出することで完全に再利用でき、非同期ロジックではメッセージを自己に戻す必要があります。

selfへのメッセージも、Futureコールバックから送信することをお勧めします(実際には、俳優のタスクの実行順序を混乱させないようにするための正しい方法です)。ここで

は、同期的なアプローチを説明するためのスニペットです:自分自身にメッセージを送ることが未来から送られるべきであるのはなぜ

import akka.pattern.{ask, pipe} 
class MyActor extends Actor { 
    val logger = context.actorOf(Props[DedicatedLogger]) 
    def receive = { 
    case Foo(foo) => 
     doSomeFooSpecificWork() 
     loggerActor ? LogFooOrBar(sender(), foo) pipeTo self 

    case Bar(bar) => 
     loggerActor ? LogFooOrBar(sender(), bar) pipeTo self 

    case LoggedFoo(reportTo, foo) => reportTo ! "foo done" 

    case LoggedBar(reportTo, bar) => reportTo ! "bar done" 
    } 
} 
+0

class MyActor extends Actor with ActorLogging { def receive = { case Foo(foo) => doSomeFooSpecificWork() logFooOrBar() sender() ! "foo done" case Bar => logFooOrBar() sender() ! "bar done" } def logFooOrBar() = log.debug("A common message is handled") } 

そして、ここでは、私は、非同期1のために書くだろう何ですか? – Tomer

+1

メッセージを 'self'に送る必要はありません。メッセージの元の' sender'への参照を自由に保存し、直接それに返信することができます。とにかく、 'Actor's'' receive'呼び出しは常に' ActorSystem'によってスケジューリングされ、明示的な同期がない場合の正当性は**あなたのすべてのアクターが同期的に処理するメッセージを受け取ったときに**保証されます。競合状態、古いデータ、デッドロックなどの並行性のすべての不具合につながる、他のスレッドで実行されるので、メッセージを送信すること以外のロジックは 'Future'コールバックにはありません。 – Sergey

+0

Amm、非同期ドライバを使ったデータベースへのエントリ?私は次のようなものを持っています:def receive = {case X(name)=> da.save(name)}、保存戻り値はFuture [String]ですか? – Tomer

関連する問題