Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Retrieving Actor Data from Handle Last Ack Core

I had a wild idea to be able to decouple two actors and reuse a piece of code anywhere.

 

In my application I have an Actor A (UI) and an Actor B (Database Interface).

 

ZCM was something I was looking at for the messaging scheme in this application, however, I also thought about the lifetime of Actor B. 

 

Actor B will do the following:

Start up (open DB Connection)

Perform operation

Shut down (close connection)

 

Actor B will be launched by Actor A along with an SQL String command to perform. 

 

Instead of having Actor B send a msg back to Actor A with the data, could I instead retrieve the database data from the Handle Last Ack Core vi, this would be completely decoupled and allow for flexibility of use, no?

 

The database supports concurrent connections so launching multiple independent actors is not an issue. 

 

I have also thought about if multiple sessions to the DB were open, I could use something like the GUID hash embedded in the class data to identify each session to make sure data didnt get jumbled up.

 

Feedback, criticism? What are you nuts?

 

Appreciate constructive criticism, it is there to help you succeed.
0 Kudos
Message 1 of 3
(1,530 Views)

I would just use an abstract method defined in the DB actor. I think it'll actually reduce coupling more than having to manually decipher a Last Ack message. That seems like a very tight coupling, but on the Actor A side, since you'll have a whole actor class object you'll have to interact with. If you change your database actor, you'll have to update how Class A interprets the data. The DB actor will be decoupled, but *all* callers will be coupled to it by needing methods to "unload" the data. It's doable, but still lightly coupled.

 

It seems that it's quite likely that the DB actor will need to return a message when called. Try this for a zero coupling message:

 

-In your DB actor, create a new message class with a string payload (or struct, or whatever you'd like to use to represent your reply). Let's call it "Result Msg.lvclass"

-Delete the Do.vi that gets created. Now you'll have just Send Message.vi.

-Add this message class to the private data of the DB actor.

-Create a custom "Launch actor" that has a requirement that the upstream actor wires in a value for Result Msg.lvclass, which goes into the private data of the new actor. (This is optional; you could just use a class constant and a Setter, but having a "Launch actor" VI makes it simpler to enforce that this class MUST be launched with a message added. You'll see why in a minute.)

-In the DB actor, when it finishes doing its operation, add a Result Msg::Send Message VI. Here you must wire in the Message Object to be the Result Msg from the class's private data, and the value for the message to send is your payload. The enqueuer is just the caller's enqueuer.

 

(If some of this isn't precisely perfect, forgive me- I don't have the actor framework open and I'm going from memory)

 

Think about what you have here now. Your database actor is now complete. When it finishes its task, it will take its data and build it into a message, then send it to its caller. However, there is no Do.vi function (in other words, no method for it to call when the message arrives) so it won't work at all by itself.

 

Next we'll get the caller ready (the GUI, or Actor A). It already knows it's calling the DB actor, so it's already "coupled" in that sense. Since it's calling the actor, it'll also know what kind of value it expects the actor to return- a string (or struct or whatever). Now do the following:

 

-Create a method within Actor A that will handle the database results. Just wire the database result as a control on its front panel; we'll actually retrieve this data in another step. Just pretend it's magically available for you. Say you want to display it to the user; just have this method take the database result string then put it in a string indicator. Or process the data. Or do whatever your GUI does with database results.

-Create a message class for this method.

-Delete the Send Message.vi that just got created. Now you have an orphaned Do.vi with a method, but no way to send the message.

-Change the inheritance of this new message to the Result Msg class in the DB message class.

 

Now consider where you are: you now have a full message class containing a Send Message *and* a Do.vi. The message class you defined earlier with no Do.vi is called your Abstract Class, and the message class you made second with Do.vi but no Send is called your Concrete Class. The concrete class uses the abstract Send Message to send the class, but the concrete Do.vi to complete the method.

 

Tying it together:

 

-Within your GUI actor, when you launch the DB actor, use the custom Launch DB actor VI you created earlier. Wire in your new class to its Message Object terminal you created.

 

Now you have a zero coupled message that's VERY reusable. Consider this:

 

-Your DB actor, in a general sense, knows it must send data somewhere. It never knows what to actually do with that data. Thus, it isn't coupled. Since you KNOW it'll need to Send data, it has a Send Message function. Since it does NOT know what to DO with that data, it does not have a Do message.

-Your GUI actor (or any other actor that calls your DB actor!) will never "send" this data; it only receives it. It DOES know what to DO with the data it receives. Thus, the caller will have a Do.vi (and thus a method to "do") but it will NOT have a Send Message.

 

The two together make this work, and it's VERY flexible. Let's say your GUI actor isn't working quite right, so you want to isolate it from the database actor. You can build a whole "database actor" that acts like the normal DB actor, but pops up a window so you can type a manual reply message. As long as you call a "Send message" VI in there, your caller actor will never know the difference.

 

Ah, you say- you can do all of this with the Last Ack method! Just make an abstract "Database" actor with children of "SQL Database" and "Debug Database", implement the methods as abstracts in the Database actor, and you're good to go. No coupling involved! Well, you'd be right, and it'd work just fine. Until one day you have to implement "Really Slow to Connect Remote Database", and you say, well dang, it sure would be nice to connect once at the beginning of the program and disconnect at the end. Unfortunately with the Last Ack method, you can ONLY ever retrieve data when the actor dies, so you have to really restructure your program. With the message-based approach, you can keep the actor alive the whole time (if you want) or kill it after each message (if you want).

 

Either way you will need to handle a message. Either you can use Last Ack, which means you have to handle the Last Ack message, look up the enqueuer to figure out which message it came from, then cast the actor to the right type, then call a method to unpack the data, then make sure the actor didn't send Last Ack because it couldn't connect to the database, OR you can just give the correct message to the DB actor so it knows what to send, then process it like a normal message, leaving Last Ack for sending when there was an error. Honestly both will work, but it seems like Last Ack will be more complicated.

 

This method also works wonderfully for things like a data acquisition actor. It can sit there acquiring data and piping it into its Send Message function, and it'll never know where the data goes or what it does, as it lets the caller decide what specific message to send.

 

I hope that helps. Your Last Ack will work but it will hamper your ability to send more than one reply, and you'll have to do a lot of manual casting of Last Ack message payloads to figure out the data. The zero coupling approach will be faster to execute (since dynamic dispatch is faster than downcasting), faster to code (since you're using automatic message generators), and more flexible.




Heads up! NI is moving LabVIEW to a mandatory SaaS subscription policy, along with a big price increase. Make your voice heard.
0 Kudos
Message 2 of 3
(1,510 Views)

And for some further reading and discussion, check out this wonderful thread:

 

https://forums.ni.com/t5/Actor-Framework-Discussions/Need-a-more-detailed-explanation-of-quot-Zero-C...

 




Heads up! NI is moving LabVIEW to a mandatory SaaS subscription policy, along with a big price increase. Make your voice heard.
0 Kudos
Message 3 of 3
(1,508 Views)