ni.com checkout is currently experiencing issues.

Support teams are actively working on the resolution.

Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Request: lose the "Caller-To-Actor" and "Actor-To-Caller" language

I do love the idea of handling stops automatically. Managing sub-actors is code I've added many times and it seems like there should be a way of handling it automatically. But...

AristosQueue wrote:


Maybe that's an input on the Launch Nested Actor.vi? A boolean input for "Nested actor stops when this actor stops? (T)" , perhaps? Except it seems like something that a programmer might want to decide at shutdown instead of at launch.

No. Please don't do this. What happens if the stop condition varies with state or can't be predetermined? If stop is propagated automatically there needs to be an override mechanism.

I hope to follow up with ideas, but short on time for now.

0 Kudos
Message 51 of 66
(1,250 Views)

Daklu wrote:

What's the use case for launching a sub actor from a helper loop?  Launching sub actors from a loop other than the message handling loop (Actor Core) seems like a dangerous move for newbies anyway, since it opens the door to inserting a helper loop in an actor and sub actor's communication path, which leads to other tricky problems such as distributing an actor's state data across multiple loops.

Huh? No idea what you're talking about here. 

I'm talking about the difference between this...

Capture1.PNG

and this...

Capture1.PNG

Inserting a helper loop between the message handling loops (which typically maintain an actor's state data) of two actors makes it much easier to make mistakes, one of which is splitting the calling actors' publicly available state data among multiple internal loops.  Launching a sub actor from a helper loop (or appended loop in your terminology) makes the second scenario much more likely, especially among those who are trying to learn AOP and the AF.  Given you've stated one of your primary goals with the AF is to make AOP more accessable to less advanced developers by providing protections against common errors, I assumed you'd want to discourage the second scenario.  Hence my question regarding the use case for wanting to launch a sub actor from a helper loop.

Splitting it to another ongoing loop that maintains state (or, worse, gives the impression that it maintains state) is the problem. Forking it to read-only methods is more than fine.

Earlier you said, "...unless you forked the actor wire which you should NEVER do."  You, I, and others familiar with AOP understand that "NEVER" really means "you *can* do it, but it is dangerous if you don't know what you're doing."  As the AF is designed for those who are learning AOP techniques, it is beneficial to give them an API that allows them to follow the guidelines you have provided.  I'm just saying...

Ah. Thank you for reminding me why we don't do this already.

My point was that the asymetrical behavior was unexpected and violates the principle of least astonishment.  Since stops propagate up by default, it is natural to assume they also propagate down by default.  Either change it so stops will propagate down by default or change it so they no longer propagate up by default.  Doesn't matter which one--either choice is more intuitive than the current implementation--but given the target audience I assume downward propagation is preferred.

As for the actual implementation, I'm not familiar enough with the AF internals to design downward stop propagation.  However, I do have some questions...

1. Since you will be adding a new Launch Root Actor method and support multiple trees in a single app, is there still a use case for leaving nested actors running after the root actor exits, or are those use cases better supported by launching the ongoing actors as new root actors?

2. The Launch Sub Actor method Yair proposed will have access to both the calling actor, the launched actor, and the launched actor's enqueuer.  You should be able to build collections based on the subactors that have been launched.  Couldn't you maintain a collection of the enqueuers from all the launched actors and iterate through them sending each one a stop message?

0 Kudos
Message 52 of 66
(1,250 Views)

kegghead wrote:

I do love the idea of handling stops automatically. Managing sub-actors is code I've added many times and it seems like there should be a way of handling it automatically. But...

AristosQueue wrote:


Maybe that's an input on the Launch Nested Actor.vi? A boolean input for "Nested actor stops when this actor stops? (T)" , perhaps? Except it seems like something that a programmer might want to decide at shutdown instead of at launch.

No. Please don't do this. What happens if the stop condition varies with state or can't be predetermined? If stop is propagated automatically there needs to be an override mechanism.

I hope to follow up with ideas, but short on time for now.

I have a  "Nested actor stops when this actor stops? (T)" input on "Launch Actor" in my "Messenging" framework (though the terminal is called "Autoshutdown slave").  I almost always leave it at "True" so actors are triggered to shutdown when their caller stops for any reason (including Abort).  One can still shut the subactor down explicitly and thus not depend on the autoshutdown.  In my latest version of the framework, the subActor defines the message it receives if it's caller shuts down, so one could have it follow a different strategy for unexpected caller death than normally-signalled shutdown.

0 Kudos
Message 53 of 66
(1,250 Views)

AristosQueue wrote:

This came up a while ago (can't find the thread now) and the conversation petered out without action. But my memory is that we couldn't find a good way for an actor to designate which nested actors should stay running and still leave the general shutdown mechanism in the parent's hands.

Been thinking about this for a bit and I can't come up with anything dynamic. We already have a way of deciding at run-time (through overrides of Stop Core.vi) if an Actor needs to shut down a sub-Actor. The problem though is what of a mixed use case?

So maybe I'm coming around to an input to the Launch Actor method with a boolean flag. As I see it, when an Actor starts up a sub-Actor if this flag is set the sub-Actor's enqueur is added to a list. Should the Actor ever get a Last-Ack from a sub-Actor, the corresponding enqueuer is removed. When executed Actor.lvclass:Actor Core.vi will look at this list and send a stop message to anything left. Any sub-Actors which are not flagged are the responsibility of an Actor's implementation's to keep track of, much as we have today.

0 Kudos
Message 54 of 66
(1,250 Views)

Daklu wrote:

I wouldn't eliminate the Launch Actor (actor, caller's enqueuer) as suggested.  Seems to me it's still necessary for integrating AF code with non-AF code.

At first I thought that this isn't actually possible, as all the relevant pieces would be private, but looking at it shows that the palette does have a dequeue VI, which should in principle allow you to create a "static" actor, which is basically a loop duplicating the actor core functionality, similar to what you have in your framework. I don't *think* that having a controlled caller enqueuer would be useful in any other case, but I'm not familiar enough with the AF or the various use cases to say.

I'm not sure what I think of this, because while in priniciple I agree with the concept of static actors, since they're much easier to understand, I'm not sure that this should be something that's allowed, as having the framework expose its internals so that users can use them makes it more difficult to understand (and in fact it's possible that some of the existing VIs on the pallete, like enqueue and dequeue, should be removed. Dequeue would be handled only by actor core and enqueue would be created only by the message maker). I would say that if static actors should be allowed, then ideally it should be something which is basically a static wrapper for actor core, or maybe you need two VIs - one for launching, which returns the enqueuer and another as the wrapper for the core. That said, I haven't thought this through and this is probably a whole separate discussion on its own and we should not have it in this thread.

I would suggest that if communicating with non-actors is needed, then it should probably be limited to reporting something like last ack from the root, and then maybe there should be a special VI just for waiting on that.

Again, this entire thing was basically stream of consciousness. Sense is not guaranteed.


___________________
Try to take over the world!
0 Kudos
Message 55 of 66
(1,250 Views)

AristosQueue wrote:

So I'd suggest adding one more standard piece:

          Launch Nested Actor Message.lvclass

This message's payload is an actor, and it tells the actor to launch a nested actor.

My thought exactly. I don't know if that means it's a good idea or not.

I didn't suggest it as part of the framework before because I'm not as concerned with splitting the actor wire as you are and because I wanted to hear more feedback on the general idea first.

Regarding stopping, I think that each parent should tell its nested actors "I'm stopping", but that you then have a problem with two different use cases:

  1. The nested actor is a child. The parent is telling it "we're leaving and that's it. Let's go".
  2. The nested actor is a teenager. The parent is telling it "I'm leaving. You do what you want".

This would probably be easy enough if you could know in advance which sub-actor is which (the boolean switch), but that doesn't help at shutdown.

How about the following: The actor remembers its nested actors and tells them "I'm stopping". If the user wants to force certain nested actors to shut down, they collect their enqueuers and send them a special "force shutdown" message. I have no better idea for allowing the children to override the shutdown by default, but still allow the parent to force a shutdown at will.


___________________
Try to take over the world!
0 Kudos
Message 56 of 66
(1,250 Views)

Given the target audience, I'm not at all convinced keeping subactors running after the calling actor has stopped is a use case you want to encourage with something so obvious as "Stop Nested Actor" boolean.  It's much simpler to define an actor tree as a system of actors that work as a unit and all stop together.

I've looked over the framework a bit more and added autostop behavior to the attached sample project.  With the addition of Launch Subactor the implementation is not difficult at all and entirely transparent to the user.  Furthermore, advanced users can easily keep a subactor running if they need to by overriding Handle Error and inserting custom shutdown logic.  (In the project, do a text search for "{AutoStop}" to find the implementation.)

This implementation does shutdown the tree from the top down.  If you want to implement a bottom-up autostop process it will require the calling actor to keep track of which subactors have sent Last Ack messages and only shut down once it has received a Last Ack from all of them.  That shouldn't be difficult--all the pieces are there.  In that kind of system subactors that will continue running would have to send a "fake" Lack Ack to the calling actor in their Handle Error override.

Message 57 of 66
(1,250 Views)

Daklu wrote:

Given the target audience, I'm not at all convinced keeping subactors running after the calling actor has stopped is a use case you want to encourage with something so obvious as "Stop Nested Actor" boolean.  It's much simpler to define an actor tree as a system of actors that work as a unit and all stop together.

That was my thought also.  There is a big abstraction benefit from being able to launch an actor and think of it as a single entity, rather than a complex branch of many subcomponents, and having the possibility that that entity will be "semi-stopped" interferes with that.  What would these orphaned actors be doing and how would you connect them once their parent has stopped? 

Aside> My "Stop Nested Actor" boolean option was originally motivated by ideas of having "services" that have a separate lifetime from their (multiple) "callers".  I haven't developed this though (all my "actors" are set to die with their caller).  It would require some kind of global name to allow connection (named queues or named TCP services), and a better way to do such a service in AF would be to use "Launch Root Actor" at the start of the application, then connect by that global name.

0 Kudos
Message 58 of 66
(1,250 Views)
There is a big abstraction benefit from being able to launch an actor and think of it as a single entity

More importantly, there's a big benefit to having it behave as a single entity.  I think the current design--without downward propagating autostops--leaves too many opportunities for AF newbies (*cough* me *cough*) to accidentally leave orphaned actors roaming the streets of the Labview runtime.

As long as we're talking about changes to the AF, I'd also replace the "use an error code to signal shutdown" scheme with a Stop field in the Actor class, add a pair of Handle Stop Message methods similar to how the Last Ack is handled, and maybe rename Stop and Stop Core to use the word "Cleanup" or "Destroy" instead of "Stop."  (Originally I incorrectly assumed I could alter an actor's shutdown logic by overriding Stop Core.  It turns out that isn't called until after the actor's message handling loop is exited.)  But these are changes that break backwards compatibility and AQ may not want to go that far.

0 Kudos
Message 59 of 66
(1,250 Views)

Daklu wrote:

As long as we're talking about changes to the AF, I'd also replace the "use an error code to signal shutdown" scheme with a Stop field in the Actor class, add a pair of Handle Stop Message methods similar to how the Last Ack is handled, and maybe rename Stop and Stop Core to use the word "Cleanup" or "Destroy" instead of "Stop."  (Originally I incorrectly assumed I could alter an actor's shutdown logic by overriding Stop Core.  It turns out that isn't called until after the actor's message handling loop is exited.)  But these are changes that break backwards compatibility and AQ may not want to go that far.

I'm not going to shift to cleanup/destroy. I want to stay with the process-oriented terminology rather than going into the reference object terminology. As for the use of error to signal stop, we can have that discussion again, but I think it is going to end in the same place it did before (not archived in the forum because there wasn't a forum yet). That argument went something like: Even if we add the Stop field in actor, we still have to do something with the error, so we either make error a stop condition by default or force every method to check for error and then set the stop field, including setting the error code that was the reason for stopping, which really doesn't save anything so we might as well use the error. And although I'm open to the discussion, you're right that I'm going to shy away from anything that breaks backward compatibility at this point. At some point in the future (a couple years out), I'm suspecting we'll have enough lessons learned that we'll want to issue a new AF2 that is not backward compatibile and ship both with LabVIEW (deprecating the original but leaving it in vi.lib so existing apps continue to operate with new LV versions), but we're not anywhere near there yet. 

If you want to have that conversation, I suggest you start separate discussion thread.

0 Kudos
Message 60 of 66
(1,250 Views)