In an implementation of an FSM (old story: modeling an Elevator/Lift), I am trying to see if I can test whether the FSM follows a transition from and to the same State. It seems, it is not happening, but that surprises me because according to this discussion on StackOverFlow, the fix is available in Akka 2.4.x.
Here's the relevant portion of the code:
class LiftCarriageWithMovingState extends Actor
with FSM[LiftState,LiftData]
with ActorLogging
{
import context._
val mxTimeToWaitStopping = 500 milliseconds
private var pendingPassengerRequests: Vector[NextStop] = Vector.empty
private var currentFloorID = 0 // Always start at Ground Floor
val timeToReachNextFloor = 1000 millis // up or down, same time taken
private val dontCare: StateFunction = { /* ... */ }
private val powerYourselfOff: StateFunction = { /* ... */ }
private val powerYourselfOn: StateFunction = { /* ... */ }
private val beReady: StateFunction = { /* ... */ }
private val moveToWaitingPassenger: StateFunction = { /* ... */ }
private val transportPassengerToDest: StateFunction = {/* ... */ }
private val actWhenStoppedForLongEnough: StateFunction = {
case Event(StateTimeout,_) =>
if (this.pendingPassengerRequests isEmpty) {
println("timeout in Stopped, no passenger requests pending")
goto (Stopped)
}
else {
println("timeout in Stopped, moving to floor(" + this.pendingPassengerRequests.head + ")")
simulateMovementTo(this.pendingPassengerRequests.head)
goto(Moving)
}
}
startWith(PoweredOff,InitialData)
when (PoweredOff) (powerYourselfOn orElse
dontCare)
when (PoweredOn) (powerYourselfOff orElse
beReady orElse
dontCare)
when (Ready) (moveToWaitingPassenger orElse
transportPassengerToDest )
when (Stopped) (actWhenStoppedForLongEnough orElse
moveToWaitingPassenger orElse
transportPassengerToDest )
when (Moving) {
case Event(ReachedFloor(floorID, PurposeOfMovement.ToWelcomeInAnWaitingPassenger),_) =>
currentFloorID = pendingPassengerRequests.head.floorID
pendingPassengerRequests = pendingPassengerRequests.tail
goto (Stopped) forMax(this.mxTimeToWaitStopping)
case Event(ReachedFloor(floorID,PurposeOfMovement.ToAllowATransportedPassengerAlight),_) =>
currentFloorID = pendingPassengerRequests.head.floorID
pendingPassengerRequests = pendingPassengerRequests.tail
goto (Stopped) forMax(this.mxTimeToWaitStopping)
// .... Other events
}
whenUnhandled {
// Event handlers...
}
onTransition {
case Stopped -> Stopped => {
println("Remaining in Stopped ...")
}
}
// Rest of the Actor
I have pruned unnecessary parts, because the main point is this:
When the actor receives a
Event(ReachedFloor(floorID, PurposeOfMovement.ToWelcomeInAnWaitingPassenger),_)
when it is in the Moving state, it switches to Stopping state, with a specified timeout. When that timer fires while the FSM is Stopped, the handler that is supposed to execute, is named (shown above too):
actWhenStoppedForLongEnough
Here, I am checking a certain exit condition, and if I am not happy, I am switching back to same Stopped state again. I am using goto() now, but the original code had stay().
I have set up a onTransition block too (shown above again), to prove that the transition indeed does happen.
onTransition {
case Stopped -> Stopped => {
println("Remaining in Stopped ...")
}
}
When I run the code, the println statement is not executed, at all.
I also have a testcode; the relevant testcase is this:
var carriage: ActorRef = _
override def beforeAll(): Unit = {
super.beforeAll()
carriage = TestActorRef(Props(new LiftCarriageWithMovingState))
carriage ! SubscribeTransitionCallBack(testActor)
}
"A LiftCarriage" must {
"be ready, when it settles down after being PoweredOn" in {
expectMsg(Duration(100, TimeUnit.MILLISECONDS), new CurrentState(carriage,PoweredOff))
carriage ! InstructedToPowerOn
expectMsg (new Transition(carriage,PoweredOff,PoweredOn))
carriage ! BeReady
expectMsg((new Transition(carriage,PoweredOn,Ready)))
}
"move to where a passenger is waiting, if ready" in {
carriage ! ReportCurrentFloor
expectMsg(StoppedAt(0))
carriage ! PassengerIsWaitingAt(3)
expectMsg(new Transition(carriage,Ready,Moving))
expectMsg(Duration(5000, TimeUnit.MILLISECONDS), new Transition(carriage,Moving, Stopped))
carriage ! ReportCurrentFloor
expectMsg(StoppedAt(3))
}
"let a passenger in and transport her to her destination" in {
carriage ! ReportCurrentFloor
expectMsg(StoppedAt(3))
carriage ! PassengerRequestsATransportTo(Vector(7))
expectMsg(new Transition(carriage,Stopped,Moving))
expectMsg(Duration(5000, TimeUnit.MILLISECONDS), new Transition(carriage,Moving,Stopped))
carriage ! ReportCurrentFloor
expectMsg(StoppedAt(7))
// This always times out and fails.
expectMsg(Duration(5000, TimeUnit.MILLISECONDS), new Transition(carriage,Stopped,Stopped))
}
I am trying to think hard as to if and where the gap in my understanding lies, but failing. Any hints?
Here's the build.sbt:
name := """akka-sample-fsm-scala"""
version := "2.4"
scalaVersion := "2.11.8"
libraryDependencies ++= Seq(
// https://mvnrepository.com/artifact/com.typesafe.akka/akka-actor_2.11
"com.typesafe.akka" % "akka-actor_2.11" % "2.4.12",
// https://mvnrepository.com/artifact/org.scalatest/scalatest_2.11
"org.scalatest" % "scalatest_2.11" % "2.1.3",
// https://mvnrepository.com/artifact/com.typesafe.akka/akka-testkit_2.11,
"com.typesafe.akka" % "akka-testkit_2.11" % "2.3.15"
)
Another question - which is quite similar to mine - has been asked earlier, but I don't see any responses. May be, the answer has been found already but not yet shared.
Related
I'm writing a simple breadth first search algorithm is Scala and I feel like it should be pretty efficient. However when I run this one some relatively small problems I'm managing to run out of memory.
def search(start: State): Option[State] = {
val queue: mutable.Queue[State] = mutable.Queue[State]()
queue.enqueue( start )
while( queue.nonEmpty ){
val node = queue.dequeue()
if( self.isGoal(node) )
return Some(node)
self.successors(node).foreach( queue.enqueue )
}
None
}
I believe the enqueue and dequeue methods on a mutable queue were constant time and for each is implemented efficiently. The methods isGoal and successors I know are as efficient as they as they can be. I don't understand how I can be running out of memory so quickly. Are there any inefficiencies in this code that I'm missing?
I think c0der's comment nailed it: you may be getting caught in an infinite loop re-checking nodes that you've already visited. Consider the following changes:
def search(start: State): Option[State] = {
var visited: Set[State] = Set() // change #1
val queue: mutable.Queue[State] = mutable.Queue[State]()
queue.enqueue( start )
while( queue.nonEmpty ){
val node = queue.dequeue()
if (!visited.contains(node)) { // change #2
visited += node // change #3
if( self.isGoal(node) )
return Some(node)
self.successors(node).foreach( queue.enqueue )
}
}
None
}
Initialize a new Set, visited, to keep track of which Nodes you've been to.
Immediately after dequeueing a Node, check if you've visited it before. If not, continue checking this Node. Otherwise, ignore it.
Make sure to add this Node to the visited Set so it's not checked again in the future.
Hope that helps :D
You have some Java, not Scala code there. For Scala vars and while is something that you should not use at all. Here is my suggestion how you could solve this.
class State(val neighbours: List[State]) // I am not sure how your State class looks like, but it could look something like this
val goal = new State(List())
def breathFirst(start: State): Option[State] = {
#scala.annotation.tailrec
def recursiveFunction(visited: List[State], toVisit: List[State]): Option[State] = { // So we will create recursive function with visited nodes and nodes that we should visit
if (toVisit.isEmpty) return None // If toVisit is empty that means that there is no path from start to goal, return none
else {
val visiting = toVisit.head // Else we should take first node from toVisit
val visitingNeighbours = visiting.neighbours // Take all neighbours from node that we are visiting
val visitingNeighboursNotYetVisited = visitingNeighbours.filter(x => !visited.contains(x)) //Filter all neighbours that are not visited
if (visitingNeighboursNotYetVisited.contains(goal)) { //if we found goal, return it
return Some(goal)
} else {
return recursiveFunction(visited :+ visiting, toVisit.tail ++ visitingNeighboursNotYetVisited) // Otherwise add node that we visited in this iteration to list of visited nodes that does not have visited node - it was head so we take toVisit.tail
// and also we will take all neighbours that are not visited and add them to toVisit list for next iteration
}
}
}
if (start == goal) { // If goal is start, return start
Some(start)
} else { // else call our recursive function with empty visited list and with toVisit list that has start node
recursiveFunction(List(), List(start))
}
}
NOTE: You could change:
val visitingNeighboursNotYetVisited = visitingNeighbours.filter(x => !visited.contains(x)) //Filter all neighbours that are not visited
with
val visitingNeighboursNotYetVisited = visitingNeighbours
and check if you will go out of memory, and, as probably you wont it will show you why you should use tailrec.
Given the following code
case class Score(value: BigInt, random: Long = randomLong) extends Comparable[Score] {
override def compareTo(that: Score): Int = {
if (this.value < that.value) -1
else if (this.value > that.value) 1
else if (this.random < that.random) -1
else if (this.random > that.random) 1
else 0
}
override def equals(obj: _root_.scala.Any): Boolean = {
val that = obj.asInstanceOf[Score]
this.value == that.value && this.random == that.random
}
}
#tailrec
private def update(mode: UpdateMode, member: String, newScore: Score, spinCount: Int, spinStart: Long): Unit = {
// Caution: there is some subtle logic below, so don't modify it unless you grok it
try {
Metrics.checkSpinCount(member, spinCount)
} catch {
case cause: ConcurrentModificationException =>
throw new ConcurrentModificationException(Leaderboard.maximumSpinCountExceeded.format("update", member), cause)
}
// Set the spin-lock
put(member, None) match {
case None =>
// BEGIN CRITICAL SECTION
// Member's first time on the board
if (scoreToMember.put(newScore, member) != null) {
val message = s"$member: added new member in memberToScore, but found old member in scoreToMember"
logger.error(message)
throw new ConcurrentModificationException(message)
}
memberToScore.put(member, Some(newScore)) // remove the spin-lock
// END CRITICAL SECTION
case Some(option) => option match {
case None => // Update in progress, so spin until complete
//logger.debug(s"update: $member locked, spinCount = $spinCount")
for (i <- -1 to spinCount * 2) {Thread.`yield`()} // dampen contention
update(mode, member, newScore, spinCount + 1, spinStart)
case Some(oldScore) =>
// BEGIN CRITICAL SECTION
// Member already on the leaderboard
if (scoreToMember.remove(oldScore) == null) {
val message = s"$member: oldScore not found in scoreToMember, concurrency defect"
logger.error(message)
throw new ConcurrentModificationException(message)
} else {
val score =
mode match {
case Replace =>
//logger.debug(s"$member: newScore = $newScore")
newScore
case Increment =>
//logger.debug(s"$member: newScore = $newScore, oldScore = $oldScore")
Score(newScore.value + oldScore.value)
}
//logger.debug(s"$member: updated score = $score")
scoreToMember.put(score, member)
memberToScore.put(member, Some(score)) // remove the spin-lock
//logger.debug(s"update: $member unlocked")
}
// END CRITICAL SECTION
// Do this outside the critical section to reduce time under lock
if (spinCount > 0) Metrics.checkSpinTime(System.nanoTime() - spinStart)
}
}
}
There are two important data structures: memberToScore and scoreToMember. I have experimented using both TrieMap[String,Option[Score]] and ConcurrentHashMap[String,Option[Score]] for memberToScore and both have the same behavior.
So far my testing indicates the code is correct and thread safe, but the mystery is the performance of the spin-lock. On a system with 12 hardware threads, and 1000 iterations on 12 Futures: hitting the same member all the time results in spin cycles of 50 or more, but hitting a random distribution of members can result in spin cycles of 100 or more. The behavior gets worse if I don't dampen the spin without iterating over yield() calls.
So, this seems counter intuitive, I was expecting the random distribution of keys to result in less spin than the same key, but testing proves otherwise.
Can anyone offer some insight into this counter-intuitive behavior?
Granted there may be better solutions to my design, and I am open to them, but for now I cannot seem to find a satisfactory explanation for what my tests are showing, and my curiosity leaves me hungry.
As an aside, while the single member test has a lower ceiling for the spin count, the random member test has a lower ceiling for time spinning, which is what I would expect. I just cannot explain why the random member test generally produces a higher ceiling for spin count.
I have an easy task to accomplish: read a password from a command line prompt without exposing it. I know that there is java.io.Console.readPassword, however, there are times when you cannot access console as if you are running your app from an IDE (such as IntelliJ).
I stumbled upon this Password Masking in the Java Programming Language tutorial, which looks nice, but I fail to implement it in Scala. So far my solution is:
class EraserThread() extends Runnable {
private var stop = false
override def run(): Unit = {
stop = true
while ( stop ) {
System.out.print("\010*")
try
Thread.sleep(1)
catch {
case ie: InterruptedException =>
ie.printStackTrace()
}
}
}
def stopMasking(): Unit = {
this.stop = false
}
}
val et = new EraserThread()
val mask = new Thread(et)
mask.start()
val password = StdIn.readLine("Password: ")
et.stopMasking()
When I start this snippet I get a continuos printing of asterisks on new lines. E.g.:
*
*
*
*
Is there any specific in Scala why this is not working? Or is there any better way to do this in Scala in general?
So I was reading tutorial about akka and came across this http://manuel.bernhardt.io/2014/04/23/a-handful-akka-techniques/ and I think he explained it pretty well, I just picked up scala recently and having difficulties with the tutorial above,
I wonder what is the difference between RoundRobinRouter and the current RoundRobinRouterLogic? Obviously the implementation is quite different.
Previously the implementation of RoundRobinRouter is
val workers = context.actorOf(Props[ItemProcessingWorker].withRouter(RoundRobinRouter(100)))
with processBatch
def processBatch(batch: List[BatchItem]) = {
if (batch.isEmpty) {
log.info(s"Done migrating all items for data set $dataSetId. $totalItems processed items, we had ${allProcessingErrors.size} errors in total")
} else {
// reset processing state for the current batch
currentBatchSize = batch.size
allProcessedItemsCount = currentProcessedItemsCount + allProcessedItemsCount
currentProcessedItemsCount = 0
allProcessingErrors = currentProcessingErrors ::: allProcessingErrors
currentProcessingErrors = List.empty
// distribute the work
batch foreach { item =>
workers ! item
}
}
}
Here's my implementation of RoundRobinRouterLogic
var mappings : Option[ActorRef] = None
var router = {
val routees = Vector.fill(100) {
mappings = Some(context.actorOf(Props[Application3]))
context watch mappings.get
ActorRefRoutee(mappings.get)
}
Router(RoundRobinRoutingLogic(), routees)
}
and treated the processBatch as such
def processBatch(batch: List[BatchItem]) = {
if (batch.isEmpty) {
println(s"Done migrating all items for data set $dataSetId. $totalItems processed items, we had ${allProcessingErrors.size} errors in total")
} else {
// reset processing state for the current batch
currentBatchSize = batch.size
allProcessedItemsCount = currentProcessedItemsCount + allProcessedItemsCount
currentProcessedItemsCount = 0
allProcessingErrors = currentProcessingErrors ::: allProcessingErrors
currentProcessingErrors = List.empty
// distribute the work
batch foreach { item =>
// println(item.id)
mappings.get ! item
}
}
}
I somehow cannot run this tutorial, and it's stuck at the point where it's iterating the batch list. I wonder what I did wrong.
Thanks
In the first place, you have to distinguish diff between them.
RoundRobinRouter is a Router that uses round-robin to select a connection.
While
RoundRobinRoutingLogic uses round-robin to select a routee
You can provide own RoutingLogic (it has helped me to understand how Akka works under the hood)
class RedundancyRoutingLogic(nbrCopies: Int) extends RoutingLogic {
val roundRobin = RoundRobinRoutingLogic()
def select(message: Any, routees: immutable.IndexedSeq[Routee]): Routee = {
val targets = (1 to nbrCopies).map(_ => roundRobin.select(message, routees))
SeveralRoutees(targets)
}
}
link on doc http://doc.akka.io/docs/akka/2.3.3/scala/routing.html
p.s. this doc is very clear and it has helped me the most
Actually I misunderstood the method, and found out the solution was to use RoundRobinPool as stated in http://doc.akka.io/docs/akka/2.3-M2/project/migration-guide-2.2.x-2.3.x.html
For example RoundRobinRouter has been renamed to RoundRobinPool or
RoundRobinGroup depending on which type you are actually using.
from
val workers = context.actorOf(Props[ItemProcessingWorker].withRouter(RoundRobinRouter(100)))
to
val workers = context.actorOf(RoundRobinPool(100).props(Props[ItemProcessingWorker]), "router2")
I have a Future[Future[Set[String]]. I flatmap it to return a Future[Set[String]]. I wait for infinity (I know this is bad) and then check if the Future is complete. It returns true. However, when I get the value returned by Future and try to add it to a Set, it doesn't add it. Statements at the end of the callback get printed first. When I return the Set from the method, it is always empty though the Future does return values. I have added comments as to explain the sequence of events happening. Please point me if I am doing something wrong! Thanks!
val googleXfpSegments = Set[String]()
val customCriteriaFuture: Future[List[Long]] = getCustomCriteriaValueIds(lineItemPage.getResults())
// getCustomCriteriaValues returns a Future[Set[String]]
val criteriaValueList = customCriteriaFuture.flatMap(criteriaIdList => getCustomCriteriaValues(criteriaIdList.toSet))
// I wait for infinite time
Await.result(criteriaValueList, scala.concurrent.duration.Duration.Inf)
log.info("Future Completed = " + criteriaValueList.isCompleted) // This returns true
criteriaValueList onComplete {
case Success(segmentNames) => {
// This statement gets printed after the "TEST" value gets printed
log.info("SegmentNameList = " + segmentNames.mkString(","))
googleXfpSegments ++= segmentNames
// This prints nothing which means the segmentNames is not getting added
log.info("Google Segments = " + googleXfpSegments.mkString(","))
}
case Failure(error) => log.error("Error occurred ", error)
}
googleXfpSegments += "TEST"
// This prints TEST
log.info("Google Segments = " + googleXfpSegments.mkString(","))
Log output is shown below:
[info] [INFO] [2014-12-09 17:25:01,147] [service.GoogleXFPService] Future Completed = true
[info] [INFO] [2014-12-09 17:25:01,148] [service.GoogleXFPService] Google Segments = TEST
[info] [INFO] [2014-12-09 17:25:01,148] [service.GoogleXFPService] SegmentNameList = vt.cm,vt.cp,ex.qy,ex.ahe,cm.gannett_trav
You need to assign the output of Await.result(criteriaValueList, scala.concurrent.duration.Duration.Inf) to a value. Currently you are waiting for it to complete, doing nothing with the output, then attaching an onComplete callback to an already completed future, then your program terminates before the callback can run.
val segmentNames = Await.result(criteriaValueList, scala.concurrent.duration.Duration.Inf)
log.info("Google Segments = " + segmentNames.mkString(","))