Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Issue with abstract messaging to remote machine using Linked Network Actors

Solved!
Go to solution

Hi,

 

I am working on a project that has firmware running on an RT PXI controller (Remote) and a UI on a host PC (Host). I want the Remote to not depend on the Host. This is because the UI code makes extensive use of subpanels and the RT refuses to compile when subpanel references are found in dependencies.

 

The Remote needs to periodically send messages to the Host, but the Remote cannot have knowledge of the methods available on the Host (to avoid dependency). So I am using abstract messaging, where the Remote is told the implementation to use when sending messages to the Host at run-time. In short, the Host connects with the Remote and sends a message containing its concrete implementation of the Remote's abstract message. So only the Host is dependent on the Remote and not the other way around. This is one-way dependency, as opposed to the two-way sort that typically exists for Actors that send each other messages. So far so simple!

 

A complication is that I am using Linked Network Actors (LNAs) to intermediate the messaging between the Host and Remote. LNAs are nice because they provide a handy interface to Network Streams. I use Send Transmit Network Message to enqueue a message into a remote Actor's queue.

 

This works when the Remote and the Host are running on the same machine but this does not work when the Remote is running on my RT PXI target and the Host is running on my local machine. NB I am using LNAs both times. Please see project files below to see the two situations. 

 

I have debugged this issue for a day or so now and am stuck. Advice is welcome!

 

So far I have determined that the problem appears to occur because the Remote does not interpret the concrete implementation correctly:

  • The LNA appears to convert the message containing the host's concrete message to the generic Message type. As a result, the Remote Actor then does not perform the Write Concrete Implementation method. So the Remote cannot tell the Host to run the concrete Implementation.
  • Sending the abstract parent message, rather than the concrete child message, does get passed properly to the Remote Actor! But the RT does not then have a concrete implementation to call on the Host.
  • I can send simple messages to the Remote from the Host with no problems at all. This issue only seems to occur with messages that contain messages, on the RT.

I would like to see if the problem occurs with all messages that contain messages or just those that contain concrete child messages. But I have run out of time today!

 

PS I am using LV2018, but have saved the projects in 2015 for reference. These projects are dependent on LNA, to run the project you will need to download it from the relevant forums pages

CLA - Kudos is how we show our appreciation for comments that helped us!
0 Kudos
Message 1 of 14
(4,117 Views)

 Good morning MaxJoseph,

 

Instead of using Linked Network Actors, try using Network Endpoints instead.

See this link on how you can get them and how to implement. 

 

https://forums.ni.com/t5/Actor-Framework-Documents/Network-Endpoint-Actors/ta-p/3525072

 

I too tried with Linked Network Actors a few years ago and had nothing but headaches. Once I learned Network Endpoints, I never went back.

 

In fact, Network Endpoints is the tool that is utilized during the Actor Framework class when discussing distributed network actors. 

 

 

Steven R. Howell
A&T Sr. Electrical Engineer

3000 N Sam Houston Pkwy E
Houston, TX 77032-3219
steven.howell@halliburton.com
Message 2 of 14
(4,098 Views)

Let me see if I can help here.  I wrote the original LNA, which is now deprecated in favor of its replacement, Network Endpoints.

 

Abstract messages don't really work across a network boundary.  The sender has to have the correct child class instance loaded into memory, which of course creates the dependency you were hoping to avoid in the first place.  You'll have to do a little more work.

 

I have a presentation on inter-target communication called Inter-Target Communication in Actor Framework.  I talk about how to use Network Endpoints, including a way to properly decouple your host and remote.  The whole video is about 43 minutes, but you'll get what you need in the first 15 or 20.  (But do watch the rest; Launch Remote Actor doesn't get enough attention IMO.)  The techniques I discuss are also covered in the Actor-Oriented Design in LabVIEW, the official course on AF.

 

Anyway, check out the video, and post back here if you have any questions.

Message 3 of 14
(4,093 Views)

The latest version of Network Endpoints is on the LabVIEW Tools Network, and you can download it with VI Package Manager.

0 Kudos
Message 4 of 14
(4,091 Views)

Ah, thanks for the replies Allen and Steven! It sounds like I shouldn't have just picked the first relevant sounding module I found for my inter-actor remote network communication!

 

I will review the video and the Network Endpoints module. Unfortunately I have now given up my work laptop for the Xmas break, so I won't be able to test anything until January... I feel like a young kind filled with anticipation, how seasonally appropriate! Maybe I can sneak a look on my home PC... time to dust off that evaluation license...

CLA - Kudos is how we show our appreciation for comments that helped us!
0 Kudos
Message 5 of 14
(4,068 Views)

Hi again all,

 

I eagerly downloaded the Network Endpoints addon and tried it out on my test code on my local PC over the holidays. It worked flawlessly! I then had to wait until today when I am back at work to try with the remote PXI controller. It does not work!

 

