2

ここで Akka と Scala の初心者です。Scala と Akka のドメインでの私の意図を明確に表現するために、必要に応じて質問を自由に編集してください。

コード スニペットを示す前に、ここで解決したい問題があります。基本的には、チームが Akka アクターを使用してアプリケーションを開発するときに使用する共通モジュールを開発したいと考えています。主にロギングの目的で、実行時に受信機能を拡張する特性をミックスインできるようにしたいと考えています。コンパイル エラーが発生しましたが、これについては後で説明します。

しかし、まず、単純なメインを例にとります。

object Test extends App {

   val system = ActorSystem("system")
   val myActor = system.actorOf(Props(new MyActor), "myActor")
   myActor ! "Hello world!"
}

チーム メンバーがアプリケーションに実装する可能性のあるアクターの実装例を次に示します。

class MyActor extends Actor with ActorLogger {

   override def receive: Receive = {
       case msg => {
          log.info("testing ...")
       }
       case _ => throw new RuntimeException("Runtime Ex")
   }
}

そして、これが mixin に共通の特性を提供する方法の例です:

trait ActorLogger extends Actor {

    val log: DiagnosticLoggingAdapter = Logging(this)

    abstract override def receive: Receive = {

         case msg: Any => {
            if (msg.isInstanceOf[String]) {
              println("enter")
              log.mdc(Map[String, Any]("someKey" -> 123))
              super.receive(msg)
              log.clearMDC()
               println("exit")
            }
          }

         case _ => throw new RuntimeException("Runtime Ex")
    }

}

ご覧のとおり、メッセージがたまたま String の場合、MDC にデータを追加しようとしています (基本的な例ですが、実際には、独自のカスタム タイプを確認します)。

私が得るエラーは次のとおりです。

 Error:(29, 16) overriding method receive in trait ActorLogger of type =>   
 MyActor.this.Receive;
 method receive needs `abstract override' modifiers
 override def receive: Receive = {
           ^

ここで何が問題なのですか?そして、スタック可能な特性は、このようなことを達成するために放棄する権利がありますか? そうでない場合、最も慣用的な方法は何ですか?

より一般的には、「インターセプター」パターン以外にここで適用されている別のパターンはありますか?

助けてくれてありがとう!

4

3 に答える 3

6

akkaパッケージを使用したハックなしのソリューション:

import akka.actor.{Actor, ActorSystem, Props}

trait MyActorExtension extends Actor {

  def receiveExtension: Receive = PartialFunction.empty

}

abstract class MyActor extends MyActorExtension {

  protected def receiveMsg: Receive

  def receive: Receive = receiveExtension orElse receiveMsg

}

trait ActorLogger1 extends MyActor with MyActorExtension {

  abstract override def receiveExtension = {
    case msg =>
      println(s"********** Logging # 1: $msg")
      super.receiveExtension.applyOrElse(msg, receiveMsg)
  }

}

trait ActorLogger2 extends MyActor with MyActorExtension {

  abstract override def receiveExtension = {
    case msg =>
      println(s"########## Logging # 2: $msg")
      super.receiveExtension.applyOrElse(msg, receiveMsg)
  }
}

class SpecificActor extends MyActor with ActorLogger1 with ActorLogger2 {

  def receiveMsg = {
    case someMsg =>
      println(s"SpecificActor: $someMsg")
  }
}

object Test extends App {

  val system = ActorSystem("system")
  val mySpecificActor = system.actorOf(Props(new SpecificActor), "SpecificActor")
  mySpecificActor ! "Hello world!"
}
#### ロギング # 2: Hello world!

******ロギング # 1: Hello world!

SpecificActor: Hello world!

于 2014-08-01T09:45:01.820 に答える
4

aroundReceiveは Akka の内部使用用であり、積み重ね可能なトレイル パターンはこの場合にはそれほど快適ではありません。簡単にメッセージを傍受できるように、受信パイプラインを使用することをお勧めします。

于 2014-11-03T21:23:43.203 に答える
1

このようなものが必要だと思います

package akka

import akka.MsgsProt._
import akka.actor.{ Actor, ActorSystem, Props }

import scala.concurrent.duration._

sealed trait MsgProt
object MsgsProt {
  case object FooMsg extends MsgProt
  case object BarMsg extends MsgProt
}

trait Foo extends Actor {

  override protected[akka] def aroundReceive(receive: Actor.Receive, msg: Any): Unit = msg match {
    case FooMsg => println("Foo message")
    case msg    => super.aroundReceive(receive, msg)
  }
}

trait Bar extends Actor {
  override protected[akka] def aroundReceive(receive: Actor.Receive, msg: Any): Unit = msg match {
    case BarMsg => println("Bar message")
    case msg    => super.aroundReceive(receive, msg)
  }
}

class MyActor extends Actor with Foo with Bar {
  override def receive: Actor.Receive = {
    case _ => println("Nothing I know")
  }
}

object Foo extends App {
  val system = ActorSystem("foobar")
  val myActor = system.actorOf(Props[MyActor])
  implicit val timeout = 2 seconds

  myActor ! FooMsg
  myActor ! BarMsg
  myActor ! "wrong message"

  system.awaitTermination(10 seconds)
}

このプログラムの出力は次のとおりです。 Foo メッセージ Bar メッセージ Nothing I know

最も重要な部分は、そのパッケージ宣言です - akka. メソッドaroundReceiveは akka パッケージのみに限定されているため、 some.package.akka が必要であり、内部でそのメソッドを使用できますaroundReceive。解決策ではなくハックのように見えますが、機能すると思います。これは、Akka 自体の内部でさらに使用されていることがわかります。akka.DiagnosticActorLogging . しかし、これは基本的に、アクタの動作を積み重ねて実行したいソリューションです。

于 2014-08-01T08:54:23.020 に答える