Introducing the AF Msg Forwarding Utility
The Trouble with Traversing
Actor Framework has proven itself to be a robust, flexible and maintainable solution ideal for large-scale applications. However, one of the common pain points is producing data at one end of the actor tree and needing to share that data to potentially distant nodes of the tree, in both depth and breadth.
In the above example, Fridge shares a temperature data update (an announcement). The announcement needs to get shared with the Displays on the other side of the tree. Practically speaking, this means the developer must create Actor Messages at every step along the way.
For simple announcements, this is significant overhead. It’s also a code smell - why do we have so many message classes and associated payload methods that are virtually identical?
Unmodified distribution of announcements through complex actor trees is a common scenario and so the tedium of both message creation and maintenance has led many developers to try various workarounds. For example, using a single common actor message to transport many kinds of data, then parsing to determine the exact data being shared - essentially making a string-and-variant type message. Or circumventing the actor tree with alternate transport mechanisms.
While these solutions are tempting and avoid the overhead of explicit actor messaging, they lead to numerous other problems. Breaking the actor hierarchy almost always leads to abstraction leaks, where modules separated in the tree need to know intimate details about each other. Requiring receivers to perform parsing is brittle to changes and can lead to run-time casting errors. And alternate messaging schemes increase complexity and negatively affects code readability.
The Zyah AF Forwarding Utility leverages interfaces to solve the problem of data distribution in a more elegant way.
Routing with Interfaces
With the introduction of interfaces in LabVIEW 2020, developers now have access to a form of multiple inheritance. With this one additional feature, we can now build a simple system for automatically routing announcements.
The first improvement is that interfaces allow the same Msg to be used by many actors. This eliminates code duplication and helps reduce coupling between modules.
Interface inheritance also gives us a simple way to identify which Actors are interested in which announcements.
Now that Actors in our project are using interfaces, we can handle Msg routing with the following steps:
1. At application launch, we make a list of interfaces that we want to automatically forward. These are the interfaces to forward.
The list of interfaces to forward can be defined statically (see example block diagram below).
The list can also be built dynamically, such as by searching for interface classes on-disk that match a certain criteria (such as a naming convention or folder location).
2. Every time we launch a Nested Actor, we determine what interfaces it inherits from.
If it inherits from an interface to forward, we store the Nested Actor enqueuer in a lookup map that uses the interface as a key.
3. Every time an Actor receives a message, we check if it’s owned by an interface of interest.
If so, we forward it to any Nested Actors that inherit from that interface.
In essence, the Zyah AF Forwarding Utility allows actors to use interface inheritance to determine message routing. Using a base actor override of Receive Message:
Messages are passed down the tree based on interface inheritance. If a nested actor wants to receive an announcement, it simply needs to inherit from that announcement interface.
Messages are passed up the tree if (1) the messages are owned by an interface to forward and (2) the receiving actor does not inherit from that announcement interface.
Changing message routing is now as simple as changing actor inheritance. Message data is strictly typed, which avoids run-time parsing errors. And none of the intervening actors in a tree need to be modified at all, which improves code encapsulation and modularity.
Caveats
At Zyah Solutions we think this forwarding utility brings a lot of value to both new and experienced developers alike, however, there are some scenarios where traditional solutions may better serve your application.
Requests/Commands - Requests that involve “control” of an Actor are less safe for automatic broadcast and should most likely be directed to nested actors more deliberately.
Modified Data - If the data needs to be processed and modified/abstracted as it travels through the AF tree, individual overrides are a better solution.
Very High Msg Throughput is Essential - Especially with modern computers, we think this is unlikely to be an issue, but there is non-zero overhead associated with dynamically and automatically routing AF Msgs. If you know that you need very high message throughput (on the order of thousands of messages per second or more) manual Msg routing may serve you better.
Where to Get It
There are two options available to get the forwarding utility:
VIPM
This is available as a package on VI Package Manager.
https://www.vipm.io/package/zyah_solutions_lib_zyah_af_msg_forwarding/GitLab
You can also do a direct pull of the source code from GitLab. We just ask that if you make any improvements, you share it with the community.
https://gitlab.com/zyah-solutions/community-tools/zyah-af-msg-forwarding-utility
If you have any questions or feedback, feel free to reach out to us by e-mail or by joining us on our Discord.
More to Follow…
Keep an eye out for future blog posts that will go into more detail about how this utility works as well as a “Getting Started” guide.