per #15423 Remove deprecated features from akka-persistence
* remove channels * remove View * remove Processor * collapse the complicated internal state management that was spread out between Processor, Eventsourced and Recovery * remove Recovery trait, this caused some duplication between Eventsourced and PersistentView, but but the enhanced PersistentView will not be based on recovery infrastructure, and therefore PersistentView code will be replaced anyway * remove PersistentBatch * remove LoopMessage * remove deleteMessages of individual messages * remove Persistent, PersistentRepr and PersistentImpl are kept * remove processorId * update doc sample code * note in migration guide about persistenceId * rename Resequencable to PersistentEnvelope
This commit is contained in:
parent
86a5b3d9d7
commit
c566d5a106
84 changed files with 2162 additions and 9560 deletions
|
|
@ -16,90 +16,45 @@ object PerformanceSpec {
|
|||
// accurate throughput measurements
|
||||
val config =
|
||||
"""
|
||||
akka.persistence.performance.cycles.warmup = 300
|
||||
akka.persistence.performance.cycles.load = 1000
|
||||
"""
|
||||
|
||||
case object StartMeasure
|
||||
case object StopMeasure
|
||||
final case class FailAt(sequenceNr: Long)
|
||||
|
||||
trait Measure extends { this: Actor ⇒
|
||||
val NanoToSecond = 1000.0 * 1000 * 1000
|
||||
class Measure(numberOfMessages: Int) {
|
||||
private val NanoToSecond = 1000.0 * 1000 * 1000
|
||||
|
||||
var startTime: Long = 0L
|
||||
var stopTime: Long = 0L
|
||||
|
||||
var startSequenceNr = 0L
|
||||
var stopSequenceNr = 0L
|
||||
private var startTime: Long = 0L
|
||||
private var stopTime: Long = 0L
|
||||
|
||||
def startMeasure(): Unit = {
|
||||
startSequenceNr = lastSequenceNr
|
||||
startTime = System.nanoTime
|
||||
}
|
||||
|
||||
def stopMeasure(): Unit = {
|
||||
stopSequenceNr = lastSequenceNr
|
||||
def stopMeasure(): Double = {
|
||||
stopTime = System.nanoTime
|
||||
sender() ! (NanoToSecond * (stopSequenceNr - startSequenceNr) / (stopTime - startTime))
|
||||
}
|
||||
|
||||
def lastSequenceNr: Long
|
||||
}
|
||||
|
||||
class PerformanceTestDestination extends Actor with Measure {
|
||||
var lastSequenceNr = 0L
|
||||
|
||||
val confirm: PartialFunction[Any, Any] = {
|
||||
case cp @ ConfirmablePersistent(payload, sequenceNr, _) ⇒
|
||||
lastSequenceNr = sequenceNr
|
||||
cp.confirm()
|
||||
payload
|
||||
}
|
||||
|
||||
def receive = confirm andThen {
|
||||
case StartMeasure ⇒ startMeasure()
|
||||
case StopMeasure ⇒ stopMeasure()
|
||||
case m ⇒ if (lastSequenceNr % 1000 == 0) print(".")
|
||||
(NanoToSecond * numberOfMessages / (stopTime - startTime))
|
||||
}
|
||||
}
|
||||
|
||||
abstract class PerformanceTestProcessor(name: String) extends NamedProcessor(name) with Measure {
|
||||
abstract class PerformanceTestPersistentActor(name: String) extends NamedPersistentActor(name) {
|
||||
var failAt: Long = -1
|
||||
|
||||
val controlBehavior: Receive = {
|
||||
case StartMeasure ⇒ startMeasure()
|
||||
case StopMeasure ⇒ stopMeasure()
|
||||
case FailAt(sequenceNr) ⇒ failAt = sequenceNr
|
||||
}
|
||||
|
||||
override def postRestart(reason: Throwable) {
|
||||
super.postRestart(reason)
|
||||
receive(StartMeasure)
|
||||
}
|
||||
}
|
||||
|
||||
class CommandsourcedTestProcessor(name: String) extends PerformanceTestProcessor(name) {
|
||||
def receive = controlBehavior orElse {
|
||||
case p: Persistent ⇒
|
||||
if (lastSequenceNr % 1000 == 0) if (recoveryRunning) print("r") else print(".")
|
||||
if (lastSequenceNr == failAt) throw new TestException("boom")
|
||||
}
|
||||
}
|
||||
|
||||
class CommandsourcedTestPersistentActor(name: String) extends PerformanceTestProcessor(name) with PersistentActor {
|
||||
|
||||
override val controlBehavior: Receive = {
|
||||
case StartMeasure ⇒ startMeasure()
|
||||
case StopMeasure ⇒ defer(StopMeasure)(_ ⇒ stopMeasure())
|
||||
case FailAt(sequenceNr) ⇒ failAt = sequenceNr
|
||||
}
|
||||
|
||||
val receiveRecover: Receive = {
|
||||
override val receiveRecover: Receive = {
|
||||
case _ ⇒ if (lastSequenceNr % 1000 == 0) print("r")
|
||||
}
|
||||
|
||||
val receiveCommand: Receive = controlBehavior orElse {
|
||||
val controlBehavior: Receive = {
|
||||
case StopMeasure ⇒ defer(StopMeasure)(_ ⇒ sender() ! StopMeasure)
|
||||
case FailAt(sequenceNr) ⇒ failAt = sequenceNr
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CommandsourcedTestPersistentActor(name: String) extends PerformanceTestPersistentActor(name) {
|
||||
|
||||
override val receiveCommand: Receive = controlBehavior orElse {
|
||||
case cmd ⇒ persistAsync(cmd) { _ ⇒
|
||||
if (lastSequenceNr % 1000 == 0) print(".")
|
||||
if (lastSequenceNr == failAt) throw new TestException("boom")
|
||||
|
|
@ -107,12 +62,9 @@ object PerformanceSpec {
|
|||
}
|
||||
}
|
||||
|
||||
class EventsourcedTestProcessor(name: String) extends PerformanceTestProcessor(name) with PersistentActor {
|
||||
val receiveRecover: Receive = {
|
||||
case _ ⇒ if (lastSequenceNr % 1000 == 0) print("r")
|
||||
}
|
||||
class EventsourcedTestPersistentActor(name: String) extends PerformanceTestPersistentActor(name) {
|
||||
|
||||
val receiveCommand: Receive = controlBehavior orElse {
|
||||
override val receiveCommand: Receive = controlBehavior orElse {
|
||||
case cmd ⇒ persist(cmd) { _ ⇒
|
||||
if (lastSequenceNr % 1000 == 0) print(".")
|
||||
if (lastSequenceNr == failAt) throw new TestException("boom")
|
||||
|
|
@ -120,11 +72,27 @@ object PerformanceSpec {
|
|||
}
|
||||
}
|
||||
|
||||
class StashingEventsourcedTestProcessor(name: String) extends PerformanceTestProcessor(name) with PersistentActor {
|
||||
val receiveRecover: Receive = {
|
||||
case _ ⇒ if (lastSequenceNr % 1000 == 0) print("r")
|
||||
/**
|
||||
* `persist` every 10th message, otherwise `persistAsync`
|
||||
*/
|
||||
class MixedTestPersistentActor(name: String) extends PerformanceTestPersistentActor(name) {
|
||||
var counter = 0
|
||||
|
||||
val handler: Any ⇒ Unit = { evt ⇒
|
||||
if (lastSequenceNr % 1000 == 0) print(".")
|
||||
if (lastSequenceNr == failAt) throw new TestException("boom")
|
||||
}
|
||||
|
||||
val receiveCommand: Receive = controlBehavior orElse {
|
||||
case cmd ⇒
|
||||
counter += 1
|
||||
if (counter % 10 == 0) persist(cmd)(handler)
|
||||
else persistAsync(cmd)(handler)
|
||||
}
|
||||
}
|
||||
|
||||
class StashingEventsourcedTestPersistentActor(name: String) extends PerformanceTestPersistentActor(name) {
|
||||
|
||||
val printProgress: PartialFunction[Any, Any] = {
|
||||
case m ⇒ if (lastSequenceNr % 1000 == 0) print("."); m
|
||||
}
|
||||
|
|
@ -146,82 +114,50 @@ object PerformanceSpec {
|
|||
class PerformanceSpec extends AkkaSpec(PersistenceSpec.config("leveldb", "PerformanceSpec", serialization = "off").withFallback(ConfigFactory.parseString(PerformanceSpec.config))) with PersistenceSpec with ImplicitSender {
|
||||
import PerformanceSpec._
|
||||
|
||||
val warmupCycles = system.settings.config.getInt("akka.persistence.performance.cycles.warmup")
|
||||
val loadCycles = system.settings.config.getInt("akka.persistence.performance.cycles.load")
|
||||
|
||||
def stressCommandsourcedProcessor(failAt: Option[Long]): Unit = {
|
||||
val processor = namedProcessor[CommandsourcedTestProcessor]
|
||||
failAt foreach { processor ! FailAt(_) }
|
||||
1 to warmupCycles foreach { i ⇒ processor ! Persistent(s"msg${i}") }
|
||||
processor ! StartMeasure
|
||||
1 to loadCycles foreach { i ⇒ processor ! Persistent(s"msg${i}") }
|
||||
processor ! StopMeasure
|
||||
expectMsgPF(100 seconds) {
|
||||
case throughput: Double ⇒ println(f"\nthroughput = $throughput%.2f persistent processor commands per second")
|
||||
}
|
||||
def stressPersistentActor(persistentActor: ActorRef, failAt: Option[Long], description: String): Unit = {
|
||||
failAt foreach { persistentActor ! FailAt(_) }
|
||||
val m = new Measure(loadCycles)
|
||||
m.startMeasure()
|
||||
1 to loadCycles foreach { i ⇒ persistentActor ! s"msg${i}" }
|
||||
persistentActor ! StopMeasure
|
||||
expectMsg(100.seconds, StopMeasure)
|
||||
println(f"\nthroughput = ${m.stopMeasure()}%.2f $description per second")
|
||||
}
|
||||
|
||||
def stressCommandsourcedPersistentActor(failAt: Option[Long]): Unit = {
|
||||
val processor = namedProcessor[CommandsourcedTestPersistentActor]
|
||||
failAt foreach { processor ! FailAt(_) }
|
||||
1 to warmupCycles foreach { i ⇒ processor ! s"msg${i}" }
|
||||
processor ! StartMeasure
|
||||
1 to loadCycles foreach { i ⇒ processor ! s"msg${i}" }
|
||||
processor ! StopMeasure
|
||||
expectMsgPF(100 seconds) {
|
||||
case throughput: Double ⇒ println(f"\nthroughput = $throughput%.2f persistent actor commands per second")
|
||||
}
|
||||
val persistentActor = namedPersistentActor[CommandsourcedTestPersistentActor]
|
||||
stressPersistentActor(persistentActor, failAt, "persistent commands")
|
||||
}
|
||||
|
||||
def stressPersistentActor(failAt: Option[Long]): Unit = {
|
||||
val processor = namedProcessor[EventsourcedTestProcessor]
|
||||
failAt foreach { processor ! FailAt(_) }
|
||||
1 to warmupCycles foreach { i ⇒ processor ! s"msg${i}" }
|
||||
processor ! StartMeasure
|
||||
1 to loadCycles foreach { i ⇒ processor ! s"msg${i}" }
|
||||
processor ! StopMeasure
|
||||
expectMsgPF(100 seconds) {
|
||||
case throughput: Double ⇒ println(f"\nthroughput = $throughput%.2f persistent events per second")
|
||||
}
|
||||
def stressEventSourcedPersistentActor(failAt: Option[Long]): Unit = {
|
||||
val persistentActor = namedPersistentActor[EventsourcedTestPersistentActor]
|
||||
stressPersistentActor(persistentActor, failAt, "persistent events")
|
||||
}
|
||||
|
||||
def stressMixedPersistentActor(failAt: Option[Long]): Unit = {
|
||||
val persistentActor = namedPersistentActor[MixedTestPersistentActor]
|
||||
stressPersistentActor(persistentActor, failAt, "persistent events & commands")
|
||||
}
|
||||
|
||||
def stressStashingPersistentActor(): Unit = {
|
||||
val processor = namedProcessor[StashingEventsourcedTestProcessor]
|
||||
1 to warmupCycles foreach { i ⇒ processor ! "b" }
|
||||
processor ! StartMeasure
|
||||
val persistentActor = namedPersistentActor[StashingEventsourcedTestPersistentActor]
|
||||
val m = new Measure(loadCycles)
|
||||
m.startMeasure()
|
||||
val cmds = 1 to (loadCycles / 3) flatMap (_ ⇒ List("a", "b", "c"))
|
||||
processor ! StartMeasure
|
||||
cmds foreach (processor ! _)
|
||||
processor ! StopMeasure
|
||||
expectMsgPF(100 seconds) {
|
||||
case throughput: Double ⇒ println(f"\nthroughput = $throughput%.2f persistent events per second")
|
||||
}
|
||||
cmds foreach (persistentActor ! _)
|
||||
persistentActor ! StopMeasure
|
||||
expectMsg(100.seconds, StopMeasure)
|
||||
println(f"\nthroughput = ${m.stopMeasure()}%.2f persistent events per second")
|
||||
}
|
||||
|
||||
def stressPersistentChannel(): Unit = {
|
||||
val channel = system.actorOf(PersistentChannel.props())
|
||||
val destination = system.actorOf(Props[PerformanceTestDestination])
|
||||
1 to warmupCycles foreach { i ⇒ channel ! Deliver(PersistentRepr(s"msg${i}", persistenceId = "test"), destination.path) }
|
||||
channel ! Deliver(Persistent(StartMeasure), destination.path)
|
||||
1 to loadCycles foreach { i ⇒ channel ! Deliver(PersistentRepr(s"msg${i}", persistenceId = "test"), destination.path) }
|
||||
channel ! Deliver(Persistent(StopMeasure), destination.path)
|
||||
expectMsgPF(100 seconds) {
|
||||
case throughput: Double ⇒ println(f"\nthroughput = $throughput%.2f persistent messages per second")
|
||||
"Warmup persistent actor" should {
|
||||
"exercise" in {
|
||||
stressCommandsourcedPersistentActor(None)
|
||||
}
|
||||
}
|
||||
|
||||
def subscribeToConfirmation(probe: TestProbe): Unit =
|
||||
system.eventStream.subscribe(probe.ref, classOf[DeliveredByPersistentChannel])
|
||||
|
||||
def awaitConfirmation(probe: TestProbe): Unit =
|
||||
probe.expectMsgType[DeliveredByPersistentChannel]
|
||||
|
||||
"A command sourced processor" should {
|
||||
"have some reasonable throughput" in {
|
||||
stressCommandsourcedProcessor(None)
|
||||
}
|
||||
"have some reasonable throughput under failure conditions" in {
|
||||
stressCommandsourcedProcessor(Some(warmupCycles + loadCycles / 10))
|
||||
"exercise some more" in {
|
||||
stressCommandsourcedPersistentActor(None)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -233,26 +169,20 @@ class PerformanceSpec extends AkkaSpec(PersistenceSpec.config("leveldb", "Perfor
|
|||
|
||||
"An event sourced persistent actor" should {
|
||||
"have some reasonable throughput" in {
|
||||
stressPersistentActor(None)
|
||||
stressEventSourcedPersistentActor(None)
|
||||
}
|
||||
"have some reasonable throughput under failure conditions" in {
|
||||
stressPersistentActor(Some(warmupCycles + loadCycles / 10))
|
||||
stressEventSourcedPersistentActor(Some(loadCycles / 10))
|
||||
}
|
||||
"have some reasonable throughput with stashing and unstashing every 3rd command" in {
|
||||
stressStashingPersistentActor()
|
||||
}
|
||||
}
|
||||
|
||||
"A persistent channel" should {
|
||||
"A mixed command and event sourced persistent actor" should {
|
||||
"have some reasonable throughput" in {
|
||||
val probe = TestProbe()
|
||||
subscribeToConfirmation(probe)
|
||||
|
||||
stressPersistentChannel()
|
||||
|
||||
probe.fishForMessage(100.seconds) {
|
||||
case DeliveredByPersistentChannel(_, snr, _, _) ⇒ snr == warmupCycles + loadCycles + 2
|
||||
}
|
||||
stressMixedPersistentActor(None)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue