Akka持久性receiveRecover接收来自其他actor实例的快照

时间:2015-06-04 16:44:17

标签: akka akka-persistence

使用Akka持久性时遇到意外行为。我对阿卡很新,所以如果我错过了一些明显的东西,请提前道歉。

我有一个叫做PCNProcessor的演员。我为每个PCN id创建一个actor实例。我遇到的问题是,当我创建第一个actor实例时,一切正常,我收到 Processed 响应。但是,当我使用不同的PCN ID创建更多PCNProcessor实例时,我得到了已经处理过的PCN 响应。

基本上,由于某种原因,作为第一个PCN id处理器的一部分存储的快照被重新应用于后续PCN id实例,即使它与该PCN无关并且PCN id不同。为了确认这种行为,我在receiveRecover中打印了一个日志,并且每个后续的PCNProcessor实例都会收到不属于它的快照。

我的问题是:

  1. 我是否应该以特定方式存储快照,以便它们与PCN ID锁定?然后我应该过滤掉与上下文中的PCN无关的快照吗?
  2. 或者Akka框架应该在幕后处理这个问题,我不应该担心存储针对PCN ID的快照。
  3. 演员的源代码如下。我确实使用分片。

    package com.abc.pcn.core.actors
    
    import java.util.UUID
    
    import akka.actor._
    import akka.persistence.{AtLeastOnceDelivery, PersistentActor, SnapshotOffer}
    import com.abc.common.AutoPassivation
    import com.abc.pcn.core.events.{PCNNotProcessedEvt, PCNProcessedEvt}
    
    object PCNProcessor {
    
      import akka.contrib.pattern.ShardRegion
      import com.abc.pcn.core.PCN
    
      val shardName = "pcn"
      val idExtractor: ShardRegion.IdExtractor = {
        case ProcessPCN(pcn) => (pcn.id.toString, ProcessPCN(pcn))
      }
      val shardResolver: ShardRegion.ShardResolver = {
        case ProcessPCN(pcn) => pcn.id.toString
      }
    
      // shard settings
      def props = Props(classOf[PCNProcessor])
    
      // command and response
      case class ProcessPCN(pcn: PCN)
    
      case class NotProcessed(reason: String)
    
      case object Processed
    
    }
    
    class PCNProcessor
      extends PersistentActor
      with AtLeastOnceDelivery
      with AutoPassivation
      with ActorLogging {
    
      import com.abc.pcn.core.actors.PCNProcessor._
    
      import scala.concurrent.duration._
    
      context.setReceiveTimeout(10.seconds)
    
      private val pcnId = UUID.fromString(self.path.name)
      private var state: String = "not started"
    
      override def persistenceId: String = "pcn-processor-${pcnId.toString}"
    
      override def receiveRecover: Receive = {
        case SnapshotOffer(_, s: String) =>
          log.info("Recovering. PCN ID: " + pcnId + ", State to restore: " + s)
          state = s
      }
    
      def receiveCommand: Receive = withPassivation {
    
        case ProcessPCN(pcn)
          if state == "processed" =>
          sender ! Left(NotProcessed("Already processed PCN"))
    
        case ProcessPCN(pcn)
          if pcn.name.isEmpty =>
          val error: String = "Name is invalid"
          persist(PCNNotProcessedEvt(pcn.id, error)) { evt =>
            state = "invalid"
            saveSnapshot(state)
            sender ! Left(NotProcessed(error))
          }
    
        case ProcessPCN(pcn) =>
          persist(PCNProcessedEvt(pcn.id)) { evt =>
            state = "processed"
            saveSnapshot(state)
            sender ! Right(Processed)
          }
      }
    }
    

    更新

    在注销收到的快照的元数据后,我可以看到问题是snapshotterId没有正确解析,并且始终被设置为pcn-processor- $ {pcnId.toString} 解决斜体字。

    [INFO] [06/06/2015 09:10:00.329] [ECP-akka.actor.default-dispatcher-16] [akka.tcp://ECP@127.0.0.1:2551 / user / sharding / pcn / 16b3d4dd-9e0b-45de-8e32-de799d21e7c5]恢复。 PCN ID:16b3d4dd-9e0b-45de-8e32-de799d21e7c5,快照SnapshotMetadata的元数据(pcn-processor - $ {pcnId.toString},1,1433577553585)

2 个答案:

答案 0 :(得分:1)

我认为您滥用Scala字符串插值功能 尝试以下方式:

override def persistenceId: String = s"pcn-processor-${pcnId.toString}"

请注意在字符串文字之前使用s

答案 1 :(得分:0)

确定通过将持久性ID更改为以下行来解决此问题:

override def persistenceId: String = "pcn-processor-" + pcnId.toString

原始字符串版本:

override def persistenceId: String = "pcn-processor-${pcnId.toString}"

仅适用于持久保存而不适用于快照。

相关问题