Scala Akka Streams ActorPublisher未收到任何请求消息

Scala Akka Streams ActorPublisher未收到任何请求消息,scala,akka,akka-stream,Scala,Akka,Akka Stream,我正在尝试使用以下库连续阅读wikipedia IRC频道: 我创建了一个定制的Akka发行者,它将作为源代码在我的系统中使用 以下是我的一些课程: class IrcPublisher() extends ActorPublisher[String] { import scala.collection._ var queue: mutable.Queue[String] = mutable.Queue() override def receive: Actor.Receive

我正在尝试使用以下库连续阅读wikipedia IRC频道:

我创建了一个定制的Akka发行者,它将作为
源代码在我的系统中使用

以下是我的一些课程:

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)
}
所以我面临的问题是这个
对象。尽管此实现与其他源(例如本地文件)配合良好,但ActorPublisher不会接收
Request()
消息

如果我对可以看到的两行标记行进行注释,则表明我的参与者已从我的流接收到请求(计数)消息。否则,所有消息将被推送到队列中,但不在我的流中(因此我可以看到打印的消息)


我认为这是多线程/同步的问题。

我对wikiticker不够熟悉,无法解决您的问题。我想问的一个问题是:为什么有必要加入当前线程

但是,我认为您已经将的使用过度复杂化了。将流作为一个整体使用比创建自定义的
ActorPublisher
更容易

您可以使用
Source.actorRef
将流具体化为actorRef并使用该actorRef。这允许您利用akka代码在缓冲区上执行enqueing/dequeing,同时可以专注于“业务逻辑”

例如,您的整个流只是过滤超过一定长度的行并将它们打印到控制台。这可以通过以下方式实现:

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
一起使用,因此您不必只与流/发布者一起使用


希望这能解决您潜在的问题…

我对wikiticker不够熟悉,无法解决您的问题。我想问的一个问题是:为什么有必要加入当前线程

但是,我认为您已经将的使用过度复杂化了。将流作为一个整体使用比创建自定义的
ActorPublisher
更容易

您可以使用
Source.actorRef
将流具体化为actorRef并使用该actorRef。这允许您利用akka代码在缓冲区上执行enqueing/dequeing,同时可以专注于“业务逻辑”

例如,您的整个流只是过滤超过一定长度的行并将它们打印到控制台。这可以通过以下方式实现:

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
一起使用,因此您不必只与流/发布者一起使用


希望这能解决您潜在的问题…

我认为主要的问题是
Thread.currentThread().join()
。此行将“挂起”当前线程,因为该线程正在等待自己死亡。请阅读。

我认为主要问题是
Thread.currentThread().join()
。此行将“挂起”当前线程,因为该线程正在等待自己死亡。请阅读。

我必须等待ticker线程(加入调用),因为ticker需要一些时间来正确初始化。在我的实验中,如果我不加入线程,我将从ticker中获得一些IO异常(InterruptedException)。所以,我认为这是因为一些后台线程从Akka开始工作。我必须等待ticker线程(join调用),因为ticker需要一些时间来正确初始化。在我的实验中,如果我不加入线程,我将从ticker中获得一些IO异常(InterruptedException)。所以,我认为这是因为一些来自Akka的背景线程工作。