Akka-Streams ActorPublisher不会收到任何请求消息

时间:2016-01-31 11:41:18

标签: scala akka akka-stream

我正在尝试使用此库继续阅读维基百科IRC频道:https://github.com/implydata/wikiticker

我创建了一个自定义的Akka Publisher,它将在我的系统中用作Source

以下是我的一些课程:

class IrcPublisher() extends ActorPublisher[String] {
  import scala.collection._

  var queue: mutable.Queue[String] = mutable.Queue()

  override def receive: Actor.Receive = {
    case Publish(s) =>
      println(s"->MSG, isActive = $isActive, totalDemand = $totalDemand")
      queue.enqueue(s)
      publishIfNeeded()

    case Request(cnt) =>
      println("Request: " + cnt)
      publishIfNeeded()

    case Cancel =>
      println("Cancel")
      context.stop(self)

    case _ =>
      println("Hm...")
  }

  def publishIfNeeded(): Unit = {
    while (queue.nonEmpty && isActive && totalDemand > 0) {
      println("onNext")
      onNext(queue.dequeue())
    }
  }
 }

object IrcPublisher {
  case class Publish(data: String)
}

我正在创建所有这些对象:

  def createSource(wikipedias: Seq[String]) {
      val dataPublisherRef = system.actorOf(Props[IrcPublisher])
      val dataPublisher = ActorPublisher[String](dataPublisherRef)
      val listener = new MessageListener {
        override def process(message: Message) = {
          dataPublisherRef ! Publish(Jackson.generate(message.toMap))
        }
      }

      val ticker = new IrcTicker(
        "irc.wikimedia.org",
        "imply",
        wikipedias map (x => s"#$x.wikipedia"),
        Seq(listener)
      )

      ticker.start() // if I comment this...
      Thread.currentThread().join() //... and this I get Request(...)

      Source.fromPublisher(dataPublisher)
}

所以我面临的问题是这个Source对象。虽然此实现适用于其他源(例如来自本地文件),但ActorPublisher不会收到Request()消息。

如果我评论我能看到的两条标记线,我的演员已从我的流程中收到了请求(计数)消息。否则所有消息都将被推送到队列中,但不会在我的流程中(因此我可以看到打印的MSG消息)。

我认为这是多线程/同步的一部分。

2 个答案:

答案 0 :(得分:1)

我不熟悉wikiticker来解决你给出的问题。我要问的一个问题是:为什么有必要加入当前的线程?

但是,我认为你使Source的使用过于复杂。您可以更轻松地使用整个流而不是创建自定义ActorPublisher

您可以使用Source.actorRef将流实现为ActorRef并使用该ActorRef。这允许您利用akka代码对缓冲区进行排队/取消,同时您可以专注于"业务逻辑"。

例如,假设您的整个流只是过滤超过一定长度的行并将其打印到控制台。这可以通过以下方式完成:

def dispatchIRCMessages(actorRef : ActorRef) = {
  val ticker = 
     new IrcTicker("irc.wikimedia.org",
                   "imply",
                   wikipedias map (x => s"#$x.wikipedia"),
                   Seq(new MessageListener {
                         override def process(message: Message) = 
                          actorRef ! Publish(Jackson.generate(message.toMap))
                       }))

  ticker.start()
  Thread.currentThread().join()
}


//these variables control the buffer behavior
val bufferSize = 1024
val overFlowStrategy = akka.stream.OverflowStrategy.dropHead

val minMessageSize = 32

//no need for a custom Publisher/Queue
val streamRef = 
  Source.actorRef[String](bufferSize, overFlowStrategy)
        .via(Flow[String].filter(_.size > minMessageSize))
        .to(Sink.foreach[String](println))
        .run()

dispatchIRCMessages(streamRef)

dispatchIRCMessages具有额外的好处,可以与任何ActorRef一起使用,因此您不需要仅与流/发布商合作。

希望这能解决你的潜在问题......

答案 1 :(得分:1)

我认为主要问题是Thread.currentThread().join()。此行将“挂起”当前线程,因为此线程正在等待自己死亡。请阅读https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#join-long-