来自路由

时间:2016-10-04 20:01:03

标签: scala akka

我试图继续指望每次成功导入。但是这里有一个问题 - 如果路由器收到来自其父节点的消息,则计数器有效但如果我试图从其子节点发送消息它接收到它但是没有更新不在其中的全局变量。范围。  我知道这听起来很复杂。让我告诉你代码。 这是路由器

    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")
  }
}

所以在supervisor ? GetValue我得到0但是假设有1000.最奇怪的是当我用case Success => ...上的断点调试它时,每次新消息到达时值都会递增。但supervisor ? 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)
  }

请你详细解释一下。为什么会这样?为什么只收到孩子们的留言?另一种方法?

1 个答案:

答案 0 :(得分:0)

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

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

另外......我不知道这个container.apply(i)会返回什么...所以我会将container.apply(1)的返回值称为MessageContainer__1 < / p>

在您的测试运行器中,您首先要创建Watcher

的实例
val supervisor = system.actorOf(Props(new Watcher(20)))

现在,我们假设您要将这些2 messages (num = 2)发送给supervisor

所以主管的邮箱看起来像是,

Queue(MessageContainer__0, MessageContainer__1)

然后您发送另一条消息GetValue,以便邮箱看起来像,

Queue(MessageContainer__0, MessageContainer__1, GetValue)

现在演员将处理第一条消息并将其传递给工作人员,邮箱看起来像,

Queue(MessageContainer__1, GetValue)

现在,即使您的工作人员发送回复超快且即时,邮箱也会如此,

Queue(MessageContainer__1, GetValue, Success)

现在,既然你的工作人员超级快速且瞬间回复了Success,那么在传递第二个MessageContainer之后的状态将会是,

Queue(GetValue, Success, Success)

而且......这是你问题的根源。无论你的工作人员有多快,Supervisor在任何GetValue消息之前都会看到Success按摩。

因此它将处理GetValue并以当前值sent回复,该值为0。