用于处理接收中的异步操作的Akka模式

时间:2014-05-13 06:00:15

标签: scala asynchronous io akka

我有一个接收指标数据点的Actor,并定期聚合并将它们保存到磁盘。后一种操作会进行I / O操作,所以我不想使用阻塞操作。但是,如果我将其切换为异步,如何在聚合完成之前阻止接收其他数据点而不会在某处阻塞。

我见过的一种模式是使用Stash,如下所示:

class Aggregator extends Actor with Stash {
  def receive = processing

  def processing: Receive = {
    case "aggregate" => {
      context.become(aggregating)
      aggregate().onComplete {
        case Success => self ! "aggregated"
        case Failure => self ! "aggregated"
      }
    }
    case msg => ??? // Process task
  }

  def aggregating: Receive = {
    case "aggregated" =>
      unstashAll()
      context.become(processing)
    case msg =>
      stash()
  }
}

我对此的不满是我的集体行动的完成只是任何人都可以发送的信息。据我了解,我不能影响"不合适的"从我未来的完成开始。

作为旁注,我无法确定像onComplete这样的完成是否由同一个调度程序以receive执行,因为如果它们不是,则完成会破坏单线程演员否则提供的保护。

或者是否有一个更好的模式来完成receive内部不同步和直接的动作,同时保证在完成之前我的状态不能改变?似乎这种情况只要演员状态处理任何类型的I / O(如数据库),显然你可以避免同步I / O,如果可以的话。

1 个答案:

答案 0 :(得分:5)

您的聚合器actor目前正在做两件事:聚合和存储。您可以通过拆分这两项任务来解决问题并简化系统。 single-responsibility-principle也适用于演员。

我创建了一个用于编写的专用actor和一个用于保存聚合数据的消息类。这个actor子系统应该如下所示: Aggregator-Store actor subsystem

理想情况下,写入磁盘所需的时间比聚合间隔短,因此系统保持稳定。如果出现峰值,DataStore actor的队列将作为缓冲区用于将消息写入存储。

根据您的应用程序,您可能需要实施某种形式的ack&如果您想确保已写入聚合数据,则重试。