我有一个接收指标数据点的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,如果可以的话。
答案 0 :(得分:5)
您的聚合器actor目前正在做两件事:聚合和存储。您可以通过拆分这两项任务来解决问题并简化系统。 single-responsibility-principle也适用于演员。
我创建了一个用于编写的专用actor和一个用于保存聚合数据的消息类。这个actor子系统应该如下所示:
理想情况下,写入磁盘所需的时间比聚合间隔短,因此系统保持稳定。如果出现峰值,DataStore actor的队列将作为缓冲区用于将消息写入存储。
根据您的应用程序,您可能需要实施某种形式的ack&如果您想确保已写入聚合数据,则重试。