Jump to content

[LVTN] Messenger Library


Recommended Posts

 

3) Give the subUI the address of a third party (“DataSourceâ€) from which it can request the data (request directly, not by notification, synchronous or asynchronous).   Note that this address cannot be the Caller, as we are placing the subUI above DataSource in the service hierarchy (subUI is below Caller by definition).

 

— James

 

So this is the option I went for. It provides the subView with a reference to the service actor, placing the subView (and it's caller View actor) above the Project service actor.

 

This seems to work well, and I'm progressing my trial project nicely. I'm learning the power of the framework as a I go, and realised a few places where using the State Notifier instead of an Event Notifier would have been better. For some reason I thought there could only be one state notification, as compared to any number of event notifications. I think maybe I misinterpreted the intent in one of your instructional videos.

 

It would be possible for Main to pass the address of B to A in a message.   In which case, A can use B as if it were a subactor, like A1 and A2.  But this should be rarely used.   Main should never pass itself to A, or pass A and B to each other, as this makes actor subcomponents of each other, and that can lead to problems.

 

Hmm. So does this not conflict with advise earlier to share the registration handle of B with A1, which is what I did, so that A1 can directly ask B for it's required info. This is working well for me, B is unaware of any other actor so it's at the bottom of the chain and cannot demand anything synchronously of any other component.

Link to comment

So does this not conflict with advise earlier to share the registration handle of B with A1, which is what I did, so that A1 can directly ask B for it's required info. This is working well for me, B is unaware of any other actor so it's at the bottom of the chain and cannot demand anything synchronously of any other component.

 

No, no, I was just trying to stress that one is making a conscious decision to make B a “serviceâ€, and thus “lower†than A, and you shouldn’t make the service dependance go both ways.  Also, though I do this kind of stuff, it is not the technique I reach for first.  However, it’s a great technique when one is working with plugins, where the top-level calling actor may know less about a subactor than another subactor knows.  For example, one might have multiple plugin UI actors that are designed to interact with a plugin equipment actor; these UIs know more about the Equipment than the Top-level actor, so it makes sense for the Top-Level to just hand-off the Equipment actor to the UI.  

Link to comment

I believe for your trial project your dealing with configuration information.  I was just today adding a configuration feature to a project, and the technique I used is different from the above discussed technique, so I thought I would post the relevant subVI, called from the top-level VI:

 

post-18176-0-45228000-1454011793.png

 

“SubMod†is cluster of subActor addresses.  It is converted to an array and then I use “Scatter-Gather†to send the same message to all actors (in parallel) and wait for all responses.   Each actor replies to the “Configuration: Get as JSON†message by returning a JSON value, so we extract these and build a JSON Object from them.   The top-level actor saves this to a JSON file.   Another subVI is used on startup (or when the User selects “Set to default control valuesâ€) to parse the JSON and send subcomponents off to the correct subactor.   Note that there are no typedefs to share that increase coupling; the top-level has no dependance on the form of the Config info (other than that it is JSON). 

 

 

Here’s the code in one of the subactors for replying to the â€œConfiguration: Get as JSON†message:

post-18176-0-13007100-1454015531.png

This subactor has two forms of information that it wants to save: a cluster called “Limitsâ€, and an array of control references.  Both are easy to convert into JSON.  The JSON Object is sent back in a reply labelled “Config†(though this label isn’t actually needed). 

Link to comment

That's neat. My configuration implementation is different, in that I have a specific list of stats that I want to write and a service actor is responsible for controlling the values. Therefore updates are sent to it live (notifications) from the other actors. On exit (or on demand if needed) the actor saves to file. Your implementation which is entirely re-usable as there is no coupling whatsoever, mine not so much. I did however take the elements associated with file I/O and make a reusable lvlib out of those, so there's some reuse.

 

Speaking a little more on Service Hierarchy. I came across a conundrum with my user interface sub-actors (think of them as A1 and A2 in your topology above). There is a pool of n sub-actors that the caller (A) loads dynamically from file when required and inserts their FP into it's own sub-panel. This is a plugin approach to allow feature extension by creating additional sub-actors without needing to touch the rest of the solution. And this is where my puzzle begins.

 

Each sub-actor provides a unique view of the project data. Additional future subactors will provide new views and new functionality, as requirements are defined. Therefore, these sub-actors present an unknown to the caller (A). So caller A can handle messages that are common to all sub-actors, but it can't handle specific messages because it can't know what they are.

 

So the way I see it, my options are:

 

1. Where a sub-actor (A3) needs to cause some specific action to occur, such as asking the Project actor to add a new source object with a provided path, it will have to bypass the caller (A) and directly message the Project actor. This means providing the Project actor's messaging queue to the sub-actor. However it defeats the Service Hierarchy proposal as it allows sub-actors to bypass the preferred message paths and creates hard to debug links between actors.

 

2. Create a generic messaging structure, probably a class hierarchy, that somehow allows caller A to receive and handle requests without knowing in advance what the content will be. This maintains the hierarchy tree and supports future messages.

 

3. Use sophisticated Translators in A that receive all messages from the sub-actors and parse the content to interpret their intent, following a predefined syntax, and forward requests/notifications onto other actors. This maintains the hierarchy tree and supports future messages.

 

4. Other?

 

Any thoughts James?

Link to comment

Any thoughts James?

 

Option (1) seems fine to me.  As long as it is a considered architectural decision, making “Project†a service of all the other actors looks like the best trade-off.  UI’s are something that I have used option (1) for in the past, because they often are written specifically as a UI for one business-logic actor, know more about that actor than their caller (the overall application manager), yet can’t themselves launch the business-logic actor because their can be multiple UIs for the business actor, and the lifetimes of the UIs can be shorter than the business actor.

 

One app I had had this:

 

— MAIN would launch an “Equipment Manager†and pass it equipment config JSON.

 

— Equipment Manager would dynamically load the equipment, which included Test Steps that equipment could run and Editor actors that could be used to modify those steps (Cameras, for example, needed special editors with imaging).

 

— Main would register for the list of editors, and allow the User to select among them.  When selected, it would launch one and pass it the Equipment Manager.  The Editor would register for the info it needed from the Manager (state notifications), and also control the Manager.

 

MAIN actor itself knew nothing about equipment or Tests and only controled startup, config, and shutdown.  In fact, MAIN mostly received no messages all and did nothing most of the time.   When the User picked a different Editor, the current one would be shutdown first (only one Editor was alive at any point).  

 

Option (2), I think, is difficult to execute in a way that is worth the effort (easy to make your program harder to understand).

 

Option (3), custom translators (also, custom “Send†child classes) should by an “ace-in-the-holeâ€, reserved to get you out of trouble, rather than being your primary design tool.

Link to comment

I think your framework has come far enough now that you need to drop all this "actor" terminology. You now have specific modes of messaging and operations such as services, listeners, controllers and processes which are all merged under the banner "actor" - the same way everything is a "VI", even LVPOOP "methods".

 

This is a similar scenario to the electrician/decorator problem and a switch of view will help understanding, adoption and epiphanies. I tend to think of actors as the micro and services et. al. as the macro.

 

Your framework is superior to the Actor Framework so you should no longer ride on its terminology coat-tails and the OOP definition is just a universal catch-all for chunks of code (turtles all the way down). Calling all your use case solutions "actors" is just confusing and hiding the underlying application realisation and therein lies the power of your framework.

Link to comment

Actually, option 1 is the option I implemented, but afterwards led to a dependency complication that made me wonder about alternatives (hence my post above).

 

My current situation is now this:

post-33316-0-42413200-1454068673.png

 

Main launches View Main, Project and ConfigData actors.

View dynamically launches View subactors, as and when required.

Because the View subactors require access to the Project service, I need to pass the Project actor messaging queue to both View, and then subsequently onto each View subactor. This is first conducted by Main, then by View to each subactor.

 

The View actor provides a menu from which the operator can select, for example, "Add Data Source to Project", which causes a message to be sent to Project actor instructing that a new data source be included in the project. The path of the new data source is part of the message, so the View actor has a little bit of code (a subVI) that requests a path from the operator, performs some checks and returns the path value.

 

One of the View subactors also has an onscreen option to add a new data source to the project. This is where I tripped up. Currently, this subactor uses the exact same subVI as View actor. The intent was for sensible reuse, but I've created a dependency link. The View actor is now sharing a resource *(subVI) with an entirely independent subView actor, and there potentially many more examples of this in the other View subactors. This makes the plugin based solution tricky, I've lost my component cohesion. It's much neater to have each actor's dependencies distinct (zero-coupling?).

 

So I began to wonder if the subactors shouldn't be performing any work at all, and instead be passing messages up to View and have something else conduct their activities? That would mean this particular subVI is called in only one place, probably only by View actor. But that doesn't work without creating a fair bit of coupling between actors - we lose the flexibility to add new View subactors with unique functionality.

 

So I still agree that it makes sense to pass the Project reference down to the subView actors so that they can independently get on with their duties, but I'm not sure where to put common dependencies (subVIs called by both View actor and the View subActors).

 

If I create a library of common VIs called by multiple View-related actors (viewcommon.lvlib) how do I best ensure this linkage is honoured when building an executable? If the View subactors are distributed as built PPLs then it will draw into the PPL a copy of viewcommon.lvlib (as well 5Mb worth of Messaging framework too!). If I distribute the subactors as pure source then I think that will work as the links are rebuilt on dynamic load within the View actor, but distributing source code isn't good for control purposes. Turning the subactors into traditional llbs doesn't work (I tried - they end up broken).

 

Sorry for the long posts. Any thoughts?

Edited by Thoric
Link to comment

PPL’s eh?   Hardcore.  Or masochistic, I’m not sure which.  I have not had reason to try PPL’s but I believe one needs to think out a library hierarchy, starting from the base, so the first thing one would do is make PPLs out of Messenger Library and any other reuse packages.  Then you build a viewcommon PPL, and then finally PPLs for your View subactors.

Link to comment

I think your framework has come far enough now that you need to drop all this "actor" terminology. 

 

Well, I originally called them just “parallel processesâ€, but I adopted the “actor†terminology because it is a standard computer science term.  One can google “actor model programming†and learn about the theory, and find many other implementation in multiple languages (Akka, C++ Actor Framework and Erlang are the ones I follow).   The terminology isn’t owned by the LabVIEW "Actor Frameworkâ€, and there are other LabVIEW developers that use “actor†or “actor-oriented†terminology, following the Actor Model rather than the AF.  

 

Unfortunately, it is difficult to identify terminology that means the same thing to all people.  I used “Observer Pattern†terminology in some of the framework, before realizing that other developers have strange associations with “observer patternâ€.  

Link to comment

Well, I originally called them just “parallel processesâ€, but I adopted the “actor†terminology because it is a standard computer science term.  One can google “actor model programming†and learn about the theory, and find many other implementation in multiple languages (Akka, C++ Actor Framework and Erlang are the ones I follow).   The terminology isn’t owned by the LabVIEW "Actor Frameworkâ€, and there are other LabVIEW developers that use “actor†or “actor-oriented†terminology, following the Actor Model rather than the AF.  

 

Unfortunately, it is difficult to identify terminology that means the same thing to all people.  I used “Observer Pattern†terminology in some of the framework, before realizing that other developers have strange associations with “observer patternâ€.  

 

Indeed. But in LabVIEW, pure (CS) programmers are scarce and applied programmers are many which is why I pointed out the electrician/decorator example.

'Parallel processes' is actually worse since it has a well defined meaning in terms of the operating system and labview VIs run under the executable process. I see similar misuses of "threads".

 

Anyway. Just food for thought.

Link to comment
  • 2 months later...

Is it OK to put an Actor's "Internal Data" into its class control? or does it need to be empty?  I ran out of space on the actor diagram and had to make SubVIs to parse some messages and handle some follow on actions.   The internal data is a relatively big cluster and takes up a lot of space on the front panel of the SubVIs and could be cleaned up if it was a class wire.  Do you try to keep everything on the top level block diagram as good practice?  I think I remember one of JKI's style guidelines for their "state machine" recommending to keep the state string constants at the top level for clarity.

 

post-549-0-92071100-1459509570.png

post-549-0-30891200-1459509575.png

 

Also opening another can of worms...do you often have parent-child inheritance situations where an actor inherits from another?  For instance, for an "instrument" do you have an abstract parent and implementation in a child actor or do you make the messages abstract (message names shared between the same instrument type) such as "measure" and "set range" and the actors of the same instrument type do not inherit?

Link to comment

Is it OK to put an Actor's "Internal Data" into its class control? or does it need to be empty?  I ran out of space on the actor diagram and had to make SubVIs to parse some messages and handle some follow on actions.   The internal data is a relatively big cluster and takes up a lot of space on the front panel of the SubVIs and could be cleaned up if it was a class wire.  Do you try to keep everything on the top level block diagram as good practice? 

Personally, I tend to look to see if some of the actor’s data should really include one or more classes, then my subVIs are methods of these classes.  I generally try not to have a class that is all the data of the actor, or have subVIs that pass in all the data (you’ll note I don’t even type-def the Internal-Data cluster).  I like the high-level actions to be on the top-level block diagram, but the details hidden in more specific subVIs that only act on part of the date.  For example, here is a Top-level actor that presents a picture to the User, showing a “pipeline†of analysis actors, where the User may modify the pipeline by adding, deleting, copying and pasting.  The code for copy/delete is shown.

 

post-18176-0-69634000-1459539141.png

 

post-18176-0-00664300-1459539161.png

 

This code is basically: If the User selects “Deleteâ€, then identify which icon was clicked on, write the deleted actor to the Clipboard (so the User has the option of pasting it elsewhere in the pipeline), and delete it from the Pipeline list of actors (calling "change pipeline.vi†to complete this).

 

There are three complicated bits of detail here, but they each only need part of the Internal data.  There is a method of the “Icon Picture†object that handles all the details of the picture (rather complex internally); a method of the (not so complicated) “Clipboard†object; and a subVI that acts on arrays of “Pipeline Component†Actors.  No subVI needs all actor data.   

 

BTW, the actor class here (your “Solo_Msg.ctlâ€) is actually serving as the address of the actor to external processes, so I wouldn’t try and make it do double duty as an internal-data store.  Instead, you could make a different class.  You could even have the actor’s caller preconfigure such an object and send it to the actor after launch.

Link to comment

Also opening another can of worms...do you often have parent-child inheritance situations where an actor inherits from another?  For instance, for an "instrument" do you have an abstract parent and implementation in a child actor or do you make the messages abstract (message names shared between the same instrument type) such as "measure" and "set range" and the actors of the same instrument type do not inherit?

 

I use composition instead of inheritance: actors with common behavior will all use some common class to get this behavior.  You can change the “Default†message case from throwing an error to calling a “Handle Message†method of some common class.  The “Pipeline Component†actor classes, in the example above, all contain a common class that handles common messages (the actors can “override†these messages by choosing to explicitly handle them).  Note that you can inherit off of this common class and inject different behavior to your actors by having the caller send the common class to the launched actors.

 

Below is an example that is as close as I’ve done to all-internal-data-in-one-object.  All this actor does is receive a “Graph Augmentation†object from it’s caller, then it passes all events on a graph to methods of this object.  It also passes any unknown message to the “Receive Msg†method.     “Graph Augmentation†is a parent class of several children that actually do things, and 99% of the work is done in methods of this class.   This is quite powerful, but it is also harder to figure out what is going on.  You would have an easier time understanding my other example, because you can see high-level stuff happening on the diagram.  Here it is just “Cursor Moved—> call 'Cursor Moved’ dynamic-dispatch method; Message Received—> call 'Receive Message’ DD methodâ€.

 

post-18176-0-91117600-1459541641.png

Link to comment

Hi James,

 

Hope you are well! Hopefully you can answer a question I have about your Messaging Library. I'm currently using it to try and implement some TCP communications (using your TCP messenger Library.) One problem I am having is trying to make multiple unique TCP event messengers (upto n), that can be serviced by a registering processes. This means the processes need to be able to register for them at run-time. I dont suppose you have any recommendations on how to acheive this?

 

EDIT: Looks like I was being really dumb here, I didnt notice the obs registry in the client... solution is clear now, but any recommendations feel free to make them!

 

Thanks!

Edited by df_rob
Link to comment

HI Rob,

 

Have you looked at the example code (and video linked to) here?  It’s a TCP example.   Standard Request-Reply and Register-Notify should work seamlessly over TCP (as the various TCP actors route the messages back over the connection) without needing to do anything special.

  • Like 1
Link to comment
  • 3 weeks later...

James,

I am your #1 fan!!

I noticed recently all the improvements you have made under the hood in the ObserverRegistry...

I have a request for you.  Will you include a vi in the queue messenger library that is simply queue status?   I've made this vi a time or two, to see if a actor gets behind,  the problem is that when I switch to a different computer, or update the Messenger library from the repository, this QueueStatus vi is lost......

 

Ben

Edited by monzue
  • Like 1
Link to comment
1 hour ago, monzue said:

 Will you include a vi in the queue messenger library that is simply queue status?   I've made this vi a time or two, to see if a actor gets behind,  the problem is that when I switch to a different computer, or update the Messenger library from the repository, this QueueStatus vi is lost......

Sure, Ben.  I haven’t needed such thing (yet) so I hadn’t put it in.   Is it just the number of elements in the queue that you need?

Link to comment
  • 3 months later...
11 minutes ago, drjdpowell said:

I am considering changing the LabVIEW version I develop Messenger Library in from 2011 to either 2013 or 2015.  Does this cause a problem for anybody?  Older versions would still be available through LAVA-CR.

Not for me, I develop in 2014/15 so preferably keep it in 2013 if you can. What's the reason for the upgrade, there a particular feature you want to adopt that's not available in 2011? Or are you simply abandoning older LV installs on your dev machine ;-)

Link to comment
2 hours ago, Thoric said:

What's the reason for the upgrade, there a particular feature you want to adopt that's not available in 2011? Or are you simply abandoning older LV installs on your dev machine ;-)

