Scala 来自路由器的消息到达时的Akka路由器增量计数器

Scala 来自路由器的消息到达时的Akka路由器增量计数器,scala,akka,Scala,Akka,我一直在努力指望每一次成功的导入。但这里有一个问题-如果路由器从其父节点接收到消息,计数器会工作,但是如果我试图从其子节点发送消息,它会接收消息,但不会更新超出范围的全局变量。 我知道这听起来很复杂。让我给你看看代码。 这是路由器 class Watcher(size: Int) extends Actor { var router = { val routees = Vector.fill(size) { val w = context

我一直在努力指望每一次成功的导入。但这里有一个问题-如果路由器从其父节点接收到消息,计数器会工作,但是如果我试图从其子节点发送消息,它会接收消息,但不会更新超出范围的全局变量。 我知道这听起来很复杂。让我给你看看代码。 这是路由器

    class Watcher(size: Int) extends Actor { 
      var router = {
        val routees = Vector.fill(size) {
          val w = context.actorOf(
            Props[Worker]
          )
          context.watch(w)
          ActorRefRoutee(w)
        }

        Router(RoundRobinRoutingLogic(), routees)
      }

      var sent = 0

      override def supervisorStrategy(): SupervisorStrategy = OneForOneStrategy(maxNrOfRetries = 100) {
        case _: DocumentNotFoundException => {
          Resume
        }
        case _: Exception => Escalate
      }

      override def receive: Receive = {
        case container: MessageContainer =>
          router.route(container, sender)
        case Success =>
          sent += 1
        case GetValue =>
          sender ! sent
        case Terminated(a) =>
          router.removeRoutee(a)
          val w = context.actorOf(Props[Worker])
          context.watch(w)
          router = router.addRoutee(w)
        case undef =>
          println(s"${this.getClass} received undefinable message: $undef")
      }
}
工人来了

class Worker() extends Actor with ActorLogging {

  var messages = Seq[MessageContainer]()
  var received = 0

  override def receive: Receive = {
    case container: MessageContainer =>
      try {
        importMessage(container.message, container.repo)
        context.parent ! Success
      } catch {
        case e: Exception =>
          throw e
      }
    case e: Error =>
      log.info(s"Error occurred $e")
      sender ! e
    case undef => println(s"${this.getClass} received undefinable message: $undef")
  }
}
那么是
主管?GetValue
我得到0,但假设有1000。最奇怪的是,当我在
case Success=>上的断点处调试它时,…
每次新消息到达时,该值都会递增。但是
主管?GetValue仍然返回0

让我们假设我想依靠
case-container:MessageContainer=>…
,它将神奇地工作;我会得到理想的数字,但它不能显示我是否真的导入了任何东西。发生什么事了

下面是测试用例

 @Test
  def testRouter(): Unit = {
    val system = ActorSystem("RouterTestSystem")

//    val serv = AddressFromURIString("akka.tcp://master@host:1334")
    val supervisor = system.actorOf(Props(new Watcher(20)))//.withDeploy(akka.actor.Deploy(scope = RemoteScope(serv))))

    val repo = coreSession.getRepositoryName
    val containers = (0 until num)
      .map(_ => MessageContainer(MessageFactory.generate("/"), repo))

    val watch = Stopwatch.createStarted()
    (0 until num).par
      .foreach( i => {
      supervisor ! containers.apply(i)
    })

    implicit val timeout = Timeout(60 seconds)
    val future = supervisor ? GetValue
    val result = Await.result(future, timeout.duration).asInstanceOf[Int]

    val speed = result / (watch.elapsed(TimeUnit.MILLISECONDS) / 1000.0)
    println(f"Import speed: $speed%.2f")
    assertEquals(num, result)
  }

你能详细解释一下吗。为什么会这样?为什么只在收到孩子们的信息时才这样做?另一种方法

嗯。。。在您尚未共享的代码部分中可能隐藏着许多潜在问题。但是,为了讨论这个问题,我假设其他一切都很好,我们只讨论共享代码的问题

现在,让我解释一下演员。简单地说,每个参与者都有一个邮箱(它按接收顺序保存消息),并按接收顺序逐个处理消息。由于邮箱的使用方式类似于
队列
,因此在本讨论中将其称为队列

还有。。。我不知道这个
容器。apply(I)
将返回什么。。。因此,我将引用该
容器的返回值。apply(1)
作为
MessageContainer\uu 1

在测试运行程序中,您首先创建了
观察者的一个实例

val supervisor = system.actorOf(Props(new Watcher(20)))
现在,假设您正在将这些
2条消息(num=2)
发送给
supervisor

所以主管的邮箱看起来像

Queue(MessageContainer__0, MessageContainer__1)
然后再向它发送另一条消息
GetValue
,使邮箱看起来像

Queue(MessageContainer__0, MessageContainer__1, GetValue)
Queue(MessageContainer__1, GetValue, Success)
Queue(GetValue, Success, Success)
现在,演员将处理第一条消息并将其传递给工人,邮箱将如下所示:

Queue(MessageContainer__1, GetValue)
现在,即使您的工作人员以极快的速度发送回复,邮箱也会是这样

Queue(MessageContainer__0, MessageContainer__1, GetValue)
Queue(MessageContainer__1, GetValue, Success)
Queue(GetValue, Success, Success)
现在,由于您的工作人员以超快的速度即时回复
成功
,因此传递第二个MessageContainer后的状态如下:

Queue(MessageContainer__0, MessageContainer__1, GetValue)
Queue(MessageContainer__1, GetValue, Success)
Queue(GetValue, Success, Success)
而且。。。这是你问题的根源。无论您的员工速度有多快,
主管在任何
成功
消息之前都会看到
GetValue
消息


因此,它将处理
GetValue
,并使用当前值
sent
进行回复,当前值为0。

那么,如何获取到达的消息量呢。首先,我想到的是创建一个等待循环。。。但是,我认为它不会做得很漂亮。