I can successfully pass a message (where the payload is a concrete implementation of an abstract message) to a 'remote' recipient when that recipient is on the local machine. I cannot pass this same message when the recipient is on a remote machine. When the remote receives a message within a message like this, it appears to generate an Report Error Msg.

 

I can pass simple messages to the Remote over the network using Network Endpoints without any problems, even when the remote is on another machine.

 

I suspect the problem is in the Unflatten From String in NetworkStream:Receive Message or the Flatten to String in NetworkStream:SendMessage in that they are not properly interpreting the message within a message. But this is just a hunch, I can't really interpret the strings that come out of these functions!

 

It strikes me that this sort of thing; trying to avoid dependency by sending children of abstract messages across a network, must be fairly common. So I assume it is my implementation that is wrong, rather than the addon itself. Can anyone recommend a way forward?

 

Many thanks in advance!

 

Max

CLA - Kudos is how we show our appreciation for comments that helped us!
0 Kudos
Message 6 of 14
(3,971 Views)

@MaxJoseph wrote:

It strikes me that this sort of thing; trying to avoid dependency by sending children of abstract messages across a network, must be fairly common. So I assume it is my implementation that is wrong, rather than the addon itself. Can anyone recommend a way forward?


This issue has been discussed before.  See Decoupling message based systems that communicate across a network.  My answer is to use "envelopes": messages for a recipient that contain, rather than inherit from, the sender's message.  This allows one to avoid needing to have the recipient's message classes loaded in memory on the sending machine (which I assume is the problem you are having).  I do not know if any AF practitioner has implemented this, though.   

0 Kudos
Message 7 of 14
(3,915 Views)

Thanks for the reply drjdpowell. I raised a service call with NI about it and the agent pointed out that the problem, like so many in life, was entirely of my own making.

 

In short the problem occurs when the Remote tries to unflatten the message that contains the concrete implementation sent from the Host. Since the Remote does not have the concrete class loaded into memory, the unflatten fails. To be fair the concrete class is a class of the Host that is not loaded on the Remote at compile time. In other words, the Remote has no way of knowing this message will come in and so is unable to handle it when it does.

 

The reason the Host and Remote abstract messaging ran when everything is on the host PC was because they were in the same project. In this case the Remote has access to the Host's classes and can unflatten successfully. A fairer test would have been to put the Host and Remote in two separate projects. In this case, the messaging fails for the same reason, that the Remote is unable to unflatten the message. I should have used separate projects as a better representative of the two remote systems in my testing.

 

In terms of solutions; I am looking at defining a proxy interface that the Host and Remote either have (associate) or are (inherit). I will have a go this morning and report back...

CLA - Kudos is how we show our appreciation for comments that helped us!
0 Kudos
Message 8 of 14
(3,905 Views)

Yes, that's the problem I thought you had.  I believe some kind of proxy is what other AF people have done, but to me this seems excessively complicated and work intensive for what should be a very simple thing: having the sending code not care what the receiving code does with a message.

0 Kudos
Message 9 of 14
(3,900 Views)
Solution
Accepted by topic author MaxJoseph

Hi all,

 

I have implemented a solution to my problem, with help from NI support. The solution was not to use Network Endpoints in preference to Linked Network Actors. My problem was due to a fundamental misunderstanding of how remote actors cannot cast to more specific if they do not know what the specific is. I thought (for some reason) that this was possible and assumed my 'positive control' code was fair. The positive control was flawed, and when I changed my code to make it fairer, the scheme broke in the predicted way.

 

The solution uses a proxy, a pair of Interface actors that sit between the Host and Remote. The Interface actors themselves call and link Network Endpoint actors to communicate over the network. Messages are sent using the parental Interface message class, and the do that is executed depends on which child receives the message.

 

 

The attached file has a few projects in. Users should be able to open both the Remote and Host projects separately. See that there is no dependency between Host and Remote, only to the Interface class. Run both launchers and then enter an input into the Remote's string control. See that the Host string indicator has changed.

 

Here is a sequence of events.

 

Remote: Changes to the string control sends a Send String to Host message to the Interface Remote-side actor.

Interface Remote-side: A Send String to Host method sends a Send String to Host message to the Network Endpoint and then on to the connected Interface Host-side.

Interface Host-side: The Send String to Host method sends an Update String message to the caller (which is Host)

Host: The Update String method causes the string indicator to update.

 

This achieves my objective, but like drjdpowell says it is a bit labour intensive to make the override methods in the Interface children. I can sense this would become very boring very quickly for a large interface. Maybe I should learn scripting?

CLA - Kudos is how we show our appreciation for comments that helped us!
Message 10 of 14
(3,852 Views)