Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

AF Style Question

It's been a while, since I have done much AF work. Just inherited a project that was written in AF.

 

It's doing some things that I find interesting and I wanted to see what others thought.

 

So certain messages, when executed (ie in the VI that is called by DO.vi) send a message to self. I thought that was interesting. Why do this? Why not just call the VI that the message executes directly? Seems very not atomic to me. Seems unnecessary to drop a message in the queue, when you can simply call the method. It also seems like having a queued state machine that self-enqueues. That always seemed like a bad idea.

 

Also, some of those same VIs send a stop message to self. Is that necessary? Why not just output error 43?

 

Thoughts?  Am I being overly critical? Is this a common practice among AF developers that I am just not aware of?

 

Also, another thing they are doing that is just curious. In the AF class, we are taught to launch nested actors in an actor core override. So I opened up the root actor (I could tell it was that actor b/c that is what was launched by the launcher) and it has no actor core override. Interesting. There are lots of other actors in the project and I was pretty sure they were getting launched somewhere. Figured out that all actors in this project inherit from some actor that has a post-launch init message (which is sent in the prelaunch init - so it is the first one in the queue.). That was where nested actors were getting launched from. Made sense once I figured it out. A little documentation would have helped there. Is this a common practice?

 

Also, the design relies on the post-launch init being the first message in the queue, but can you guarantee that? Any child class could override pre-launch init and drop something in the queue before calling the parent method - right? Am I thinking about that correctly?

 

I'm not sure I am going to change any of it, because a. it is already built and works and b. These particular VIs are part of a framework like reuse thing built on top of AF. That developer has moved on, so I guess I could rewrite all that, but the whole program appears built on that framework.

 

And if you are the person who wrote this (they are probably on this forum) - this is not meant to be critical but more curious and just to get a second opinion.

Sam Taggart
CLA, CPI, CTD, LabVIEW Champion
DQMH Trusted Advisor
Read about my thoughts on Software Development at sasworkshops.com/blog
GCentral
0 Kudos
Message 1 of 24
(3,488 Views)

By the way when it comes to the sending to self - I get the idea behind having an actor core override and sending messages to self from there, it's the sending it from inside another message method that seems weird and unneeded.

Sam Taggart
CLA, CPI, CTD, LabVIEW Champion
DQMH Trusted Advisor
Read about my thoughts on Software Development at sasworkshops.com/blog
GCentral
0 Kudos
Message 2 of 24
(3,469 Views)

@Taggart wrote:

 

So certain messages, when executed (ie in the VI that is called by DO.vi) send a message to self. I thought that was interesting. Why do this? Why not just call the VI that the message executes directly? Seems very not atomic to me. Seems unnecessary to drop a message in the queue, when you can simply call the method. It also seems like having a queued state machine that self-enqueues. That always seemed like a bad idea.

It is usually unnecessary; I would just call the VI directly.  If the previous developer does this all the time, I would suspect that they are adhering to the "actors respond to messages" paradigm a little too literally.  However, sending a message to yourself means the operation will be queued up after anything else that may already be pending, and there may be times to do that.

 


Also, some of those same VIs send a stop message to self. Is that necessary? Why not just output error 43?

This is one of those times where you might want to send a message to yourself, if you want to process all currently pending messages before stopping.  Return error 43 if you want to stop right now.

 


Also, another thing they are doing that is just curious. In the AF class, we are taught to launch nested actors in an actor core override. So I opened up the root actor (I could tell it was that actor b/c that is what was launched by the launcher) and it has no actor core override. Interesting. There are lots of other actors in the project and I was pretty sure they were getting launched somewhere. Figured out that all actors in this project inherit from some actor that has a post-launch init message (which is sent in the prelaunch init - so it is the first one in the queue.). That was where nested actors were getting launched from. Made sense once I figured it out. A little documentation would have helped there. Is this a common practice?

We actually teach that you can launch an actor from any method (except Pre Launch Init).  For nested actors that launch with your calling actor, Actor Core is a reasonable (and probably the most common) place to do it.  If you don't want a Actor Core, though, you need a different place to do it.  I've heard of people using a Post Launch Init in such instances.

 


