我有一个持久的演员。当它第一次启动时(数据库为空)我会保留一些初始数据。但是国家没有像我预期的那样得到更新。只有在处理完第一条消息后才会更新。如何在状态更新后让actor开始处理消息?
演员代码
class TestActor extends PersistentActor {
var numberOfEvents = 0
def updateState(e: Any): Unit = {
println("updating")
numberOfEvents += 1
}
override def receiveRecover: Receive = {
case RecoveryCompleted =>
if (numberOfEvents == 0) {
println("persisting")
persist("foo")(updateState)
}
}
override def receiveCommand: Receive = {
case _ => {
println("answering")
sender ! numberOfEvents
}
}
}
测试代码
Await.result(actorRef ? "stats", Duration.Inf) shouldBe 0 // I wan't 1 here
Await.result(actorRef ? "stats", Duration.Inf) shouldBe 1
输出
persisting
answering // why this goes before updating?
updating
answering
答案 0 :(得分:1)
您要重新考虑的一件事是,您通常不会更新RecoveryCompleted事件的状态,而是处理您持续重建状态的事件。 RecoveryCompleted消息用于处理恢复结束时要执行的操作。这些事件将是您持久保存的日志中重播的事件。如果您使用快照,还可以选择获取快照事件。
例如:
override def receiveRecover: Receive = {
case Added(num) =>
updateState(num)
case SnapshotOffer(metadata, snapshot) ⇒
// Restore your full state from the data in the snapshot
case RecoveryCompleted =>
println("Recovery completed") // use logger here
}
另一方面,receiveCommand用于处理传入的命令并持久保存这些事件,然后在更新这些事件后更新内部状态。
override def receiveCommand: Receive = {
case Add(num) => {
println("received event and persisting")
persist(Added(num){ evt ⇒
// This gets called after the persist succeeds
updateState(num)
sender ! numberOfEvents
}
}
}
def updateState(e: Int): Unit = {
println("updating")
numberOfEvents += e
}
就消息传递而言,我发现将事件命名为命令的过去时非常有用,如下所示:
//活动
案例类已添加(v:Int)
//命令
案例类添加(v:Int)
希望这会让它更清晰一些。