Recommended Posts

I just use the message translation for errors, as well as other messages. There is more than one way to do it; a simple way is to just register for all errors and relabel the messages. For example, here I launch a "Simple UI" and relabel its error notifications as "Simple UI --> Error". Then, in the case that handles that error (as well as differently-named error messages from other actors, I just attach the message label the the error description, so that the User knows where the error came from.

Then, in the case that handles that error (as well as differently-named error messages from other actors) I just attach the message label the the error description, so that the User knows where the error came from.

Share this post

Link to post

Share on other sites

Your solution makes sense and it works nicely for errors that occur in the sub-actor when there were no
messages sent to it (error triggered inside by some other events). However, imagine the main actor is registered
for all errors with a translator and I send a synchronous request to it:

The request potentially could result in an error which will go directly to the error handler, but since
the main actor is also registered for all errors it will get another message with the same error.
Basically, the error gets reported twice.

Similar thing happens when there is an asynchronous reply coming into the main actor containing an
error:

In this case I receive an error by a separate message (registered for it) and also as a reply
to my asynchronous request.

Both messages will have different labels, one is 'Inst 1 -> Error' another will be 'Inst 1 --> Reading'.

I spent couple of days thinking of the way of handling errors in one place, because my system is designed
to act autonomously on some particular errors, on other to ask user what to do. I still can't think of the
elegant way of doing this.

Share this post

Link to post

Share on other sites

Ah, so the issue is that an actor both replies with an error message, and publishes one. One possible solution is to say that only one actor should “own" the error. If actor_a asked actor_b to do something, and an error occurs, then actor_a is the one responsible for handling/reporting it. You can do this by changing the error handling case to only publish the error message if their was no return address attached to the original request message. Thus you Reply OR Notify, rather than Reply AND Notify, and there is only one error message.

Share this post

Link to post

Share on other sites

I was trying to code a project in C#, and I was looking for a C# library that would be similar to what you have here. Do you know of any? Is there a library that is the inspiration for this messenger library?

Share this post

Link to post

Share on other sites

I was trying to code a project in C#, and I was looking for a C# library that would be similar to what you have here. Do you know of any? Is there a library that is the inspiration for this messenger library?

I can't speak for him, but the concept of queued actors has been around for a long, long time. The two c# actor-type frameworks I'm aware of are:

http://getakka.net/
Which is based off the java framework of the same name (about a decade old now), which in turn was inspired by erlang (30 years old). Akka seems to be extremely popular, and their website has an obscene amount of documentation.

https://dotnet.github.io/orleans/
Is slightly unique in that its intended for distributed systems (their claim to fame is that various xbox game services like halo 4 and 5 use it). Similar to this is http://proto.actor/docs/what is protoactor but this protoactor project seems to have the advantage as far as minimizing dependencies...but its also much much newer and not backed by microsoft.

Share this post

Link to post

Share on other sites

Not really an “inspiration”, but I do try to study Akka, and it does have similar concepts to Messenger Library, and seems one of the most popular “Actor” frameworks, so if there is a C# version of Akka then that seems a good route.

Share this post

Link to post

Share on other sites

Looking at the orleans framework actually brought me to ask this question, because I couldn't tell if that framework supported a Messaging queue, or if there was any way to determine the number of messages in the queue.

Share on other sites

Looking at the orleans framework actually brought me to ask this question, because I couldn't tell if that framework supported a Messaging queue, or if there was any way to determine the number of messages in the queue.

I had a brief look at Orleans last night. Very interesting, but it brings up a warning. Most “actor” programming out there has been developed to handle distributed software-only applications on large numbers of interchangeable servers. Think 20,000 Halo5 players and 2 or 3 Microsoft server farms. We, in LabVIEW, are more likely to be dealing with a small number of not-at-all-interchangeable pieces of physical hardware. We don’t have the option of handling an error by restarting to finish the job on a different server. So the features of Orleans “virtual actors” sounds very interesting, but not necessarily that applicable to hardware-controlling applications. I would still look at Akka if I were not doing LabVIEW.

Share this post

Link to post

Share on other sites

I have a scenario where I'd like to use Messenger to send TCP messages between a LV 2014 machine/app to/from a LV 2016 machine/app. I started experimenting using the examples provided with the Messenger library.... Starting TCP Control Server (Messenging).vi on the 2016 machine and TCP Control Client (Messenging).vi on the 2014 machine. On startup, the first message from the client (2014) goes through to the server (2016) fine, but when the 2016 machine replies back the received message on the 2014 machine is not unflattened properly in the "Route Back Reply" case of the TCP Client Actor and returns an error 122:

Share on other sites

As far as I can tell, the reason is that variants are flattened to strings differently in every version of LabVIEW. Althoug the schema is the same, the actual version of LabVIEW is prepended in the flattened string. Thus, when a 2016 flattened string is passed to LabVIEW 2014 it does not assume to know the schema and throws error 122.

NI's white paper on using "Variant Flatten Exp", which allows you to set the flattening format structure, is their recommended approach. Thus you can set your 2016 code to create 2014-style strings.

Note: I think this only affects the flattening of variants. All other datatypes are unaffected.

However. I am still noticing differences between my 2014 strings and 2017 strings. For me, the issue is now down to the links to the typedefs controls in the clusters that I use. when flattening clusters (that contain variants) to strings, that are linked to typedefs, there is still a problem when passing between LabVIEW versions...

As far as I can tell, the reason is that variants are flattened to strings differently in every version of LabVIEW. Althoug the schema is the same, the actual version of LabVIEW is prepended in the flattened string. Thus, when a 2016 flattened string is passed to LabVIEW 2014 it does not assume to know the schema and throws error 122.

NI's white paper on using "Variant Flatten Exp", which allows you to set the flattening format structure, is their recommended approach. Thus you can set your 2016 code to create 2014-style strings.

Note: I think this only affects the flattening of variants. All other datatypes are unaffected.

However. I am still noticing differences between my 2014 strings and 2017 strings. For me, the issue is now down to the links to the typedefs controls in the clusters that I use. when flattening clusters (that contain variants) to strings, that are linked to typedefs, there is still a problem when passing between LabVIEW versions...

Hi Thoric,

Are you having the variant problem using Messenger specifically or just the same generic problem with flattening variants between versions of LabVIEW?

I took a little peak under the hood of the Messenger Library flatten / unflatten VIs and they have a U8 byte to define what items are present in the flatten data. Maybe you already tried this based on your message, but one possible workaround would be to embed the 5 bits of version data (would only work up to LV2020 ) from the white paper you referenced into the upper portion of the U8 in the messenger library. Not sure if drjdpowell would be up for that and not sure if the upper 5bits of that U8 are used for anything else since I only did a cursory check. Also the added version stuff on the front and backend would add overhead.

Share this post

Link to post

Share on other sites

I'm on holiday this week, sans LabVIEW, so I can't help. But question: is there a way to flatten to an older version of LabVIEW? So tell 2016 to flatten to 2014 format? I vaguely recall reading this. If so, we should be able to make usingly an older format an options, allowing communication with an older version of LabVIEW.

Share this post

Link to post

Share on other sites

My issue is not with Messenger, but with my own variant handling code between differing versions of LabVIEW.

The LabVIEW version data requires 8 bits, not just the top 5 bits. For example, LabVIEW 2012 is represented by x12008004. But if the Messenger library (built in LabVIEW 2013?) were to enfornce the same LabVIEW version format for all flattened data then they ought to be compatible across all instances.

I'm still battling to get this to work in my own code - I'm encountering problems associated with nested variants (A variant as part a few items in a cluster array, which is passed through a message which uses its own variant container), whereby the inner variant is always unflattened to empty. Might simply be that I have something mixed up somewhere, need to keep investigating...

Share this post

Link to post

Share on other sites

I'm on holiday this week, sans LabVIEW, so I can't help. But question: is there a way to flatten to an older version of LabVIEW? So tell 2016 to flatten to 2014 format? I vaguely recall reading this. If so, we should be able to make usingly an older format an options, allowing communication with an older version of LabVIEW.

Yes there is a way as to tell 2016 to flatten to 2014 (and lower) described in Thorics link above. Enjoy your holiday we can look at when you get back.

Share this post

Link to post

Share on other sites

My experience having used this technique in my own application (not Messenger Framework related, but nonetheless the same issue) is that it works without loss.

This flatten function honours any attributes within the variant. It does not, however, include a bitness setting, so you cannot set the bitness to your own choice. However, this shouldn't be an issue when passing data between Messenger actors.

There are, as far as I understand, no changes to the variant flattening syntax since LabVIEW 8.2, so unless something changes in the future there would be no loss of info using this.

Share this post

Link to post

Share on other sites

I'm thinking of modifying the TCP Messengers to optionally accept a LabVIEW version for use in flattening. Then you can set whatever version you need.

That sounds good.

Is there a downside to simply flattening to the lowest LabVIEW version Messenger Library supports? Based on my limited testing it seems like the unflattening in higher versions of lower versions works without code changes on the unflattening side. It might be less effort for you this way.

Share this post

Link to post

Share on other sites

I have a separate issue. When I load my project which uses Messenger toolkit, LabVIEW warns that the "Library information could not be updated". This pops up three times consecutively, yet once cleared everything seems to work OK.

I've seen this before, when I used Messenger library about two years ago on another project LabVIEW used to complain with the exact same notification (today that project loads without the warning).

I've only see this warning when I open a project using Messenger toolkit, so I think it's fairly safe to assume it's related?

I was wondering if anyone else had seen this behaviour? I'm using LabVIEW 2017 on Win7 SP1 currently, but two years ago it was on 2014 within a VM (still Win7).

OK - I did some deep digging, this issue has nothing to do with Messenger toolkit. Apologies.

Share on other sites

Is there a downside to simply flattening to the lowest LabVIEW version Messenger Library supports?

There must be something, otherwise why up-rev the format with each version?

Anyway, I’m thinking of having the the two TCP communication actors exchange two initial messages to tell the LabVIEW versions they are each running in, then have each use the lowest version for flattening. Then they will use the highest version available to both sides. If that is too much work I could just set the version used to 2011.

Link to post

Share on other sites

There must be something, otherwise why up-rev the format with each version?

James, I believe the risk is only with variants and there's actually been no change to their flattened syntax since LV8.2

A 2017 flattened string refused to be interpreted by older LV code is purely a precautionary act. However annoying it is one can understand perhaps the design intent.

So unless there are improvements in the NI pipeline for flattening variants then I don't believe there are any risks with forcing the version to the same as the Messenger toolkit source version (2011).

Share this post

Link to post

Share on other sites

Added a new version 1.8.4.85 to the Code Repository. Tested that this works between 2011 and 2017 using the TCP Client/Server example that comes with the library (with either side being the Server or Client). The TCP Connection and TCP Client actors now send an initial message to each other containing a flattened variant, and they each determine if the other is running an older LabVIEW version (if so, they use bean’s fix from above).

Note that this only affects the VariantMessage class. If you flatten Objects containing Variants then this won’t work, and I don’t know what happens if your VariantMessage contains a cluster that contains nested Variants. Please report any such problems, and we can look into a solution. Personally, I don’t tend to use Variants internally to other data structures, but I know others do.

Also note that both sides of the connection will need to be running this latest Messenger-Library version, otherwise the initial exchange of version messages will fail.

Link to post

Share on other sites

Added a new version 1.8.4.85 to the Code Repository. Tested that this works between 2011 and 2017 using the TCP Client/Server example that comes with the library (with either side being the Server or Client). The TCP Connection and TCP Client actors now send an initial message to each other containing a flattened variant, and they each determine if the other is running an older LabVIEW version (if so, they use bean’s fix from above).

Note that this only affects the VariantMessage class. If you flatten Objects containing Variants then this won’t work, and I don’t know what happens if your VariantMessage contains a cluster that contains nested Variants. Please report any such problems, and we can look into a solution. Personally, I don’t tend to use Variants internally to other data structures, but I know others do.

Also note that both sides of the connection will need to be running this latest Messenger-Library version, otherwise the initial exchange of version messages will fail.

Thanks for the mod

Sorry for peppering you with questions, but I have another one. I'm trying to connect to a remote server that may or may not be there. I want to have the capability to attempt and retry the connection in a non blocking fashion (since it may not be there at all). Since the default timeout is 5 seconds and timeout is not exposed in the Remote Service.vi a synchronous approach can hang for a long time. I tried creating an asynchronous remote connect lvclass in the attached example (mods your TCP client server example) that inherits from the Action.lvclass in your library. I am able to launch the remote service ok and establish a connection in the TCP Client Actor, but when the Async Execute.vi finishes, I think the messenger queue that was created during execute "goes bad" or is destroyed when the Async Execute.vi goes out of memory.

Share this post

Link to post

Share on other sites

Is the NI Service Locator not running on the remote machine? When I run the example Clients with no Server running, they quickly return error 1510: "The requested service was not found as a registered service with the NI Service Locator.”

The problem you’re having is because the TCP Client actor is launched as an “Autoshutdown slave”, meaning it will shut itself down when it’s caller dies. See below. As the caller is your short-lived Async Action, it shuts down immediately.

However, you don’t need an Async Action, as you already have an async actor (“TCP Client”). You just need an async Request-Reply instead of the sync Query currently used in RemoteTCPMessenger:Create.vi (see below). Replace the Query with a Send, and supply your own Reply Address. The TCP Client Actor will send you a reply (containing the string “connected” if it was successful, or an Error Message if it isn't). You can then decide to restart it if it failed to connect, or start sending messages if it did connect.

Let me know if this works, and I’ll make a Messenger-Library addition of an async way to start the RemoteTCPMessenger (I would do it in a slightly more complex way, where the RemoteTCPMessenger is returned in the Reply message, so there is no way to send it messages before it’s connected).

Share this post

Link to post

Share on other sites

The problem you’re having is because the TCP Client actor is launched as an “Autoshutdown slave”, meaning it will shut itself down when it’s caller dies. See below. As the caller is your short-lived Async Action, it shuts down immediately.

You just need an async Request-Reply instead of the sync Query currently used in RemoteTCPMessenger:Create.vi (see below). Replace the Query with a Send, and supply your own Reply Address. The TCP Client Actor will send you a reply (containing the string “connected” if it was successful, or an Error Message if it isn't). You can then decide to restart it if it failed to connect, or start sending messages if it did connect.

Let me know if this works, and I’ll make a Messenger-Library addition of an async way to start the RemoteTCPMessenger (I would do it in a slightly more complex way, where the RemoteTCPMessenger is returned in the Reply message, so there is no way to send it messages before it’s connected).

Replacing the query with a send and wiring in the reply address worked. I just temporarily created an asynch create VI (without dynamic dispatch to test).

If you are updating the RemoteTCP Messenger class, can you expose (make a datamember of the class) the timeout value the Actor uses during communication to the Remote Service.vi? It would be nice to be able to adjust this timeout if necessary.