Also, the design relies on the post-launch init being the first message in the queue, but can you guarantee that? Any child class could override pre-launch init and drop something in the queue before calling the parent method - right? Am I thinking about that correctly?

If you send a high priority message to yourself from Pre Launch Init, it's almost certain to be the first message you handle.  The only messages that will beat it are the two Critical Priority ones:  Emergency Stop and Last Ack.  Last Acks come from nested actors, and you haven't launched those yet.  Your caller *might* send an Emergency Stop in the narrow window between when your return from Pre Launch Init and start message handling, but if it does, so what?  You are e-stopping.

 

(If you send yourself a message in Pre Launch Init, and then launch an actor in Actor Core prior to message handling, I suppose you could get an E-Stop or Last Ack from the nested actor in that same narrow window.  If your message is to launch all your nested actors, you should be fine.  Any other message would need to allow for the possibility of getting one of those critical messages.  But you're writing your actor to gracefully receive any of its messages at any time, right?)

 

You correctly observe that you do run the risk of a child actor overriding Pre Launch Init and sending a *different* high priority message first.  You'd need to be concerned about that.

 


I'm not sure I am going to change any of it, because a. it is already built and works and b. These particular VIs are part of a framework like reuse thing built on top of AF. That developer has moved on, so I guess I could rewrite all that, but the whole program appears built on that framework.

If it ain't broke, don't fix it, unless or until it becomes a problem.  What you've described is perhaps not optimal practice, but nothing is obviously broken.

Message 3 of 24
(3,455 Views)

@justACS wrote:
If it ain't broke, don't fix it, unless or until it becomes a problem.  What you've described is perhaps not optimal practice, but nothing is obviously broken.

That's kind of where I fell on the whole thing. Just wanted to get a second opinion. Also wondering if maybe it's worth fixing some of these things just to make it easier for whoever comes after me. Or maybe I do that by just documenting it a little bit (for example the prelaunch init part) - maybe just that is enough.

Sam Taggart
CLA, CPI, CTD, LabVIEW Champion
DQMH Trusted Advisor
Read about my thoughts on Software Development at sasworkshops.com/blog
GCentral
0 Kudos
Message 4 of 24
(3,451 Views)

@justACS wrote:

@Taggart wrote:

 

So certain messages, when executed (ie in the VI that is called by DO.vi) send a message to self. I thought that was interesting. Why do this? Why not just call the VI that the message executes directly? Seems very not atomic to me. Seems unnecessary to drop a message in the queue, when you can simply call the method. It also seems like having a queued state machine that self-enqueues. That always seemed like a bad idea.

It is usually unnecessary; I would just call the VI directly.  If the previous developer does this all the time, I would suspect that they are adhering to the "actors respond to messages" paradigm a little too literally.  However, sending a message to yourself means the operation will be queued up after anything else that may already be pending, and there may be times to do that.




In general, I agree - just call the payload method VI directly. However, sometimes it might be useful to introduce the ability to break from the sequence of actions when you otherwise might not be able to if you had called all the VIs directly. That's my "guess". 😉

 


@justACS wrote:

@Taggart wrote:

 

Also, some of those same VIs send a stop message to self. Is that necessary? Why not just output error 43?

This is one of those times where you might want to send a message to yourself, if you want to process all currently pending messages before stopping.  Return error 43 if you want to stop right now.


In the AF course is it taught to just inject an error if you want to stop vs sending a stop message? That would seem odd to me if that were the case. Injecting a specific error code is way more abstract than enqueueing the Stop message and way less traceable, IMO.

 

CLA CLED AF Guild
Message 5 of 24
(3,436 Views)

@CaseyM wrote:

sometimes it might be useful to introduce the ability to break from the sequence of actions when you otherwise might not be able to if you had called all the VIs directly. That's my "guess". 😉

 

Injecting a specific error code is way more abstract than enqueueing the Stop message and way less traceable, IMO.

 


Very good points.

Sam Taggart
CLA, CPI, CTD, LabVIEW Champion
DQMH Trusted Advisor
Read about my thoughts on Software Development at sasworkshops.com/blog
GCentral
0 Kudos
Message 6 of 24
(3,425 Views)


In the AF course is it taught to just inject an error if you want to stop vs sending a stop message? That would seem odd to me if that were the case. Injecting a specific error code is way more abstract than enqueueing the Stop message and way less traceable, IMO.


Yep, that's what we teach.  Very explicitly, in fact, on a particular slide in the error handling lesson.  The Stop message does not invoke an actual method - its Do just returns Error 43, which we use as a stop code.  (Error 43 is Operation Cancelled by User.)  Absent a "stop actor" method, you have no other way of stopping an actor immediately, without processing any further messages.

 

A couple of slides later, I point out that you can change how your actor stops by changing its response to Error 43.

 

It is a little obscure, which is why we have to teach it.  It's not really any less traceable than invoking a VI to stop your actor.  In hindsight, adding a "Stop Actor" dynamic dispatch VI might have been a bit more clear, but that ship sailed a long time ago.

Message 7 of 24
(3,418 Views)

I would say the answer to most of these questions is that it depends.

 

Personally, I generally don't override actor core with any code unless it specifically needs to be in actor core (a UI or helper loop for example.) If my actor has startup behavior, I put it in pre launch init (specifically in a message that is sent in pre launch init.) Because pre launch init is synchronous, I never put any code beyond defining startup values, creating resources (like a DVR the actor uses), or sending initial messages here - so any real initialization will always be called through a startup message. In my opinion that is how pre launch init should be used - it should define the startup behavior of the actor. 

 

Regarding the question whether or not secondary methods should be called via message, it really depends. If that secondary method needs to be called directly after the first, then it should be called directly inside the first method. There are cases where that secondary message doesn't need to be called directly after, and in some cases you actually want to allow for other messages that may have been enqueued during the processing of the first part of the method to be able to be processed before getting to the second call.. I don't think you can really make a hard and fast rule here, rather just make sure you understand the behavior - that if you are sending a message to yourself you have no idea where in the queue that message is - and, your actor might stop before getting to that second message, so it better not contain anything that needs to happen. Generally speaking, I think its much clearer and safer to just directly call the second method, unless you explicitly want other messages to be available for processing first. 

 

I don't see any reason you would always want to launch actors in actor core - you can't launch actors in pre launch init, so I am guessing that would be the default place to launch them if you wanted to launch the nested actors as the actor's first operation, but personally I would say that should probably be in a message that gets called from pre launch init. 

 

Regarding the error 43 output, I did that for a while but the main problem with that is that you lose the error handling on the method you are executing. Maybe you don't care because you're stopping, but generally speaking I would prefer to capture the error in my logs, then stop, just so I am aware of the fact that the error occurred. Also, if you have an override of receive message where you're logging the messages you received (or anything similar) it can be helpful to see the explicit stop message rather than having your actor randomly stop because a method returned error 43. I think you could make arguments either way with regards to this particular one, and the error handling strategy of your actors should also play a part in the decision. After doing it both ways, I lean towards sending the stop - I think the intended behavior is more obvious, especially for those who aren't super familiar with AF. 

Message 8 of 24
(3,389 Views)

> Regarding the question whether or not secondary methods should be called via message, it really depends.

 

But be strongly biased toward "just call the method". Messaging yourself has tons of downsides that aren't worth it unless you're actually designing for that intentionally. I don't generally have to teach people that because it's annoying enough (two nodes [self enqueuer + send] vs one node [direct method]) that most people just make the direct method call anyway.

 

Self messaging is generally only if you're posting a message with a time delay or something like that. In general, Send calls to self don't belong inside message handling.

0 Kudos
Message 9 of 24
(3,384 Views)

> In hindsight, adding a "Stop Actor" dynamic dispatch VI

> might have been a bit more clear, but that ship sailed a long time ago.

 

There's some not-small downsides to that approach because it stores state in the actor. We needed some sort of return value to signal stop, and it made no sense to add another terminal to every Do.vi to be wired with False... especially when any error returned ought to stop the actor. [In hindsight, I shouldn't have made Handle Error.vi be dynamic dispatch... there should've been a Log Error.vi that was a no-op in Actor that children could override.]

 

Once we realized that we needed a stop signal return value, it made sense to have it in the error cluster. The bigger mistake was reusing error code 43. That should've been unique, just like emergency stop. Ah well. Lessons learned for binary-breaking AF 2.0 someday.

0 Kudos
Message 10 of 24
(3,380 Views)