如何使用Plays Iteratee处理数据流时等待免费的Akka演员

时间:2016-01-21 00:32:51

标签: asynchronous playframework akka actor iterate

我有无限的流,其中的消息表示为我应用{​​{1}}的播放select countrylanguage.language, country.code, sum(country.population*countrylanguage.percentage/100) from countrylanguage join country on countrylanguage.countrycode = country.code group by countrylanguage.language, country.code order by sum(country.population*countrylanguage.percentage) desc ; 。然后每个消息由Akka actor处理(actor的数量限制为10)。

现在我希望Enumerator中的代码异步等待自由演员如果所有10个演员都忙,而不是向他们发送另一个导致异常Iteratee的消息。

如何实现此类功能?有没有更好的方法来处理10个没有Iteratee的演员的无限流?

我所谈论的代码示例可能如下所示:

Ask timed out on ...

1 个答案:

答案 0 :(得分:0)

使用Iteratee.foldM与你在这里的演员问问模式似乎是正确的方法。假设您不希望您的演员建立大型邮箱(如果您不关心大邮箱,请使用tellIteratee.foreach代替ask)将需要一些专门的路由逻辑。由于用于制作自定义akka路由器的api不支持异步,因此您需要一个自定义actor来处理一次将一件作品分配给actor池中每个actor的逻辑。

我想它的工作方式如下:

class WorkDistributor extends Actor {
  final val NUM_WORKERS = 10
  val workers = context.actorOf(Props[MyWorker].withRouter(RoundRobinRouter(NUM_WORKERS))) 

  var numActiveWorkers = 0
  var queuedWork: Option[Work] = None

  def receive = {
    case IterateeWork(work) if numActiveWorkers < NUM_WORKERS => workers ! work; numActiveWorkers += 1; sender ! SendMeMoreWork
    case IterateeWork(work) => queuedWork = Some(work)
    case ActorFinishedWork if queuedWork.isDefined => queuedWork.foreach(workers ! _); queuedWork = None
    case ActorFinishedWork => numActiveWorkers -= 1; sender ! SendMeMoreWork
  }
}

迭代者发送IterateeWork消息,并且演员池中的actor发送ActorFinishedWork消息。

看看我写的这个东西,应该重写这个以使用become来改变演员池满时的行为(而不是每个案例的if过滤器,但我把它留作为读者锻炼。

然后您的Iteratee看起来像

Iteratee.foldM[Work, SendMeMoreWork.type](SendMeMoreWork) {
  case (_, work) => workDistributor ? IterateeWork(work)
}