Scala Akka Streams ActorPublisher未收到任何请求消息
我正在尝试使用以下库连续阅读wikipedia IRC频道: 我创建了一个定制的Akka发行者,它将作为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
源代码在我的系统中使用
以下是我的一些课程:
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的背景线程工作。