2016-04-05 3 views
3

Вот код:Stackoverflow исключение в PersistentFSM актер

import akka.actor.{ActorSystem, Props} 
import akka.persistence.fsm.PersistentFSM 
import akka.persistence.fsm.PersistentFSM.FSMState 

import scala.reflect._ 
import scala.reflect.ClassTag 

/** 
    * Created by IDEA on 4/4/16. 
    */ 

object Vendor { 

    sealed trait State extends FSMState 

    case object Dumb extends State { 
    override def identifier = "dumb-state" 
    } 

    case object Smart extends State { 
    override def identifier = "smart-state" 
    } 

    val prices = Map(
    "cola-light" -> 1.23, 
    "cola-fanta" -> 1.23, 
    "cola" -> 1.23, 
    "lays-natural" -> 3.92, 
    "lays-paprika" -> 3.24, 
    "lays-mix" -> 2.56, 
    "lays-superchips" -> 3.99 
) 

    case class Data(var userBalance: Double, val stock: collection.mutable.Map[String, Int]) 

    sealed trait DomainEvent 

    case class DoTransaction(item: String, amount: Int, change: Double) extends DomainEvent 

    case class StoreTransaction(credit: Double, reason: String) extends DomainEvent 

    case object DoReturnMoney extends DomainEvent 

    case class Reject(reason: String) extends DomainEvent 

    sealed trait Msg 

    case class Transaction(item: String, amount: Int, input: Double) extends Msg 

    case object ToggleSmart extends Msg 

    case object ReturnMoney extends Msg 

} 

class Vendor extends PersistentFSM[Vendor.State, Vendor.Data, Vendor.DomainEvent] { 

    import Vendor._ 

    val initData = Data(0d, collection.mutable.Map(
    "cola-light" -> 10, 
    "cola-fanta" -> 10, 
    "cola" -> 10, 
    "lays-natural" -> 10, 
    "lays-paprika" -> 10, 
    "lays-mix" -> 10, 
    "lays-superchips" -> 10 
)) 

    override implicit def domainEventClassTag: ClassTag[DomainEvent] = classTag[DomainEvent] 

    override def applyEvent(domainEvent: DomainEvent, currentData: Data): Data = { 
    domainEvent match { 
     case DoTransaction(item, amount, change) => 
     val (verb, suffix) = if (amount > 1) ("are", "s") else ("is", "") 
     val changeInfo = if (change > 0) { 
      s"And here is your change: €${change}. " 
     } else "" 
     println(s"Here $verb $amount item$suffix of $item. ${changeInfo}Thanks!") 
     currentData.stock(item) -= amount 
     currentData.userBalance = 0 
     currentData 

     case StoreTransaction(credit, reason: String) => 
     println(s"Transaction not successful. \n${reason}\n€${credit} stored on your balance.") 
     currentData.userBalance += credit 
     currentData 

     case DoReturnMoney => 
     println(s"Here is your money: €${currentData.userBalance}.") 
     currentData.userBalance = 0 
     currentData 

     case Reject(reason) => 
     println(s"Transaction rejected due to this reason: $reason") 
     currentData 
    } 
    } 

    startWith(Dumb, initData) 

    when(Dumb) { 
    case Event(Transaction(item, amount, input), currentData) => 
     if (input <= 0) { 
     stay applying Reject("you didn't put in money.") 
     } 
     if (!currentData.stock.contains(item)) { 
     val reason = s"We don't have ${item}." 
     stay applying StoreTransaction(input, reason) 
     } 
     if (currentData.stock(item) < amount) { 
     val reason = s"We have only ${currentData.stock(item)} ${item} in stock." 
     stay applying StoreTransaction(input, reason) 
     } 
     val change = input + currentData.userBalance - prices(item) * amount 
     if (change >= 0) { 
     stay applying DoTransaction(item, amount, change) 
     } else { 
     val reason = s"Insufficient credit, €${-change} in short." 
     stay applying StoreTransaction(input, reason) 
     } 

    case Event(ReturnMoney, _) => 
     stay applying DoReturnMoney 

    case Event(ToggleSmart, _) => 
     goto(Smart) 
    } 


    when(Smart) { 
    case Event(Transaction(item, amount, input), currentData) => 
     if (input <= 0) { 
     stay applying Reject("you didn't put in money.") 
     } 
     if (!currentData.stock.contains(item)) { 
     val suggestion = currentData.stock.keys.find(x => x.startsWith(item)) 
     suggestion match { 
      case None => 
      stay applying StoreTransaction(input, s"We can't find anything similar to ${item}") 
      case Some(item1) => 
      self ! Transaction(item1, amount, input) 
     } 
     } 
     if (currentData.stock(item) < amount) { 
     val reason = s"We have only ${currentData.stock(item)} ${item} in stock." 
     stay applying StoreTransaction(input, reason) 
     } 
     val change = input + currentData.userBalance - prices(item) * amount 
     if (change >= 0) { 
     stay applying DoTransaction(item, amount, change) 
     } else { 
     val reason = s"Insufficient credit, €${-change} in short." 
     stay applying StoreTransaction(input, reason) 
     } 

    case Event(ReturnMoney, _) => 
     stay applying DoReturnMoney 

    case Event(ToggleSmart, _) => 
     goto(Dumb) 

    } 

