Akka Typed事件溯源:多实体共用事件日志是否合理?
问题背景
在名为office的应用中存在多个EventSourcedBehavior actor,代码示例如下:
trait OfficeFridgeCommand case object OpenFridge extends OfficeFridgeCommand case object CloseFridge extends OfficeFridgeCommand trait OfficeFridgeEvent case object FridgeOpened extends OfficeFridgeEvent case object FridgeClosed extends OfficeFridgeEvent trait OfficeCoffeeMachineCommand case object MakeCoffee extends OfficeCoffeeMachineCommand trait OfficeCoffeeMachineEvent case object CoffeeMade extends OfficeCoffeeMachineEvent val fridgeEntity = EventSourcedBehavior[OfficeFridgeCommand, OfficeFridgeEvent, OfficeFridge]() val frontDoorEntity = EventSourcedBehavior[OfficeFrontDoorCommand, OfficeFrontDoorEvent, OfficeFridge]() val coffeeMachineEntity = EventSourcedBehavior[OfficeCoffeeMachineCommand, OfficeCoffeeMachineEvent, OfficeFridge]()
冰箱实体已生成1000条带有不同Persistence Ids(0-1000)的事件,事件日志结构如下:
| ordering | persistence_id | event_ser_manifest |
|---|---|---|
| 1 | 200 | FridgeOpened |
| 2 | 200 | FridgeClosed |
| ... | ... | ... |
| 500 | 500 | FridgeOpened |
| ... | ... | ... |
| 1000 | 501 | FridgeClosed |
当frontDoorEntity收到携带persistence id为500的GetCoffeeMachineState消息时,尝试重放该persistence_id对应的事件,但因无法将OfficeFridgeEvent转换为OfficeCoffeeMachineEvent而失败,抛出java.lang.ClassCastException,导致实体无限重启,堆栈信息如下:
at akka.persistence.typed.internal.ReplayingEvents.onJournalResponse(ReplayingEvents.scala:200) at akka.persistence.typed.internal.ReplayingEvents.onMessage(ReplayingEvents.scala:98) at akka.persistence.typed.internal.ReplayingEvents.onMessage(ReplayingEvents.scala:73)
Caused by: java.lang.ClassCastException
咨询问题
多实体共用同一事件日志是否为Akka Typed事件溯源的常见配置?还是每个实体需单独使用仅包含其可处理事件的数据库?
回答
- 多实体共用同一事件日志是Akka Typed事件溯源的标准且常见配置,Akka Persistence的设计初衷就是支持在同一个事件日志中存储不同类型实体的事件,无需为每个实体单独创建数据库或日志分区。
- 你遇到的问题并非来自共用日志本身,而是错误混用了不属于当前实体类型的persistence id:
frontDoorEntity尝试重放属于冰箱实体(persistence id 500)的事件,但该实体的事件类型是OfficeFridgeEvent,和frontDoorEntity预期的OfficeFrontDoorEvent类型不匹配,导致类型转换异常。 - 核心原则是:每个persistence id应唯一对应一种实体类型,不同实体类型的persistence id不能重叠或混用。建议给不同实体的persistence id加上前缀区分,比如
fridge-500、coffee-machine-123、front-door-main,从根源避免跨实体类型重放事件的错误。
内容的提问来源于stack exchange,提问作者Daniel Vas
相关产品推荐
相关产品推荐

