Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

"Acceptable" or extremely "low risk" situations for the use of synchronous messaging?


@Taggart wrote:

Stephen is very smart and has thought about this a lot. He is the AF guru and this is the AF channel, so I would probably listen to him.

 

Someone needs to be contrarian though, so I'll pick up the mantle.


I also feel like a very similar situation. Where I believe AQ (and others) are way more informed than I am, and that my perspective might be wrong for others, or even myself.  But my Actor style asynchronous running workers, are by default synchronous, with asynchronous being an option. The example I usually go to is that when I want to read DAQ data from DAQmx, then log it, I typically don't want this to be asynchronous.  I want to call the read, wait for the data to be read, then once the data is returned do stuff with the data.  I feel like this only makes more sense when something like a relay or switch matrix is used to control where a read will get it's data from.  I request a relay to be turned on then wait until it has been turned on.  Then once the synchronous process of turning the relay on is complete, I request the read of the DAQ.  This feels like it should default to synchronous.  SubVIs and dataflow are synchronous, and maybe LabVIEW changed my brain to think this way. 

 

Is that Actor that perform the read request waiting while the relay is being turned on? Well sure, but the Actor in this case is a higher level actor like a sequencer, which is waiting for the data, and doing nothing else until the data comes in.  It is by design sequential.  After it reads the data and figures out what it wants to do with it, it goes to the next step in the sequence, calling the next thing to be done.  Calling the sequence to be started should be asynchronous. Calling data to be written to disk should be asynchronous.  In some rare cases I have implemented a type of Futures into my Actors where multiple requests can come in from different locations, and then when it gets what it wants it will send the corresponding data to where it belongs, but even this is fairly rare for me and typically only used on something like a get status request which could probably be handled differently.

 

The benefit of this design is absolutely that requests go down the hierarchy, never up.  Now we can avoid circular dependencies too since all the lower level Actors depend on no one, and the higher level ones only depend on those under them.  Actors are also not spun up or down.  They are just normal VIs when one instance is needed, and Reentrant with N Actors when needed.  This also means I can open up their front panels on Real-Time and see what is happening and interact with the UI for debugging. With the Web Publishing Tool now my Actors can then be controlled in a web browser on these RT targets too.  These same VIs then run the same on Windows and can be interacted with.  One limitation is that on RT reentrant VI front panels aren't accessible but they are on Windows.

 

Maybe my designs are too simplistic.  Still I'm loving the discussion and am glad to learn more about other peoples' designs.

0 Kudos
Message 21 of 25
(402 Views)

@D_Hooks wrote:

 

The way I've often seen it coded up is the Autofocus actor sends a message intended for XYZ Stage to move, then sets a state enum in its private data to "Waiting on XYZ Stage Update". When a stage update message arrives at the Autofocus actor it might need to check the contents to see if the update was sent after the move was requested, if the stage is stopped, if the z-axis position matches the requested position (maybe within some limits?), if the x-axis and y-axis positions have remained unchanged, etc.


An aside on the Messanging Pattern "Request-Reply (Async)":

It sounds like you have the common problem of using Notifications to make up for the lack of true Reply messages (async ones, at least).   You have a stream of "status" messages and need to determine which status is after the handling of your Request.  This can be a lot of work and has a lot of potential difficulties.  A true "Async Reply" message is a lot easier.  Replies can be illustrated with email, which supports async replies.  For example:

 

From: Autofocus

To: XYZ Stage

Label: "Move to Postion (For Autofocusing step=5)"

Body: "X=...,Y=...,Z=..."

 

From: XYZ Stage

To: Autofocus

Label: "Re: Move to Postion (For Autofocusing step=5)"

Body: "Done"

 

Note that it is entirely obvious that the second message is a reply to the first.  And the reply contains info set in the Request ("For Autofocusing" and "step=5") that let's Autofocus know what to do with the returned info.  We don't need any checks to determine which of many "At Position" notifications is the "right" one to respond to.

 

I'm sure this can be done with Actor Framework.  I would imagine the Request message would contain the address of the Emqueuer of requesting Actor and a Message object to send in reply, with that object pre-configured with attached info like the "Step=5".   In Messenger Library, the Request might be sent like this:

