В реализации FSM (старая история: моделирование лифта/лифта) я пытаюсь посмотреть, смогу ли я проверить, следует ли FSM переходу из одного состояния и в одно и то же. Кажется, этого не происходит, но это меня удивляет, потому что согласно the-same-state?rq=1">это обсуждение на StackOverFlow, исправление доступно в Akka 2.4.x.
Вот соответствующая часть кода:
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
Я вырезал ненужные части, потому что суть вот в чем: когда актер получает
Event(ReachedFloor(floorID, PurposeOfMovement.ToWelcomeInAnWaitingPassenger),_)
когда он находится в состоянии «Перемещение», он переключается в состояние «Остановка» с заданным тайм-аутом. Когда этот таймер срабатывает, когда FSM остановлен, обработчик, который должен выполняться, получает имя (также показано выше):
actWhenStoppedForLongEnough
Здесь я проверяю определенное условие выхода, и если я не доволен, я снова переключаюсь обратно в то же состояние Stopped. Сейчас я использую goto(), но исходный код имел stay().
Я также установил блок onTransition (снова показан выше), чтобы доказать, что переход действительно происходит.
onTransition {
case Stopped -> Stopped => {
println("Remaining in Stopped ...")
}
}
Когда я запускаю код, оператор println вообще не выполняется.
У меня также есть тестовый код; соответствующий тестовый пример таков:
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))
}
Я пытаюсь усердно размышлять о том, есть ли пробел в моем понимании и где, но безуспешно. Любые подсказки?
Вот 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"
)
Еще один вопрос, очень похожий на мой - уже спрашивали, но ответов не вижу. Может быть, ответ уже найден, но еще не опубликован.
akka-testkit
вместе с текущейakka-actor
может это как-то связано с твоей проблемой? - person johanandren   schedule 09.11.2016