All Downloads are FREE. Search and download functionalities are using the official Maven repository.

no.nextgentel.oss.akkatools.persistence.EnhancedPersistentShardingActor.scala Maven / Gradle / Ivy

There is a newer version: 2.5.0.2
Show newest version
package no.nextgentel.oss.akkatools.persistence

import java.io.UnsupportedEncodingException
import java.net.URLDecoder

import akka.actor.{ActorPath, PoisonPill}
import akka.cluster.sharding.ShardRegion

import scala.concurrent.duration.FiniteDuration
import scala.reflect.ClassTag

/**
  *
  * @param dmSelf dmSelf is used as the address where the DM-confirmation-messages should be sent.
  *               In a sharding environment, this has to be our dispatcher which knows how to reach the sharding mechanism.
  *               If null, we'll fallback to self - useful when testing
  * @tparam E     Superclass/trait representing your events
  * @tparam Ex    Exception-type representing a "known error" - not a failure
  */
abstract class EnhancedPersistentShardingActor[E:ClassTag, Ex <: Exception : ClassTag]
(
  // dmSelf is used as the address where the DM-confirmation-messages should be sent.
  // In a sharding environment, this has to be our dispatcher which knows how to reach the sharding mechanism.
  // If null, we'll fallback to self - useful when testing
  dmSelf:ActorPath
  ) extends EnhancedPersistentActor[E, Ex] {

  // Used as prefix/base when constructing the persistenceId to use - the unique ID is extracted runtime from actorPath which is construced by Sharding-coordinator
  def persistenceIdBase():String

  private lazy val resolvedPersistenceId:String = {
    // Same as in akka 2.3.3
    // We need to have it resolvable like this
    // Sharding is creating instances of these actors with no id in constructor, so we must resolve it from the path.
    // Sharding IS giving each actor a unique name based on the (correct) id.


    // Must extract the id as the last part of the url
    val rawIdFromPath = self.path.elements.last
    val id = try {
      // Sharding urlencodes the last part of the path which is our id - therefor we must url-decode it
      URLDecoder.decode(rawIdFromPath, "UTF-8")
    }
    catch {
      case e: UnsupportedEncodingException => {
        throw new RuntimeException("Error url-decoding rawIdFromPath " + rawIdFromPath, e)
      }
    }

    persistenceIdBase + id

  }

  override def persistenceId: String = resolvedPersistenceId

  protected def onInactiveTimeout() {
    context.parent ! ShardRegion.Passivate(PoisonPill)
  }

  // The dispatchId that is used when sending messages to this actor - typically serviceId or requestId - extract it from actorPath
  lazy val dispatchId: String = {
    val id: String = self.path.name
    try {
      URLDecoder.decode(id, "UTF-8")
    }
    catch {
      case e: UnsupportedEncodingException => {
        throw new RuntimeException("Error url-decoding dispatchId " + id, e)
      }
    }
  }


  // If dmSelf is missing, we're fallbacking to super-impl which is self.
  // When running in a sharded environment, we cannot use our real actors self.
  // We must use our dispatcher, which knows about the sharding mechanism.
  // This has to be like this to make sure the DM confirmation-message is received by the correct sharded instance of our actor.
  override def getDMSelf(): ActorPath = Option(dmSelf).getOrElse(super.getDMSelf())

  // Sending messages with our dispatcherId as confirmation routing info - to help the confirmation coming back to us
  override def sendAsDM(payload: AnyRef, destinationActor: ActorPath): Unit =
    sendAsDM(payload, destinationActor, dispatchId)

  // Sending messages with our dispatcherId as confirmation routing info - to help the confirmation coming back to us
  override def sendAsDM(sendAsDM: SendAsDM): Unit = {
    super.sendAsDM( sendAsDM.copy(confirmationRoutingInfo = dispatchId) )
  }
}

abstract class EnhancedPersistentShardingJavaActor[Ex <: Exception : ClassTag]
(
  // dmSelf is used as the address where the DM-confirmation-messages should be sent.
  // In a sharding environment, this has to be our dispatcher which knows how to reach the sharding mechanism.
  // If null, we'll fallback to self - useful when testing
  dmSelf:ActorPath
) extends EnhancedPersistentShardingActor[AnyRef, Ex](dmSelf) with EnhancedPersistentJavaActorLike {

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy