09-14-2012 08:15 AM
Before I stumbled across the Actor Framework (and actor-oriented design in general), my messaging systems were simple point-to-point types. I happily made message queues available to spawned processes all over my wire-scape, and (aside from the occasional tricky race condition) life was good.
Now, having developed a few smallish Actor-based applications and in the midst of refactoring one larger project to get some of the benefits of this new approach, I have some questions about the realities of Hierarchical Messaging.
I'd love to get some opinions about the best ways to propogate messages from one branch of a tree to another. Consider the following example:
My Main actor launches a UI actor and a Camera actor, which in turn launches a Camera Driver actor. Now imagine I have a button on my UI to reset the camera driver. Assuming I don't want to create any direct paths from the UI to the driver:
I'm hoping that there are more elegant ways than creating a Reset Driver message in each of the Main/Camera/Driver actors and then passing my command along the chain.
Has anyone developed a more general message routing system to traverse through the hierarchy using a single Send method, or does that go against the spirit of things?
Would love to hear some real-world experiences about how people manage this...
Solved! Go to Solution.
09-14-2012 12:50 PM
Barring yet another link to existing discussion threads on this topic, here's some direct advice based on experience from my current project:
First: If your application logic is not going to be presented by multiple different UIs, I don't see the point of having a "Main" actor. Just let the UI actor launch and control the Camera actor. That removes one set of Status/Cmd message pairs that would otherwise have to travel through Main.
Note: the following text assumes you've made that change.
In response to your questions about sending messages from a button on the UI to the Driver:
There's a starter. I hope to write about this stuf in lots more detail when I get a lull in project work.
09-14-2012 03:38 PM
I would have a "Reset Camera" message, or so. Then the Camera actor can decide to call "Reset Driver".
09-14-2012 03:44 PM
> I'm hoping that there are more elegant ways than creating a
> Reset Driver message in each of the Main/Camera/Driver
> actors and then passing my command along the chain.
Passing your command along the chain is the good way to do it regardless of anything else. Look at the Stop Msg that is part of the core of the framework. The message passes through the tree. Each level hears the stop message, reacts to it, and passes it along to its nested actors. This "passing along" is an important part of actually getting a clean shutdown. Your Reset message is pretty much the same. You want each level of the hierarchy to hear some sort of reset command, do whatever they need to do, and then pass along to the nested actors so they can do the same. In fact, at some levels, you might not send a single reset command but a whole stream of commands, all of which are designed to put the system back in a cleaned up state.
The only way to get around this would be to create a direct path from the UI to the driver which -- rightfully -- you are loathe to do.
The lightest way would be if all of your actors inherit from a single common parent. Give that parent a Reset method and create a message that invokes it. Now you can send that same message class to any of the child classes. Essentially, exactly what the Stop Msg does. This approach works as long as you don't need to do any complicated "reset child, if that fails, try this other idea, if that fails, try something else..." because that's when you need a whole reset protocol to correctly spin down a system. It also falls appart if any of your actors don't have a well defined "reset" on their own: imagine a drill that is deep in the earth, drilling. The "reset" command at the high application layer actually means "back yourself out back to the surface." But the drill itself doesn't have its own navigation on board, that's in the caller actor that sends drive instructions to the drill. When the navigation actor gets the reset message, it starts sending the complex, and dynamic, set of messages needed to back up the drill and turn it and twist it to get it back to the surface. You wouldn't want the drill actor to even be able to get a reset message directly because the command is not well defined for the drill actor itself.
09-14-2012 06:45 PM
Todd_Lesher wrote:
I would have a "Reset Camera" message, or so. Then the Camera actor can decide to call "Reset Driver".
That's what I have been doing until now, although it still necessitates an "dummy" message in the main actor just to pass the Reset message through... (Is there a name for such beasts, whose sole purpose is to relay a specific message to a specific destination?)
09-14-2012 07:17 PM
AristosQueue wrote:
... In fact, at some levels, you might not send a single reset command but a whole stream of commands, all of which are designed to put the system back in a cleaned up state.
Yes, when the message is general enough there may be certain economies of scale from traversing the entire hierarchy. Obviously a Reset message will often fall into this category. (That's the danger of posting a specific example!)
The lightest way would be if all of your actors inherit from a single common parent. Give that parent a Reset method and create a message that invokes it. Now you can send that same message class to any of the child classes.
Ok, so then I simply override the Reset method at each point along the chain, right? Just to spell it out:
That sounds pretty workable. (I think the best part is that I only need one message class...)
Thanks for helping! 🙂
09-17-2012 07:22 PM
fabric wrote:
Todd_Lesher wrote:
I would have a "Reset Camera" message, or so. Then the Camera actor can decide to call "Reset Driver".
That's what I have been doing until now, although it still necessitates an "dummy" message in the main actor just to pass the Reset message through... (Is there a name for such beasts, whose sole purpose is to relay a specific message to a specific destination?)
I have to maintain flexibility within components so they can be used in different places. It doesn't buy me anything to come up with specific message classes that can be handled by every component. Everything is about the interface between components. Yes, some components couple more than others.