Persistence

Akka works on memory. However, it is possible to use persistence. Persistence is still kind of experimental in Akka. However, it is stable. For production, you can use advanced persistence plugins, such as Apache Cassandra. For the sake of development and education, we will use Google leveldb in our file system. Akka has multiple persistence options, such as views and persistent Actors.

Let's take a look at a persistent actor using the Google leveldb and file system:

import akka.actor._ import akka.persistence._ import scala.concurrent.duration._ class PersistenceActor extends PersistentActor{ override def persistenceId = "sample-id-1" var state:String = "myState" var count = 0

def receiveCommand: Receive = { case payload: String =>

println(s"PersistenceActor received ${payload} (nr =

${count})")

persist(payload + count) { evt => count += 1

}

}

def receiveRecover: Receive = { case _: String => println("recover...") count += 1

}

}

object PersistentViewsApp extends App { val system = ActorSystem("SimpleActorSystem") val persistentActor =

system.actorOf(Props(classOf[PersistenceActor])) import system.dispatcher

system.scheduler.schedule(Duration.Zero, 2.seconds, persistentActor, "scheduled")

}

Executing the $ sbt run command will give you the following output:

If you run this code with $ sbt run, and stop and run again, you will see the data is being stored and recovered every time you stop and start again.

As you can see, your Actor needs to extend PersistentActor in order to have persistence support. You will also need to provide a persistenceID.

Here, you will need to implement two receive functions. One is for commands (also known as messages), and the other one is for recovery. The command's receive loop will be activated when this Actor receives messages, while the recover one will be activated when the Actor boots up and will read the persistent data from the database.

So, this Actor here has a counter to count each message it receives, and prints every message it gets on the console. That's it; as you can see, it is pretty simple. In order to use this functionality, you will also need to configure your application.conf.

Your application.conf file should look something like this:

akka {

system = "SimpleActorSystem" remote {

log-remote-lifecycle-events = off netty.tcp {

hostname = "127.0.0.1" port = 0

}

}

}

akka.cluster.metrics.enabled=off akka.persistence.journal.plugin =

"akka.persistence.journal.leveldb" akka.persistence.snapshot-store.plugin = "akka.persistence.snapshot-store.local"

akka.persistence.journal.leveldb.dir = "target/persistence/journal" akka.persistence.snapshot-store.local.dir = "target/persistence/snapshots"

# DO NOT USE THIS IN PRODUCTION !!!

# See also https://github.com/typesafehub/activator/issues/287 akka.persistence.journal.leveldb.native = false

So, here we are defining a simple Akka system (local mode), and we are configuring the persistence for Google leveldb. As you can see, we will need to provide a path for persistence, and this path must exist on the OS.

As we are using an additional functionality, we will also need to change build.sbt in order to import all jars that we will need in the sense of Akka, persistence, and leveldb.

Your build.sbt file should look something like this:

// rest of the build.sbt file ... val akkaVersion = "2.4.9"

libraryDependencies += "com.typesafe.akka" %% "akka-actor" % akkaVersion

libraryDependencies += "com.typesafe.akka" %% "akka-kernel" % akkaVersion

libraryDependencies += "com.typesafe.akka" %% "akka-remote" % akkaVersion

libraryDependencies += "com.typesafe.akka" %% "akka-cluster" % akkaVersion libraryDependencies += "com.typesafe.akka" %% "akka-contrib" % akkaVersion

libraryDependencies += "com.typesafe.akka" %% "akka-persistence" % akkaVersion

libraryDependencies += "org.iq80.leveldb" % "leveldb" % "0.7" libraryDependencies += "org.iq80.leveldb" % "leveldb-api" % "0.7" libraryDependencies += "org.fusesource.leveldbjni" % "leveldbjni" % "1.8"

libraryDependencies += "org.fusesource.leveldbjni" % "leveldbjni- linux64" % "1.8"

libraryDependencies += "org.fusesource" % "sigar" % "1.6.4" libraryDependencies += "org.scalatest" % "scalatest_2.11" % "2.2.6"

That's it. That's all we need to persist the Actor's state.

Akka has way more functionalities. For more, check out the default documentation at

http://doc.akka.io/docs/akka/2.4/scala.html?_ga=1.12480951.24709

2618.1472108365.

 
Source