akka.persistence.PersistentActor Scala Examples
The following examples show how to use akka.persistence.PersistentActor.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example.
Example 1
Source File: TestActor.scala From akka-persistence-couchbase with Apache License 2.0 | 5 votes |
package akka.persistence.couchbase import akka.actor.{ActorLogging, ActorRef, Props} import akka.persistence.{DeleteMessagesSuccess, PersistentActor, RecoveryCompleted} import akka.persistence.couchbase.TestActor.{GetLastRecoveredEvent, SaveSnapshot} import akka.persistence.journal.Tagged import scala.collection.immutable object TestActor { def props(persistenceId: String): Props = props(persistenceId, "couchbase-journal.write") def props(persistenceId: String, journalId: String): Props = Props(new TestActor(persistenceId, journalId)) final case class PersistAll(events: immutable.Seq[String]) final case class PersistAllAsync(events: immutable.Seq[String]) final case class DeleteTo(seqNr: Long) final case object SaveSnapshot final case object GetLastRecoveredEvent case object Stop } class TestActor(override val persistenceId: String, override val journalPluginId: String) extends PersistentActor with ActorLogging { var lastDelete: ActorRef = _ var lastRecoveredEvent: String = _ val receiveRecover: Receive = { case evt: String => lastRecoveredEvent = evt case RecoveryCompleted => log.debug("Recovery completed, lastRecoveredEvent: {}", lastRecoveredEvent) } val receiveCommand: Receive = { case cmd: String => persist(cmd) { evt => sender() ! evt + "-done" } case cmd: Tagged => persist(cmd) { evt => val msg = s"${evt.payload}-done" sender() ! msg } case TestActor.PersistAll(events) => val size = events.size val handler = { var count = 0 _: String => { count += 1 if (count == size) sender() ! "PersistAll-done" } } persistAll(events)(handler) case TestActor.PersistAllAsync(events) => val size = events.size val handler = { var count = 0 evt: String => { count += 1 if (count == size) sender() ! "PersistAllAsync-done" } } persistAllAsync(events)(handler) sender() ! "PersistAllAsync-triggered" case TestActor.DeleteTo(seqNr) => lastDelete = sender() deleteMessages(seqNr) case d: DeleteMessagesSuccess => lastDelete ! d case SaveSnapshot => saveSnapshot("dumb-snapshot-body") sender() ! snapshotSequenceNr case GetLastRecoveredEvent => sender() ! lastRecoveredEvent case TestActor.Stop => context.stop(self) } }
Example 2
Source File: CurrentPersistenceIdsQuerySourceTest.scala From apache-spark-test with Apache License 2.0 | 5 votes |
package com.github.dnvriend.spark.sstreaming import java.util.UUID import java.util.concurrent.atomic.AtomicLong import akka.actor.{ ActorRef, Props } import akka.persistence.PersistentActor import akka.testkit.TestProbe import com.github.dnvriend.TestSpec import com.github.dnvriend.spark.datasources.SparkImplicits._ import com.github.dnvriend.spark.datasources.person.Person import org.apache.spark.sql.streaming.{ OutputMode, ProcessingTime } import org.scalatest.Ignore import scala.concurrent.ExecutionContext import scala.concurrent.duration._ import scala.language.implicitConversions object PersonActor { final case class BlogPost(id: Long, text: String) } class PersonActor(val persistenceId: String, schedule: Boolean)(implicit ec: ExecutionContext) extends PersistentActor { val counter = new AtomicLong() def ping() = context.system.scheduler.scheduleOnce(200.millis, self, "persist") def randomId: String = UUID.randomUUID.toString override val receiveRecover: Receive = PartialFunction.empty override val receiveCommand: Receive = { case "persist" => persist(Person(counter.incrementAndGet(), s"foo-$randomId", 20)) { _ => sender() ! "ack" } if (schedule) ping() } if (schedule) ping() } @Ignore class CurrentPersistenceIdsQuerySourceTest extends TestSpec { def withPersistentActor(pid: String = randomId, schedule: Boolean = false)(f: ActorRef => TestProbe => Unit): Unit = { val tp = TestProbe() val ref = system.actorOf(Props(new PersonActor(pid, schedule))) try f(ref)(tp) finally killActors(ref) } it should "query read journal" in withSparkSession { spark => withPersistentActor() { ref => tp => tp.send(ref, "persist") tp.expectMsg("ack") val jdbcReadJournal = spark.readStream .currentPersistenceIds("jdbc-read-journal") jdbcReadJournal.printSchema() println("Is the query streaming: " + jdbcReadJournal.isStreaming) println("Are there any streaming queries? " + spark.streams.active.isEmpty) val query = jdbcReadJournal .writeStream .format("console") .trigger(ProcessingTime(1.seconds)) .queryName("consoleStream") .outputMode(OutputMode.Append()) .start() query.awaitTermination(10.seconds) } } }
Example 3
Source File: UserRepository.scala From gabbler with Apache License 2.0 | 5 votes |
package de.heikoseeberger.gabbler.user import akka.NotUsed import akka.actor.{ ActorLogging, Props } import akka.persistence.PersistentActor import akka.persistence.query.EventEnvelope import akka.persistence.query.scaladsl.EventsByPersistenceIdQuery import akka.stream.scaladsl.Source object UserRepository { sealed trait UserEvent final case object GetUsers final case class Users(users: Set[User]) final case class AddUser(username: String, nickname: String, email: String) final case class UserAdded(user: User) extends UserEvent final case class UsernameTaken(username: String) final case class RemoveUser(id: Long) final case class UserRemoved(user: User) extends UserEvent final case class IdUnknown(id: Long) final case class GetUserEvents(fromSeqNo: Long) final case class UserEvents(userEvents: Source[(Long, UserEvent), NotUsed]) final case class User(id: Long, username: String, nickname: String, email: String) final val Name = "user-repository" def apply(readJournal: EventsByPersistenceIdQuery): Props = Props(new UserRepository(readJournal)) } final class UserRepository(readJournal: EventsByPersistenceIdQuery) extends PersistentActor with ActorLogging { import UserRepository._ override val persistenceId = Name private var users = Map.empty[String, User] override def receiveCommand = { case GetUsers => sender() ! Users(users.valuesIterator.to[Set]) case AddUser(username, nickname, email) => handleAddUser(username, nickname, email) case RemoveUser(id) => handleRemoveUser(id) case GetUserEvents(fromSeqNo) => handleGetUserEvents(fromSeqNo) } override def receiveRecover = { case UserAdded(user) => users += user.username -> user case UserRemoved(user) => users -= user.username } private def handleAddUser(username: String, nickname: String, email: String) = { def add() = persist(UserAdded(User(lastSequenceNr, username, nickname, email))) { userAdded => receiveRecover(userAdded) log.info("Added user with username {}", username) sender() ! userAdded } if (!users.contains(username)) add() else sender() ! UsernameTaken(username) } private def handleRemoveUser(id: Long) = { def remove(user: User) = persist(UserRemoved(user)) { userRemoved => receiveRecover(userRemoved) log.info("Removed user with id {} and username {}", id, user.username) sender() ! userRemoved } users.valuesIterator.find(_.id == id) match { case Some(user) => remove(user) case None => sender() ! IdUnknown(id) } } private def handleGetUserEvents(fromSeqNo: Long) = { val userEvents = readJournal .eventsByPersistenceId(Name, fromSeqNo, Long.MaxValue) .collect { case EventEnvelope(_, _, seqNo, event: UserEvent) => seqNo -> event } sender() ! UserEvents(userEvents) } }
Example 4
Source File: UserRepository.scala From gabbler with Apache License 2.0 | 5 votes |
package de.heikoseeberger.gabbler.chat import akka.actor.{ ActorLogging, Props } import akka.http.scaladsl.Http import akka.http.scaladsl.model.Uri import akka.persistence.{ PersistentActor, RecoveryCompleted } import akka.stream.ActorMaterializer import akka.stream.alpakka.sse.scaladsl.EventSource import de.heikoseeberger.akkasse.ServerSentEvent import io.circe.parser.decode object UserRepository { private sealed trait UserEvent final case class FindUserByUsername(username: String) final case class UsernameUnknown(username: String) private final case class AddUser(id: Long, username: String, nickname: String) private final case class UserAdded(eventId: String, user: User) private final case class RemoveUser(id: Long) private final case class UserRemoved(eventId: String, user: User) final case class User(id: Long, username: String, nickname: String) final val Name = "user-repository" def apply(userEventsEndpoint: Uri): Props = Props(new UserRepository(userEventsEndpoint)) } final class UserRepository(userEventsEndpoint: Uri) extends PersistentActor with ActorLogging { import UserRepository._ import io.circe.generic.auto._ override val persistenceId = Name private implicit val mat = ActorMaterializer() private var users = Map.empty[String, User] private var lastEventId = Option.empty[String] override def receiveCommand = { case FindUserByUsername(n) => handleFindUserByUsername(n) case (eventId: String, AddUser(i, u, n)) => handleAddUser(eventId, i, u, n) case (eventId: String, RemoveUser(i)) => handleRemoveUser(eventId, i) } override def receiveRecover = { case RecoveryCompleted => userEvents(lastEventId).runForeach(self ! _) case UserAdded(eventId, user) => lastEventId = Some(eventId) users += user.username -> user log.info("Added user with username {}", user.username) case UserRemoved(eventId, user) => lastEventId = Some(eventId) users -= user.username log.info("Removed user with username {}", user.username) } private def handleFindUserByUsername(username: String) = users.get(username) match { case Some(user) => sender() ! user case None => sender() ! UsernameUnknown(username) } private def handleAddUser(eventId: String, id: Long, username: String, nickname: String) = persist(UserAdded(eventId, User(id, username, nickname)))(receiveRecover) private def handleRemoveUser(eventId: String, id: Long) = users.values.find(_.id == id) match { case Some(user) => persist(UserRemoved(eventId, user))(receiveRecover) case None => log.warning("User with id {} does not exist!", id) } private def userEvents(lastEventId: Option[String]) = EventSource(userEventsEndpoint, Http(context.system).singleRequest(_), lastEventId) .collect { case ServerSentEvent(Some(data), Some("user-added"), Some(eventId), _) => eventId -> decode[AddUser](data) case ServerSentEvent(Some(data), Some("user-removed"), Some(eventId), _) => eventId -> decode[RemoveUser](data) } .collect { case (eventId, Right(userEvent)) => eventId -> userEvent } }
Example 5
Source File: AtLeastOnce.scala From reactive-application-development-scala with Apache License 2.0 | 5 votes |
import akka.actor.{ Actor, ActorSelection } import akka.persistence.{ AtLeastOnceDelivery, PersistentActor } sealed trait Cmd case class SayHello(deliveryId: Long, s: String) extends Cmd case class ReceiveHello(deliveryId: Long) extends Cmd sealed trait Evt case class HelloSaid(s: String) extends Evt case class HelloReceived(deliveryId: Long) extends Evt class SendActor(destination: ActorSelection) extends PersistentActor with AtLeastOnceDelivery { override def persistenceId: String = "persistence-id" override def receiveCommand: Receive = { case s: String => persist(HelloSaid(s))(updateState) case ReceiveHello(deliveryId) => persist(HelloReceived(deliveryId))(updateState) } override def receiveRecover: Receive = { case evt: Evt => updateState(evt) } def updateState(evt: Evt): Unit = evt match { case HelloSaid(s) => deliver(destination)(deliveryId => SayHello(deliveryId, s)) case HelloReceived(deliveryId) => confirmDelivery(deliveryId) } } class ReceiveActor extends Actor { def receive = { case SayHello(deliveryId, s) => // ... do something with s sender() ! ReceiveHello(deliveryId) } }
Example 6
Source File: DeduplicationInterceptor.scala From akka-cqrs with Apache License 2.0 | 5 votes |
package com.productfoundry.akka.cqrs.process import akka.persistence.PersistentActor import akka.productfoundry.contrib.pattern.ReceivePipeline import akka.productfoundry.contrib.pattern.ReceivePipeline.{HandledCompletely, Inner} import com.productfoundry.akka.cqrs.AggregateEventRecord trait DeduplicationInterceptor { this: PersistentActor with ReceivePipeline => private var deduplicationIds: Set[String] = Set.empty pipelineInner { case eventRecord: AggregateEventRecord => val deduplicationId = eventRecord.tag.value if (deduplicationIds.contains(deduplicationId)) { HandledCompletely } else { persist(DeduplicationEntry(deduplicationId))( _ => handled(deduplicationId)) Inner(eventRecord) } } override def receiveRecover: Receive = { case DeduplicationEntry(deduplicationId) => handled(deduplicationId) } protected def handled(deduplicationId: String): Unit = { deduplicationIds += deduplicationId } }
Example 7
Source File: WFActor.scala From Scala-Reactive-Programming with MIT License | 5 votes |
package com.packt.publishing.cassandra.actor import akka.actor.{ActorLogging, Props} import akka.persistence.{PersistentActor, Recovery, RecoveryCompleted, SnapshotOffer} import com.packt.publishing.cassandra.commands.{AddWF, PrintWF, RemoveWF, SnapshotWF} import com.packt.publishing.cassandra.events.{WFAdded, WFEvent, WFRemoved} import com.packt.publishing.cassandra.state.WFState object WFActor { def props(id: String, recovery: Recovery) = Props(new WFActor(id, recovery)) } class WFActor(id: String, rec: Recovery) extends PersistentActor with ActorLogging { override val persistenceId = id override val recovery = rec var state = WFState() def updateState(event: WFEvent) = state = state.update(event) val receiveRecover: Receive = { case evt: WFEvent => log.info(s"Replaying event: $evt") updateState(evt) case SnapshotOffer(_, recoveredState : WFState) => log.info(s"Snapshot offered: $recoveredState") state = recoveredState case RecoveryCompleted => log.info(s"Recovery completed. Current state: $state") } val receiveCommand: Receive = { case AddWF(wf) => persist(WFAdded(wf))(updateState) case RemoveWF(wf) => persist(WFRemoved(wf))(updateState) case SnapshotWF => saveSnapshot(state) case PrintWF => log.info(s"Current state: $state") } }
Example 8
Source File: UserHandler.scala From reactive-microservices with MIT License | 5 votes |
import akka.actor.{ActorLogging, ActorRef, PoisonPill, Props} import akka.persistence.PersistentActor import akka.routing.{RemoveRoutee, ActorRefRoutee, AddRoutee} import btc.common.UserHandlerMessages._ import btc.common.WebSocketHandlerMessages.{OperationSuccessful, Alarm, AllSubscriptions} import scala.collection.mutable import scala.concurrent.duration._ import UserHandler._ object UserHandler { case object KeepAlive case class Ticker(max: BigDecimal, min: BigDecimal, last: BigDecimal, bid: BigDecimal, ask: BigDecimal, vwap: BigDecimal, average: BigDecimal, volume: BigDecimal) def props(userId: Long, wsActor: ActorRef, broadcaster: ActorRef, keepAliveTimeout: FiniteDuration) = { Props(new UserHandler(userId, wsActor, broadcaster, keepAliveTimeout)) } } class UserHandler(userId: Long, wsActor: ActorRef, broadcaster: ActorRef, keepAliveTimeout: FiniteDuration) extends PersistentActor with ActorLogging { override val persistenceId: String = userId.toString override def preStart(): Unit = { super.preStart() broadcaster ! AddRoutee(ActorRefRoutee(self)) } override def postStop(): Unit = { super.postStop() broadcaster ! RemoveRoutee(ActorRefRoutee(self)) } override def receiveRecover: Receive = { case subscribe: Subscribe => updateState(subscribe) case unsubscribe: Unsubscribe => updateState(unsubscribe) } override def receiveCommand: Receive = { case KeepAlive if System.currentTimeMillis() - lastHeartBeatTime > keepAliveTimeout.toMillis => log.info(s"Timeout while waiting for heartbeat for user $userId, stopping") self ! PoisonPill case Heartbeat => log.debug(s"Got heartbeat for user $userId") lastHeartBeatTime = System.currentTimeMillis() sender() ! Heartbeat case QuerySubscriptions => log.info(s"Got request for subscriptions for user $userId") wsActor ! AllSubscriptions(subscriptions.values.toList) case ticker: Ticker => val alarms = getAlarmsForTicker(ticker) log.debug(s"Got ticker and sending alarms $alarms for user $userId") alarms.foreach(wsActor ! _) case subscribe: Subscribe => log.debug(s"Got subscribe request $subscribe for user $userId") persist(subscribe) { e => updateState(e) wsActor ! OperationSuccessful(e.id) } case unsubscribe: Unsubscribe => log.debug(s"Got unsubscribe request $unsubscribe for user $userId") persist(unsubscribe) { e => updateState(e) wsActor ! OperationSuccessful(e.id) } } private def updateState(subscribe: Subscribe) = subscriptions.put(subscribe.id, subscribe) private def updateState(unsubscribe: Unsubscribe) = subscriptions.remove(unsubscribe.id) private def getAlarmsForTicker(ticker: Ticker): List[Alarm] = { subscriptions.values.map { case SubscribeRateChange(id) => Option(Alarm(id, ticker.average)) case SubscribeBidOver(id, threshold) => if (ticker.bid > threshold) Option(Alarm(id, ticker.bid)) else None case SubscribeAskBelow(id, threshold) => if (ticker.ask < threshold) Option(Alarm(id, ticker.ask)) else None case SubscribeVolumeOver(id, threshold) => if (ticker.volume > threshold) Option(Alarm(id, ticker.volume)) else None case SubscribeVolumeBelow(id, threshold) => if (ticker.volume < threshold) Option(Alarm(id, ticker.volume)) else None }.toList.flatten } private val subscriptions = mutable.Map.empty[Long, Subscribe] private var lastHeartBeatTime = System.currentTimeMillis() }
Example 9
Source File: ClusterShardingQuickTerminationSpec.scala From akka-persistence-cassandra with Apache License 2.0 | 5 votes |
package akka.persistence.cassandra.sharding import akka.actor.{ ActorLogging, ActorRef, Props, ReceiveTimeout } import akka.cluster.{ Cluster, MemberStatus } import akka.cluster.sharding.{ ClusterSharding, ClusterShardingSettings, ShardRegion } import akka.persistence.PersistentActor import akka.persistence.cassandra.CassandraSpec import akka.testkit.TestProbe import scala.concurrent.duration._ object ClusterShardingQuickTerminationSpec { case object Increment case object Decrement final case class Get(counterId: Long) final case class EntityEnvelope(id: Long, payload: Any) case object Ack case object Stop final case class CounterChanged(delta: Int) class Counter extends PersistentActor with ActorLogging { import ShardRegion.Passivate context.setReceiveTimeout(5.seconds) // self.path.name is the entity identifier (utf-8 URL-encoded) override def persistenceId: String = "Counter-" + self.path.name var count = 0 def updateState(event: CounterChanged): Unit = count += event.delta override def receiveRecover: Receive = { case evt: CounterChanged => updateState(evt) case other => log.debug("Other: {}", other) } override def receiveCommand: Receive = { case Increment => persist(CounterChanged(+1))(updateState) case Decrement => persist(CounterChanged(-1))(updateState) case Get(_) => sender() ! count case ReceiveTimeout => context.parent ! Passivate(stopMessage = Stop) case Stop => sender() ! Ack context.stop(self) } } val extractEntityId: ShardRegion.ExtractEntityId = { case EntityEnvelope(id, payload) => (id.toString, payload) case msg @ Get(id) => (id.toString, msg) } val numberOfShards = 100 val extractShardId: ShardRegion.ExtractShardId = { case EntityEnvelope(id, _) => (id % numberOfShards).toString case Get(id) => (id % numberOfShards).toString } } class ClusterShardingQuickTerminationSpec extends CassandraSpec(""" akka.actor.provider = cluster """.stripMargin) { import ClusterShardingQuickTerminationSpec._ "Cassandra Plugin with Cluster Sharding" must { "clear state if persistent actor shuts down" in { Cluster(system).join(Cluster(system).selfMember.address) awaitAssert { Cluster(system).selfMember.status shouldEqual MemberStatus.Up } ClusterSharding(system).start( typeName = "tagging", entityProps = Props[Counter], settings = ClusterShardingSettings(system), extractEntityId = extractEntityId, extractShardId = extractShardId) (0 to 100).foreach { i => val counterRegion: ActorRef = ClusterSharding(system).shardRegion("tagging") awaitAssert { val sender = TestProbe() counterRegion.tell(Get(123), sender.ref) sender.expectMsg(500.millis, i) } counterRegion ! EntityEnvelope(123, Increment) counterRegion ! Get(123) expectMsg(i + 1) counterRegion ! EntityEnvelope(123, Stop) expectMsg(Ack) } } } }
Example 10
Source File: TestActor.scala From akka-persistence-cassandra with Apache License 2.0 | 5 votes |
package akka.persistence.cassandra.query import scala.collection.immutable import akka.actor.Props import akka.persistence.PersistentActor import akka.actor.ActorRef import akka.persistence.DeleteMessagesSuccess import akka.persistence.cassandra.EventWithMetaData import akka.persistence.journal.Tagged object TestActor { def props(persistenceId: String, journalId: String = "akka.persistence.cassandra.journal"): Props = Props(new TestActor(persistenceId, journalId)) final case class PersistAll(events: immutable.Seq[String]) final case class DeleteTo(seqNr: Long) } class TestActor(override val persistenceId: String, override val journalPluginId: String) extends PersistentActor { var lastDelete: ActorRef = _ val receiveRecover: Receive = { case evt: String => } val receiveCommand: Receive = { case cmd: String => persist(cmd) { evt => sender() ! evt + "-done" } case cmd: EventWithMetaData => persist(cmd) { evt => sender() ! s"$evt-done" } case cmd: Tagged => persist(cmd) { evt => val msg = s"${evt.payload}-done" sender() ! msg } case TestActor.PersistAll(events) => val size = events.size val handler = { var count = 0 evt: String => { count += 1 if (count == size) sender() ! "PersistAll-done" } } persistAll(events)(handler) case TestActor.DeleteTo(seqNr) => lastDelete = sender() deleteMessages(seqNr) case d: DeleteMessagesSuccess => lastDelete ! d } }
Example 11
Source File: TestTaggingActor.scala From akka-persistence-cassandra with Apache License 2.0 | 5 votes |
package akka.persistence.cassandra import akka.actor.{ ActorLogging, ActorRef, Props } import akka.persistence.cassandra.journal.TagWriterSpec.TestEx import akka.persistence.{ PersistentActor, RecoveryCompleted, SaveSnapshotSuccess } import akka.persistence.journal.Tagged object TestTaggingActor { case object Ack case object Crash case object DoASnapshotPlease case object SnapShotAck case object Stop def props(pId: String, tags: Set[String] = Set(), probe: Option[ActorRef] = None): Props = Props(new TestTaggingActor(pId, tags, probe)) } class TestTaggingActor(val persistenceId: String, tags: Set[String], probe: Option[ActorRef]) extends PersistentActor with ActorLogging { import TestTaggingActor._ def receiveRecover: Receive = { case RecoveryCompleted => probe.foreach(_ ! RecoveryCompleted) case _ => } def receiveCommand: Receive = normal def normal: Receive = { case event: String => log.debug("Persisting {}", event) persist(Tagged(event, tags)) { e => processEvent(e) sender() ! Ack } case Crash => throw TestEx("oh dear") case DoASnapshotPlease => saveSnapshot("i don't have any state :-/") context.become(waitingForSnapshot(sender())) case Stop => context.stop(self) } def waitingForSnapshot(who: ActorRef): Receive = { case SaveSnapshotSuccess(_) => who ! SnapShotAck context.become(normal) } def processEvent: Receive = { case _ => } }
Example 12
Source File: BlogEntity.scala From akka-blog-example with Apache License 2.0 | 5 votes |
package com.spr.blog import akka.actor.Props import akka.pattern.pipe import akka.persistence.{PersistentActor, SnapshotOffer} import scala.concurrent.{Future, Promise} class BlogEntity extends PersistentActor { import BlogEntity._ import context._ private var state = BlogState() // in order to really match the Lagom example properly, we'd create an actor for every blog post, though that // sounds a bit overkill to me. then our persistenceId would be something like s"blog-$id". override def persistenceId: String = "blog" override def receiveCommand: Receive = { case GetPost(id) => sender() ! state(id) case AddPost(content) => handleEvent(PostAdded(PostId(), content)) pipeTo sender() () case UpdatePost(id, content) => state(id) match { case response @ Left(_) => sender() ! response case Right(_) => handleEvent(PostUpdated(id, content)) pipeTo sender() () } } private def handleEvent[E <: BlogEvent](e: => E): Future[E] = { val p = Promise[E] persist(e) { event => p.success(event) state += event system.eventStream.publish(event) if (lastSequenceNr != 0 && lastSequenceNr % 1000 == 0) saveSnapshot(state) } p.future } override def receiveRecover: Receive = { case event: BlogEvent => state += event case SnapshotOffer(_, snapshot: BlogState) => state = snapshot } } object BlogEntity { def props = Props(new BlogEntity) sealed trait BlogCommand final case class GetPost(id: PostId) extends BlogCommand final case class AddPost(content: PostContent) extends BlogCommand final case class UpdatePost(id: PostId, content: PostContent) extends BlogCommand sealed trait BlogEvent { val id: PostId val content: PostContent } final case class PostAdded(id: PostId, content: PostContent) extends BlogEvent final case class PostUpdated(id: PostId, content: PostContent) extends BlogEvent final case class PostNotFound(id: PostId) extends RuntimeException(s"Blog post not found with id $id") type MaybePost[+A] = Either[PostNotFound, A] final case class BlogState(posts: Map[PostId, PostContent]) { def apply(id: PostId): MaybePost[PostContent] = posts.get(id).toRight(PostNotFound(id)) def +(event: BlogEvent): BlogState = BlogState(posts.updated(event.id, event.content)) } object BlogState { def apply(): BlogState = BlogState(Map.empty) } }
Example 13
Source File: HasPersistence.scala From ForestFlow with Apache License 2.0 | 5 votes |
package ai.forestflow.serving.cluster import akka.actor.{Actor, ActorLogging} import akka.persistence.PersistentActor trait HasPersistence extends ActorLogging { this: PersistentActor => def persistencePrefix: String override def persistenceId: String = { /*log.info(s"Getting persistenceId: akka.serialization.Serialization.serializedActorPath(self) = ${akka.serialization.Serialization.serializedActorPath(self)}") log.info(s"self.path.address = ${self.path.address}") log.info(s"self.path.elements.toList.mkString('-') = ${self.path.elements.toList.mkString("-")}") log.info(s"self.path.elements.toString() = ${self.path.elements.toString()}") log.info(s"self.path.toStringWithAddress(self.path.address) = ${self.path.toStringWithAddress(self.path.address)}") log.info(s"self.path.toString = ${self.path.toString}")*/ s"$persistencePrefix-${context.parent.path.name}-${self.path.name}" } }
Example 14
Source File: Person.scala From akka-serialization-test with Apache License 2.0 | 5 votes |
package com.github.dnvriend.domain import akka.actor.ActorLogging import akka.event.LoggingReceive import akka.persistence.{ PersistentActor, RecoveryCompleted } object Person { sealed trait PersonEvent final case class NameRegisteredEvent(name: String, surname: String) extends PersonEvent final case class NameChangedEvent(name: String) extends PersonEvent final case class SurnameChangedEvent(surname: String) extends PersonEvent sealed trait PersonCommand final case class RegisterNameCommand(name: String, surname: String) extends PersonCommand final case class ChangeNameCommand(name: String) extends PersonCommand final case class ChangeSurnameCommand(surname: String) extends PersonCommand } class Person(val persistenceId: String) extends PersistentActor with ActorLogging { import Person._ var name: String = _ var surname: String = _ override def receiveRecover: Receive = LoggingReceive { case e: NameRegisteredEvent ⇒ handleEvent(e) case e: NameChangedEvent ⇒ handleEvent(e) case e: SurnameChangedEvent ⇒ handleEvent(e) case RecoveryCompleted ⇒ println("==> Recovery completed") case e ⇒ println("Dropping event: " + e.getClass.getName) } def handleEvent(event: NameRegisteredEvent): Unit = { this.name = event.name this.surname = event.surname log.debug(s"[NameRegistered]: Person $persistenceId => name: $name, surname: $surname") } def handleEvent(event: NameChangedEvent): Unit = { this.name = event.name log.debug(s"[NameChanged]: Person $persistenceId => name: $name, surname: $surname") } def handleEvent(event: SurnameChangedEvent): Unit = { this.surname = event.surname log.debug(s"[SurnameChanged]: Person $persistenceId => name: $name, surname: $surname") } override def receiveCommand: Receive = LoggingReceive { case RegisterNameCommand(name, surname) ⇒ persist(NameRegisteredEvent(name, surname)) { e ⇒ handleEvent(e) sender() ! akka.actor.Status.Success("") } case ChangeNameCommand(newName) ⇒ persist(NameChangedEvent(newName)) { e ⇒ handleEvent(e) sender() ! akka.actor.Status.Success("") } case ChangeSurnameCommand(newSurname) ⇒ persist(SurnameChangedEvent(newSurname)) { e ⇒ handleEvent(e) sender() ! akka.actor.Status.Success("") } } override def postStop(): Unit = { log.debug(s"Stopped $persistenceId") super.postStop() } }
Example 15
Source File: AbstractEmbeddedPersistentActorSpec.scala From akka-persistence-couchbase with Apache License 2.0 | 5 votes |
package com.lightbend.lagom.scaladsl.persistence.testkit import akka.actor.{ ActorRef, Props, actorRef2Scala } import akka.persistence.PersistentActor import com.lightbend.lagom.persistence.ActorSystemSpec import scala.concurrent.duration._ object AbstractEmbeddedPersistentActorSpec { final case class Cmd(data: String) final case class Evt(data: String) case object Get final case class State(data: Vector[String] = Vector.empty) { def apply(evt: Evt): State = { copy(data :+ evt.data) } } def props(persistenceId: String): Props = Props(new Persistent(persistenceId)) class Persistent(override val persistenceId: String) extends PersistentActor { var state = State() override def receiveRecover = { case evt: Evt => state = state(evt) } override def receiveCommand = { case Cmd(data) => persist(Evt(data.toUpperCase)) { evt => state = state(evt) } case Get => sender() ! state } } } trait AbstractEmbeddedPersistentActorSpec { spec: ActorSystemSpec => import AbstractEmbeddedPersistentActorSpec._ "A persistent actor" must { "store events in the embedded journal" in within(15.seconds) { val p = system.actorOf(props("p1")) println(implicitly[ActorRef]) p ! Get expectMsg(State()) p ! Cmd("a") p ! Cmd("b") p ! Cmd("c") p ! Get expectMsg(State(Vector("A", "B", "C"))) // start another with same persistenceId should recover state val p2 = system.actorOf(props("p1")) p2 ! Get expectMsg(State(Vector("A", "B", "C"))) } } }
Example 16
Source File: AbstractEmbeddedPersistentActorSpec.scala From akka-persistence-couchbase with Apache License 2.0 | 5 votes |
package com.lightbend.lagom.javadsl.persistence.testkit import akka.actor.{ ActorRef, Props, actorRef2Scala } import akka.persistence.PersistentActor import com.lightbend.lagom.persistence.ActorSystemSpec import scala.concurrent.duration._ object AbstractEmbeddedPersistentActorSpec { final case class Cmd(data: String) final case class Evt(data: String) case object Get final case class State(data: Vector[String] = Vector.empty) { def apply(evt: Evt): State = { copy(data :+ evt.data) } } def props(persistenceId: String): Props = Props(new Persistent(persistenceId)) class Persistent(override val persistenceId: String) extends PersistentActor { var state = State() override def receiveRecover = { case evt: Evt => state = state(evt) } override def receiveCommand = { case Cmd(data) => persist(Evt(data.toUpperCase)) { evt => state = state(evt) } case Get => sender() ! state } } } trait AbstractEmbeddedPersistentActorSpec { spec: ActorSystemSpec => import AbstractEmbeddedPersistentActorSpec._ "A persistent actor" must { "store events in the embedded journal" in within(15.seconds) { val p = system.actorOf(props("p1")) println(implicitly[ActorRef]) p ! Get expectMsg(State()) p ! Cmd("a") p ! Cmd("b") p ! Cmd("c") p ! Get expectMsg(State(Vector("A", "B", "C"))) // start another with same persistenceId should recover state val p2 = system.actorOf(props("p1")) p2 ! Get expectMsg(State(Vector("A", "B", "C"))) } } }
Example 17
Source File: AwaitPersistenceInit.scala From lagom with Apache License 2.0 | 5 votes |
package com.lightbend.lagom.internal.persistence.testkit import java.util.concurrent.TimeUnit import akka.actor.ActorSystem import akka.actor.Props import akka.persistence.PersistentActor import akka.testkit.TestProbe import org.slf4j.LoggerFactory import scala.concurrent.duration._ // A copy of akka.persistence.cassandra.CassandraLifecycle's awaitPersistenceInit. private[lagom] object AwaitPersistenceInit { def awaitPersistenceInit(system: ActorSystem): Unit = { val probe = TestProbe()(system) val log = LoggerFactory.getLogger(getClass) val t0 = System.nanoTime() var n = 0 probe.within(45.seconds) { probe.awaitAssert { n += 1 system.actorOf(Props[AwaitPersistenceInit], "persistenceInit" + n).tell("hello", probe.ref) probe.expectMsg(15.seconds, "hello") log.debug( "awaitPersistenceInit took {} ms {}", TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - t0), system.name ) } } } } private[lagom] class AwaitPersistenceInit extends PersistentActor { def persistenceId: String = self.path.name def receiveRecover: Receive = { case _ => } def receiveCommand: Receive = { case msg => persist(msg) { _ => sender() ! msg context.stop(self) } } }
Example 18
Source File: AbstractEmbeddedPersistentActorSpec.scala From lagom with Apache License 2.0 | 5 votes |
package com.lightbend.lagom.scaladsl.persistence.testkit import akka.actor.ActorRef import akka.actor.ActorSystem import akka.actor.Props import akka.actor.actorRef2Scala import akka.persistence.PersistentActor import akka.testkit.ImplicitSender import akka.testkit.TestKitBase import com.lightbend.lagom.persistence.ActorSystemSpec import com.lightbend.lagom.persistence.PersistenceSpec import scala.collection.immutable import com.lightbend.lagom.scaladsl.playjson.JsonSerializerRegistry import com.lightbend.lagom.scaladsl.playjson.JsonSerializer import scala.concurrent.duration._ object AbstractEmbeddedPersistentActorSpec { final case class Cmd(data: String) final case class Evt(data: String) case object Get final case class State(data: Vector[String] = Vector.empty) { def apply(evt: Evt): State = { copy(data :+ evt.data) } } def props(persistenceId: String): Props = Props(new Persistent(persistenceId)) class Persistent(override val persistenceId: String) extends PersistentActor { var state = State() override def receiveRecover = { case evt: Evt => state = state(evt) } override def receiveCommand = { case Cmd(data) => persist(Evt(data.toUpperCase)) { evt => state = state(evt) } case Get => sender() ! state } } object EmbeddedPersistentActorSerializers extends JsonSerializerRegistry { override def serializers: immutable.Seq[JsonSerializer[_]] = { import play.api.libs.json._ import JsonSerializer.emptySingletonFormat Vector( JsonSerializer(Json.format[Cmd]), JsonSerializer(Json.format[Evt]), JsonSerializer(emptySingletonFormat(Get)), JsonSerializer(Json.format[State]) ) } } } trait AbstractEmbeddedPersistentActorSpec { spec: ActorSystemSpec => import AbstractEmbeddedPersistentActorSpec._ "A persistent actor" must { "store events in the embedded journal" in within(15.seconds) { val p = system.actorOf(props("p1")) println(implicitly[ActorRef]) p ! Get expectMsg(State()) p ! Cmd("a") p ! Cmd("b") p ! Cmd("c") p ! Get expectMsg(State(Vector("A", "B", "C"))) // start another with same persistenceId should recover state val p2 = system.actorOf(props("p1")) p2 ! Get expectMsg(State(Vector("A", "B", "C"))) } } }
Example 19
Source File: AbstractEmbeddedPersistentActorSpec.scala From lagom with Apache License 2.0 | 5 votes |
package com.lightbend.lagom.javadsl.persistence.testkit import akka.actor.ActorRef import akka.actor.Props import akka.actor.actorRef2Scala import akka.persistence.PersistentActor import com.lightbend.lagom.persistence.ActorSystemSpec import com.lightbend.lagom.serialization.Jsonable import scala.concurrent.duration._ object AbstractEmbeddedPersistentActorSpec { // All commands and events extending Jsonable so that the // tests will use Jackson serialization instead of Java's. case object Get extends Jsonable final case class Cmd(data: String) extends Jsonable final case class Evt(data: String) extends Jsonable final case class State(data: Vector[String] = Vector.empty) extends Jsonable { def apply(evt: Evt): State = { copy(data :+ evt.data) } } def props(persistenceId: String): Props = Props(new Persistent(persistenceId)) class Persistent(override val persistenceId: String) extends PersistentActor { var state = State() override def receiveRecover = { case evt: Evt => state = state(evt) } override def receiveCommand = { case Cmd(data) => persist(Evt(data.toUpperCase)) { evt => state = state(evt) } case Get => sender() ! state } } } trait AbstractEmbeddedPersistentActorSpec { spec: ActorSystemSpec => import AbstractEmbeddedPersistentActorSpec._ "A persistent actor" must { "store events in the embedded journal" in within(15.seconds) { val p = system.actorOf(props("p1")) println(implicitly[ActorRef]) p ! Get expectMsg(State()) p ! Cmd("a") p ! Cmd("b") p ! Cmd("c") p ! Get expectMsg(State(Vector("A", "B", "C"))) // start another with same persistenceId should recover state val p2 = system.actorOf(props("p1")) p2 ! Get expectMsg(State(Vector("A", "B", "C"))) } } }
Example 20
Source File: StockPersistenceActor.scala From Akka-Cookbook with MIT License | 5 votes |
package com.packt.chapter6 import akka.actor.{ActorLogging, Props} import akka.persistence.{PersistentActor, RecoveryCompleted} object StockPersistenceActor { def props(stockId: String) = Props(new StockPersistenceActor(stockId)) } class StockPersistenceActor(stockId: String) extends PersistentActor with ActorLogging { override val persistenceId = stockId var state = StockHistory() def updateState(event: ValueAppended) = state = state.update(event) val receiveRecover: Receive = { case evt: ValueAppended => updateState(evt) case RecoveryCompleted => log.info(s"Recovery completed. Current state: $state") } val receiveCommand: Receive = { case ValueUpdate(value) => persist(ValueAppended(StockValue(value)))(updateState) case "print" => log.info(s"Current state: $state") } override def postStop() = log.info(s"Stopping [${self.path}]") }
Example 21
Source File: FriendActor.scala From Akka-Cookbook with MIT License | 5 votes |
package com.packt.chapter6 import akka.actor.{ActorLogging, Props} import akka.persistence.{PersistentActor, Recovery, RecoveryCompleted, SnapshotOffer} object FriendActor { def props(friendId: String, recoveryStrategy: Recovery) = Props(new FriendActor(friendId, recoveryStrategy)) } class FriendActor(friendId: String, r: Recovery) extends PersistentActor with ActorLogging { override val persistenceId = friendId override val recovery = r var state = FriendState() def updateState(event: FriendEvent) = state = state.update(event) val receiveRecover: Receive = { case evt: FriendEvent => log.info(s"Replaying event: $evt") updateState(evt) case SnapshotOffer(_, recoveredState : FriendState) => log.info(s"Snapshot offered: $recoveredState") state = recoveredState case RecoveryCompleted => log.info(s"Recovery completed. Current state: $state") } val receiveCommand: Receive = { case AddFriend(friend) => persist(FriendAdded(friend))(updateState) case RemoveFriend(friend) => persist(FriendRemoved(friend))(updateState) case "snap" => saveSnapshot(state) case "print" => log.info(s"Current state: $state") } }
Example 22
Source File: SamplePersistenceActor.scala From Akka-Cookbook with MIT License | 5 votes |
package com.packt.chapter6 import akka.persistence.{PersistentActor, SnapshotOffer} class SamplePersistenceActor extends PersistentActor { override val persistenceId = "unique-id-1" var state = ActiveUsers() def updateState(event: Event) = state = state.update(event) val receiveRecover: Receive = { case evt: Event => updateState(evt) case SnapshotOffer(_, snapshot: ActiveUsers) => state = snapshot } val receiveCommand: Receive = { case UserUpdate(userId, Add) => persist(AddUserEvent(userId))(updateState) case UserUpdate(userId, Remove) => persist(RemoveUserEvent(userId))(updateState) case "snap" => saveSnapshot(state) case "print" => println(state) case ShutdownPersistentActor => context.stop(self) } override def postStop() = println(s"Stopping [${self.path}]") }
Example 23
Source File: InventoryActor.scala From Learn-Scala-Programming with MIT License | 5 votes |
package ch14 import akka.actor.{Actor, ActorLogging, Props} import akka.persistence.{PersistentActor, RecoveryCompleted, SnapshotOffer} import ch14.Commands.{GetArticle, GetInventory} object InventoryActor { def props: Props = Props[InventoryActor] val persistenceId = "Inventory" } class InventoryActor extends PersistentActor with Actor with ActorLogging { override def persistenceId: String = InventoryActor.persistenceId private var inventory: Inventory = Inventory(Map.empty) override def receiveRecover: Receive = { case event: Event => inventory = inventory.update(event) case SnapshotOffer(_, snapshot: Inventory) => inventory = snapshot case RecoveryCompleted => saveSnapshot(inventory) } override def receiveCommand: Receive = { case GetInventory => sender() ! inventory case GetArticle(name) => sender() ! Inventory(inventory.state.filter(_._1 == name)) case cmd: Command => inventory.canUpdate(cmd) match { case None => sender() ! None case Some(event) => persistAsync(event) { ev => inventory = inventory.update(ev) sender() ! Some(ev) } } } }
Example 24
Source File: PersistenceExample.scala From typed-actors with Apache License 2.0 | 5 votes |
package org.example import akka.actor.{ ActorLogging, ActorSystem } import akka.persistence.{ SnapshotOffer, PersistentActor } import de.knutwalker.akka.typed._ import scala.concurrent.duration._ object PersistenceExample extends App { case class Ping(replyTo: ActorRef[Pong]) case class Pong(replyTo: ActorRef[Ping]) case class Evt(data: String) case class ExampleState(events: List[String] = Nil) { def updated(evt: Evt): ExampleState = copy(evt.data :: events) def size: Int = events.length override def toString: String = events.reverse.toString } class TypedPersistentPingActor extends TypedActor with PersistentActor with ActorLogging { type Message = Ping def persistenceId: String = "typed-persistent-ping-id" var state = ExampleState() def updateState(event: Evt): Unit = state = state.updated(event) def numEvents = state.size val receiveRecover: Receive = { case evt: Evt => updateState(evt) case SnapshotOffer(_, snapshot: ExampleState) => state = snapshot } val typedReceive: TypedReceive = { case Ping(replyTo) ⇒ persist(Evt(s"$numEvents"))(updateState) persist(Evt(s"${numEvents + 1}")) { event => updateState(event) replyTo ! Pong(typedSelf) } } val receiveCommand: Receive = untypedFromTyped(typedReceive).orElse { case "snap" => saveSnapshot(state) case "print" => println(state) } override def receive: Receive = receiveCommand override def postStop(): Unit = { log.info(s"state = $state") super.postStop() } } class TypedPongActor extends TypedActor.Of[Pong] with ActorLogging { private[this] var count = 0 val typedReceive: TypedReceive = { case Pong(replyTo) ⇒ count += 1 replyTo ! Ping(typedSelf) } override def postStop(): Unit = { log.info(s"pings: $count") super.postStop() } override def preStart(): Unit = { import context.dispatcher super.preStart() context.system.scheduler.scheduleOnce(600.millis)(Shutdown(system)) () } } implicit val system = ActorSystem() val ping = ActorOf(PropsFor[TypedPersistentPingActor], "ping") val pong = ActorOf(PropsFor[TypedPongActor], "pong") ping ! Ping(pong) }
Example 25
Source File: HttpRequestRecorder.scala From rokku with Apache License 2.0 | 5 votes |
package com.ing.wbaa.rokku.proxy.persistence import akka.http.scaladsl.model.{ HttpRequest, RemoteAddress } import akka.persistence.{ PersistentActor, RecoveryCompleted, SaveSnapshotFailure, SaveSnapshotSuccess, SnapshotOffer } import com.ing.wbaa.rokku.proxy.data.User import com.ing.wbaa.rokku.proxy.persistence.HttpRequestRecorder.{ ExecutedRequestCmd, LatestRequests, LatestRequestsResult, Shutdown } import com.typesafe.config.ConfigFactory import com.typesafe.scalalogging.LazyLogging sealed trait Evt case class ExecutedRequestEvt(httpRequest: HttpRequest, userSTS: User, clientIPAddress: RemoteAddress) extends Evt object HttpRequestRecorder { case class ExecutedRequestCmd(httpRequest: HttpRequest, userSTS: User, clientIPAddress: RemoteAddress) case class LatestRequests(amount: Int) case class LatestRequestsResult(requests: List[ExecutedRequestEvt]) case object Shutdown } case class CurrentRequestsState(requests: List[ExecutedRequestEvt] = Nil) { def add(e: ExecutedRequestEvt): CurrentRequestsState = { if (size > 200) { copy(requests.reverse.drop(100)) } copy(e :: requests) } def getRequests(n: Int = 100): List[ExecutedRequestEvt] = this.requests.reverse.take(n) def size: Int = requests.size } class HttpRequestRecorder extends PersistentActor with LazyLogging { var state: CurrentRequestsState = CurrentRequestsState() val snapShotInterval = ConfigFactory.load().getInt("rokku.requestPersistence.snapshotInterval") private def updateState(e: ExecutedRequestEvt) = state = state.add(e) override def persistenceId: String = ConfigFactory.load().getString("rokku.requestPersistence.persistenceId") override def receiveRecover: Receive = { case e: ExecutedRequestEvt => { logger.debug("No snapshot, replying event sequence {}", lastSequenceNr) updateState(e) } case SnapshotOffer(metadata, snapshot: CurrentRequestsState) => { logger.debug("Received snapshot offer, timestamp: {} for persistenceId: {} ", metadata.timestamp, metadata.persistenceId) state = snapshot } case RecoveryCompleted => logger.debug("Actor State recovery completed!") } override def receiveCommand: Receive = { case SaveSnapshotSuccess(metadata) => logger.debug("Snapshot saved successfully, seq: {}", metadata.sequenceNr) case SaveSnapshotFailure(_, reason) => logger.error("Failed to save snapshot, reason: {}", reason.getMessage) case rc: ExecutedRequestCmd => persist(ExecutedRequestEvt(rc.httpRequest, rc.userSTS, rc.clientIPAddress)) { e => logger.debug("Received event for event sourcing {} from user: {}", e.httpRequest.uri, e.userSTS.userName) updateState(e) if (lastSequenceNr % snapShotInterval == 0 && lastSequenceNr != 0) saveSnapshot(state) } case get: LatestRequests => sender() ! LatestRequestsResult(state.getRequests(get.amount)) case Shutdown => context.stop(self) case _ => logger.debug(s"{} Got unsupported message type", HttpRequestRecorder.getClass.getName) } }
Example 26
Source File: Music.scala From akka-serialization-test with Apache License 2.0 | 5 votes |
package com.github.dnvriend.domain import java.time.Duration import akka.actor.ActorLogging import akka.event.LoggingReceive import akka.persistence.PersistentActor object Music { type Title = String type Year = Int final case class Song(title: Title, duration: Duration) sealed trait AlbumEvent final case class TitleChanged(title: Title) extends AlbumEvent final case class YearChanged(year: Year) extends AlbumEvent final case class SongAdded(song: Song) extends AlbumEvent final case class SongRemoved(song: Song) extends AlbumEvent sealed trait AlbumCommand final case class ChangeAlbumTitle(title: Title) extends AlbumCommand final case class ChangeAlbumYear(year: Year) extends AlbumCommand final case class AddSong(song: Song) extends AlbumCommand final case class RemoveSong(song: Song) extends AlbumCommand } class Album(val persistenceId: String) extends PersistentActor with ActorLogging { import Music._ var title: Title = _ var year: Year = _ var songs: Set[Song] = Set[Song]() override def receiveRecover: Receive = LoggingReceive { case e: TitleChanged ⇒ handleEvent(e) case e: YearChanged ⇒ handleEvent(e) case e: SongAdded ⇒ handleEvent(e) case e: SongRemoved ⇒ handleEvent(e) } def handleEvent(event: TitleChanged): Unit = { this.title = event.title log.debug(s"[TitleChanged]: Album $persistenceId => title: $title, year: $year songs: $songs") } def handleEvent(event: YearChanged): Unit = { this.year = event.year log.debug(s"[YearChanged]: Album $persistenceId => title: $title, year: $year songs: $songs") } def handleEvent(event: SongAdded): Unit = { this.songs = this.songs + event.song log.debug(s"[SongAdded]: Album $persistenceId => title: $title, year: $year songs: $songs") } def handleEvent(event: SongRemoved): Unit = { this.songs = this.songs - event.song log.debug(s"[SongRemoved]: Album $persistenceId => title: $title, year: $year songs: $songs") } override def receiveCommand: Receive = LoggingReceive { case ChangeAlbumTitle(newTitle) ⇒ persistAll(List(TitleChanged(newTitle))) { e ⇒ handleEvent(e) sender() ! akka.actor.Status.Success("") } case ChangeAlbumYear(newYear) ⇒ persistAll(List(YearChanged(newYear))) { e ⇒ handleEvent(e) sender() ! akka.actor.Status.Success("") } case AddSong(newSong) ⇒ persistAll(List(SongAdded(newSong))) { e ⇒ handleEvent(e) sender() ! akka.actor.Status.Success("") } case RemoveSong(oldSong) ⇒ persistAll(List(SongRemoved(oldSong))) { e ⇒ handleEvent(e) sender() ! akka.actor.Status.Success("") } } override def postStop(): Unit = { log.debug(s"Stopped $persistenceId") super.postStop() } }