drjdpowell_0-1732008962373.png

 

 

Message 22 of 25
(361 Views)

@AristosQueue wrote:

And there's the bug from AF perspective. There is no "A passes to B passes to C where Main can message all three directly".


The value in these discussions is how to it can bring out better understanding in the consistent sets of design principles.  This discussion started with just the question of Synchronous messaging, but that can't be answered separate from other principles.  So AQ is using this set:

  1. Strict tree, where callers broker all message flow between subactors
  2. No Sync messaging whatsoever.

Those two are a package deal.  Follow them together, if you follow one then follow the other.  

I was describing a different set:

  1. Calling actor sets up and "manages" the message flow between subactors (the "work"), but does NOT participate in that message flow
  2. Calling actor can use Sync messaging to manage the subactors.

Those two are also tied together.  It is only because the Calling actor is not participating in the actual work of the subactors, that can it synchronously manage the workers.

 

Now I think about it, I do actually switch to async-only in cases where the Calling actor does have to both manage a subactor and participate in the "work" messages.  Messenger Library has a full set of async messaging patterns, including "Scatter-Gather" which is a multi-actor version of asynchronous Request-Reply.  BUT, I do find that anything more than the simplest of cases the async version is a lot harder to follow**.  Synchronous, being basically subVI calls and dataflow, is just so very easy to read.

 

**A way past this complexity is to perfect an async shutdown of subactors (stop the "work"), make managing changes synchronously, then restart.  The Actor Framework is powerful for this as you can stop actors, reconfigure their actor objects with standard method calls, then relaunch them.

0 Kudos
Message 23 of 25
(325 Views)

@AristosQueue wrote:

If you abandon the tree structure, yes, I agree, the state of the whole system is nearly impossible to define. 

AristosQueue_0-1731935713426.png

 


Homework for me is to better make explicit why I can understand AQ's point here (such as an event at A affecting C via two paths, thus in undefined order) yet am unaffected by it.  What design principles am I using that prevent this being a problem for me?  Can I put this into words?

0 Kudos
Message 24 of 25
(315 Views)

@drjdpowell wrote:

@D_Hooks wrote:

 

The way I've often seen it coded up is the Autofocus actor sends a message intended for XYZ Stage to move, then sets a state enum in its private data to "Waiting on XYZ Stage Update". When a stage update message arrives at the Autofocus actor it might need to check the contents to see if the update was sent after the move was requested, if the stage is stopped, if the z-axis position matches the requested position (maybe within some limits?), if the x-axis and y-axis positions have remained unchanged, etc.


An aside on the Messanging Pattern "Request-Reply (Async)":

It sounds like you have the common problem of using Notifications to make up for the lack of true Reply messages (async ones, at least).   You have a stream of "status" messages and need to determine which status is after the handling of your Request.  This can be a lot of work and has a lot of potential difficulties.  A true "Async Reply" message is a lot easier.  Replies can be illustrated with email, which supports async replies.  That's an interesting point. I was definitely thinking along the lines of Notifications instead of Replies.

That's an interesting point to think about. The use case I was describing is definitely using Notifications instead of Replies.

 


I'm sure this can be done with Actor Framework.  I would imagine the Request message would contain the address of the Emqueuer of requesting Actor and a Message object to send in reply, with that object pre-configured with attached info like the "Step=5".

Actor Framework does have a built-in ability to create and send self-addressed messages, using the Address Message and Send Self-Addressed Message VIs. I've always shied away from using those VIs though, since they would short-circuit the messaging tree in most cases.

 

It would also be possible to create specific response messages sent from an actor performing an action, while still adhering to the messaging tree. More like "Stage Z-Axis Move Complete," as one of many Reply messages in an outgoing interface for the XYZ Stage Actor, rather than just a single "Stage XYZ Update" Notification. Depending on how these need to be propagated through the messaging tree you could very well end up with a lot of API and message class bloat though.

 

It's all tradeoffs of course, but I can definitely see where the "jumping through hoops" complaints come from. 

0 Kudos
Message 25 of 25
(237 Views)