Bit of both.  My work code is 2015 (except for one 2013 client that I'll soon upgrade), and when I think I want to incorporate some of it into Messenger Library I am inconvenienced by the lack of some features I have used (such as the Concatenating-tunnel indexing option, or the "VI Deactivation" Event).  Spending time recoding to support LabVIEW versions that I don't intend to use doesn't make much business sense.  I don't think there is anything that 2015 has over 2013 that matters much, so I'll probably go to 2013.

 

BTW, did you finish your big comparison of frameworks?  If so, care to give Messenger Library a review on LVTools?

Edited by drjdpowell
Link to comment

I tested back-saving a significant feature that I want to add the Messenger Library, the "Graph Augment" UI stuff mention above.  Going to 2011 gave a long list of problems due to missing features (such as "Get Control Values by index"), but going to 2013 gave no error.

Link to comment
  • 2 weeks later...
  • 7 months later...

Dear James,

Recently I started to use your elegant messaging library, it is something I always wanted to have and even
invented my own wheel before I found what you have done.

Imagine I have 3 actors:

1. Launcher
2. Two instances of the instrument actor.

To make the code easy to read I use the message translator for each instrument. However when error
occurs in one of the instruments it goes directly to the 'Launcher' actor to its 'Error Handler'.

My questions are:

1.How do I know which instance of the Instrument actor triggered an error?
2.How do you handle errors in your multi-actor systems?

Thank you!

Kind Regards,
Max

Edited by Maksim Kuznetsov
Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.