    override def persistenceId: String = "persistence-vendor" 
} 

object VendorApp extends App { 
    import Vendor._ 
    val asys = ActorSystem("persistence-vendor-app") 
    val vendor = asys.actorOf(Props[Vendor]) 
    vendor ! Transaction("cola-light", 2, 5) 
    Thread.sleep(1000) 
    asys.terminate() 
} 

Здесь ошибка:

/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/bin/java -Didea.launcher.port=7532 "-Didea.launcher.bin.path=/Applications/IntelliJ IDEA CE.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath "/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/lib/tools.jar:/Users/kaiyin/IdeaProjects/Learning Akka (video) code/section4/persistent-fsm&query/target/scala-2.11/classes:/Users/kaiyin/.ivy2/cache/com.google.guava/guava/bundles/guava-16.0.1.jar:/Users/kaiyin/.ivy2/cache/org.scala-lang/scala-library/jars/scala-library-2.11.7.jar:/Users/kaiyin/.ivy2/cache/org.reactivestreams/reactive-streams/jars/reactive-streams-1.0.0.jar:/Users/kaiyin/.ivy2/cache/org.iq80.leveldb/leveldb-api/jars/leveldb-api-0.7.jar:/Users/kaiyin/.ivy2/cache/org.iq80.leveldb/leveldb/jars/leveldb-0.7.jar:/Users/kaiyin/.ivy2/cache/org.fusesource.leveldbjni/leveldbjni-all/bundles/leveldbjni-all-1.8.jar:/Users/kaiyin/.ivy2/cache/com.typesafe.akka/akka-testkit_2.11/jars/akka-testkit_2.11-2.4.0.jar:/Users/kaiyin/.ivy2/cache/com.typesafe.akka/akka-stream-experimental_2.11/jars/akka-stream-experimental_2.11-1.0.jar:/Users/kaiyin/.ivy2/cache/com.typesafe.akka/akka-protobuf_2.11/jars/akka-protobuf_2.11-2.4.0.jar:/Users/kaiyin/.ivy2/cache/com.typesafe.akka/akka-persistence_2.11/jars/akka-persistence_2.11-2.4.0.jar:/Users/kaiyin/.ivy2/cache/com.typesafe.akka/akka-persistence-query-experimental_2.11/jars/akka-persistence-query-experimental_2.11-2.4.0.jar:/Users/kaiyin/.ivy2/cache/com.typesafe.akka/akka-actor_2.11/jars/akka-actor_2.11-2.4.0.jar:/Users/kaiyin/.ivy2/cache/com.typesafe/config/bundles/config-1.3.0.jar:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar" com.intellij.rt.execution.application.AppMain VendorApp 
Uncaught error from thread [persistence-vendor-app-akka.actor.default-dispatcher-3] shutting down JVM since 'akka.jvm-exit-on-fatal-error' is enabled for ActorSystem[persistence-vendor-app] 
java.lang.StackOverflowError 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 
    at Vendor.domainEventClassTag(Vendor.scala:70) 


    ... 

Process finished with exit code 255 

build.sbt:

name := "Persistence" 

version := "1.0" 

scalaVersion := "2.11.7" 

sbtVersion := "0.13.5" 

libraryDependencies ++= Seq(
    "com.typesafe.akka"   %% "akka-actor"  % "2.4.0", 
    "com.typesafe.akka"   %% "akka-persistence" % "2.4.0", 
    "org.iq80.leveldb"   % "leveldb"   % "0.7", 
    "org.fusesource.leveldbjni" % "leveldbjni-all" % "1.8", 
    "com.typesafe.akka" %% "akka-persistence-query-experimental" % "2.4.0", 
    "com.typesafe.akka" % "akka-stream-experimental_2.11" % "1.0 

application.conf:

akka { 
    persistence { 
    journal { 
     plugin = "akka.persistence.journal.leveldb", 
     leveldb { 
     dir = "target/example/journal", 
     native = false 
     } 
    }, 
    snapshot-store { 
     plugin = "akka.persistence.snapshot-store.local", 
     local { 
     dir = "target/example/snapshots" 
     } 
    } 
    } 
} 

Любая идея, что пошло не так?

+0

У меня та же проблема. Вы решили это? – Tim

ответ

2

мне удалось заставить его работать: Если вы посмотрите на тестах PersistentFSM (https://github.com/akka/akka/blob/master/akka-persistence/src/test/scala/akka/persistence/fsm/PersistentFSMSpec.scala#L411)

Вы видите, что они используют неявный параметр конструктора вместо реализации domainEventClassTag в организме. Как-то это, вместе с вызывающим сайтом на props, работает.

я получить что-то вроде:

... 
class Vendor(implicit val domainEventClassTag: ClassTag[Vendor.DomainEvent]) extends PersistentFSM[Vendor.State, Vendor.Data, Vendor.DomainEvent] { 
... 
1

Вместо

override implicit def domainEventClassTag: ClassTag[DomainEvent] classTag[DomainEvent] 

следует

override def domainEventClassTag: ClassTag[DomainEvent] = classTag[DomainEvent] 
Смежные вопросы