We're looking for some advice/opinion on the best way to construct our actor using the FSM trait. I've given a bit of background, hence the long post, hopefully it won't be too confusing.
We writing an actor that aggregates data from three sources, the third of which requires the data from the first two. We've been looking at the FSM syntax as opposed to the standard receive/become syntax as we had an actor which did a similar thing, and the flow was a bit unclear; we're finding FSM makes the states/transitions clearer. Our actor does the following on a request for a "Thing". - Simultaneously tell ThingPartAProvider and ThingPartBProvider to get part A and part B of the Thing respectively. - Combine thing part A and part B to create a single Thing once both providers have told us the results. - Send the Thing to a the third source, the ThingEnricher and wait for the enriched thing - Finally send the resulting thing back to the original requester We've thought-up two proposed state machines for solving this problem, and sketched out the implementation, and neither seem totally satisfactory, I've attached a diagram. <https://lh3.googleusercontent.com/-3_pd5yJqRPc/U3Id0ZXX1uI/AAAAAAAAEqk/tcn17jzt84o/s1600/FSM.png> *FSMv1:* An partial implementation (for the states waiting for parts A and B) would look something like this: ----- when(WaitingForPartAandPartB) { case Event(PartA, _) => goto WaitingForPartB using PartialThing(PartA) case Event(PartB, _) => goto WaitingForPartA using PartialThing(PartB) } when(WaitingForPartA) { case Event(PartA, _) => goto WaitingForThingEnricher using PartialThing(PartA, PartB) WaitingForThingEnricher } when (WaitingForPartB) { case Event(PartB, _) => goto WaitingForThingEnricher using PartialThing(PartA, PartB) } onTransition { case WaitingForPartA -> WaitingForThingEnricher | WaitingForPartB -> WaitingForThingEnricher => nextStateData thingEnricher ! PartialThing(PartA, PartB) } ----- *Advantage*: The only events causing state changes are those coming from outside the state machine, and the flow stays in a single, forward direction. *Disadvantage*: The duplication of the WaitingForThingEnricher goto statements, and that this would be become a lot more complex if a PartC was added. *FSMv2:* An implementation for the states waiting for parts would look something like this: ----- when(WaitingForPartAandPartB) { case Event(PartA, PartialThing(None, partB)) => { self ! CheckForBoth stay using PartialThing(Some(PartA, partB)) } case Event(PartB, PartialThing(partB, None)) => { self ! CheckForBoth stay using PartialThing(Some(partA, PartB)) } case Event(CheckForBothParts, PartialThing(Some(partA), Some(partB))) => goto WaitingForThingEnricher using PartialThing(Some(partA), Some(partB)) } onTransition { case WaitingForPartAandPartB -> WaitingForThingEnricher => nextStateData match { case thing @ PartialThing(Some, Some) => thingEnricher ! thing case _ => // stay } } ----- *Advantage*: The exit from this state is a single point, and that it allows for additional parts by adding one extra event and one extra option to the state. *Disadvantage*: Sending a message to self is perhaps a bit confusing at first glance, and feels an odd thing to do. What I'd really like to do in this implementation is move that out to the transition to make it a bit cleaner like this: ----- when(WaitingForPartAandPartB) { case Event(PartA, PartialThing(None, partB)) => goto WaitingForPartAandPartB using PartialThing(Some(PartA, partB)) case Event(PartB, Thing(partB, None)) => goto WaitingForPartAandPartB using PartialThing(Some(partA, PartB)) case Event(CheckForBothParts, PartialThing(Some(partA), Some(partB))) => goto WaitingForThingEnricher using PartialThing(Some(partA), Some(partB)) } onTransition { case WaitingForPartAandPartB -> WaitingForPartAandPartB => self ! CheckForBoth case WaitingForPartAandPartB -> WaitingForThingEnricher => nextStateData match { case thing @ PartialThing(Some, Some) => thingEnricher ! thing } } ----- But this does not seem possible (yet? I found this issue https://github.com/akka/akka/issues/13970 to allow it?) Has anyone else had experience in writing actors that did a similar aggregation? What approach did you find best? Is there a completely different approach we should be considering, or which of these two would you consider best? Thanks, tz.lillington -- >>>>>>>>>> Read the docs: http://akka.io/docs/ >>>>>>>>>> Check the FAQ: >>>>>>>>>> http://doc.akka.io/docs/akka/current/additional/faq.html >>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user --- You received this message because you are subscribed to the Google Groups "Akka User List" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/akka-user. For more options, visit https://groups.google.com/d/optout.
