0
votes

I have a Akka FSM actor that uses a SetTimer indefinitely. I have seen it few times that the timer does not dispatch the message. Has anyone seen this behavior or any gotcha that I have to avoid while using FSM?

Here is some information about how my code works.

I have a Akka FSM that waits for files to arrive. upon arrival I parse them and store them in my memory. I have a timer that gets called every hour and sends a PushTODB message to self. When FSM receives that message it goes to a non-receiving state and does pushTODB work. when pushTODB is successful I receive a message from the DAL actor(which does the database work) and the FSM goes back to receiving state. So everything hangs on the fact that I receive periodic PushTODB message.

Any help or idea is welcome. Thanks Manas

Adding the code to help understand the question. The code is bit modified to hide some details that are not important for this discussion but after stubbing the non-important function this is what the code looks like

  class FileMonitor extends Actor with ActorLogging
     with LoggingFSM[Status, Data]{
   val config = context.system.settings.config
   val landingZones = ConfigUtils.getLZInfoList(config)
   val pushToDBFreq =  1 hour
   val manager = context.actorOf(Props(new MMSIManager))
   manager ! Activate
   var collection = ActorRef.noSender
   val workingFolder = "/tmp"
   val UOWProvCH1 = "ch1path"
   val UOWProvCH2 = "ch2path"

  startWith(Idle, toBeHandled(Seq(newFile(Paths.get("")))))
  when(Idle, inf) {
    case Event(Activate(ref, again), list) =>
      collection = ref
      init(again)
      goto(Active) using list
  }
 when(Active, inf) {
    case Event(nf @ newFile(someFile, au, nextau), list: toBeHandled) =>
    dosomething()
    stay

   case Event(BeIdle, list: toBeHandled) =>
     log.info("Asking manager to pushToDB........")
     manager ! pushToDB()
     goto(NonTransmitting) using list
 }
 when(NonTransmitting, inf) {
   case Event(event :pushToDBSuccess, list: toBeHandled) =>
     log.debug("received pushTODBSucess message...............")
     cleanit(list)
     list.fileName.foreach(file => sendPositional(file))
     goto(Active) using list.copy(fileName = Seq.empty)
 }
 whenUnhandled{
   case Event(nf :newFile, list @ toBeHandled(l)) =>
     list.copy(fileName = l :+nf )
     stay using list
  stay
   case x => log.warning(s"Got message $x.........")
     stay
 }
 onTransition {
    case Idle -> Active => {
      setTimer("BeIdle", BeIdle, 1 hour, true)
      log.info("Going Active............")
 }
}

As a work around I am checking if the timer is active and re-creating it; but I would love to know if there is something that I am doing wrong here or missing anything because of which the timer does not dispatch BeIdle message. Sometime it works for few hours and then BeIdle stops showing up and at least on one instance BeIdle did not show up at all.

Hope this code help to understand the problem.

..Manas

1
Can you post your code?Ryan

1 Answers

0
votes

One fishy thing is that you are starting a new timer on every transition from Idle to Active.

Consider calling cancelTimer("BeIdle") when exiting Active status or start a single timer in preStart block.