Writing applications with Scala actors in practice II
actor, scala
Solution
You use 5 components, definitely. There are actors dealing with specific tasks, and there's an orchestrator as well.
The question you must have, of course, is how do you chain this assynchronously. Well, it's actually somewhat easy, but it can obscure the code. Basically, you send each componenent the reply you want.
react {
case DeleteTrades(user,dates) =>
PermissionService ! FindPermissions(user, DeleteTradesPermissions(dates) _)
case DeleteTradesPermissions(dates)(ps) =>
if (ps hasPermission "delete")
Persistence ! FindTrades(date, DeleteTradesTradeSet _)
case DeleteTradesTradeSet(ts) =>
ReportService ! SendCancelReports(ts)
PositionService ! UpdateWithDeletedTrades(ts)
}
Here we use currying to pass "dates" in the first returning answer. If there's a lot of parameters associated with an interaction, it might be better to keep the information for all on-going transactions in a local HashSet, and just pass a token that you'll use to locate that information when receiving the answer.
Note that this single actor can handle multiple concurrent actions. In this particular case, just Delete transactions, but you could add any number of different actions for it to handle. When the data needed for one action is ready, then that action continues.
EDIT
Here's a working example of how these classes can be defined:
class Date
class User
class PermissionSet
abstract class Message
case class DeleteTradesPermission(date: Date)(ps: PermissionSet) extends Message
case class FindPermissions(u: User, r: (PermissionSet) => Message) extends Message
FindPermissions(new User, DeleteTradesPermission(new Date) _)
A few explanations on currying and functions. The class `DeleteTradesPermission` is curried so that you can pass a `Date` on it, and have some other function complete it with a `PermissionSet`. This would be the pattern of the answer messages.
Now, the class `FindPermissions` receives as a second parameter a function. The actor receiving this message will pass the return value to this function, and will receive a `Message` to be sent as answer. In this example, the message will have both the `Date`, which the calling actor sent, and `PermissionSet`, which the answering actor is providing.
If no answer is expected, such as the case of `DeleteTrades`, `SendCancelReports` and `UpdateWithDeletedTrades` for the purposes of this example, then you don't need to pass a function of the returning message.
Since we are expecting a function which returns a Message as parameter for those messages requiring an answer, we could define traits like this:
trait MessageResponse1[-T1] extends Function1[T1, Message]
trait MessageResponse2[-T1, -T2] extends Function2[T1, T2, Message]
...
Problem
Because my first question was so long, I'm asking this as a separate question. It's another one about the architecture of an actor-based application. Keeping track of message paths through an Application Let's take a piece of Java code: ``` public void deleteTrades(User user, Date date) { PermissionSet ps = permissionService.findPermissions(user) if (ps.hasPermission("delete")) { Set<Trade> ts = peristence.findTrades(date); reportService.sendCancelReports(ts); positionService.updateWithDeletedTrades(ts); } } ``` In this code I have 4 separate components and the interaction between them required for the procedure `deleteTrades` is well-defined. It's completely contained in the method `deleteTrades`. Modelling this with `Actor`s and replacing my 4 components with 4 separate actors, how do I keep track (in my mind) of what a procedure involves? Particularly if I'm avoiding using the `!?` operator, then it's likely that I'll be sending a message `ConditionalDelete` to my `PermissionActor`, which will be sending a message `GetTradesAndDelete` to my `PersistenceActor` which will then send further messages etc etc. The code to process a delete will be strewn across my application. It also means that pretty much every actor needs a handle on every other actor (in order to forward messages). As in my previous question, how do people deal with this? Is there a good modelling tool which lets you keep track of all this? Do people use `!?` Am I turning too many components into `Actor`s?