From 11:00 PM CDT Friday, May 10 – 02:30 PM CDT Saturday, May 11 (04:00 AM UTC – 07:30 PM UTC), ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

AF Architecture Question

All,

I'm pretty new to the AF and want to make sure I'm using it correctly. I wanted to run an architecture past you guys that I'm thinking of implementing and get some feedback if you guys have time. The program I'm working on needs to have a sequence engine that will run some parts of the program. Essentially, the hierarchy is that there's a 'Protocol' that maintains an array of 'Groups'. The 'Groups' maintain an array of 'Steps' which has an array of 'Functions' which consist of multiple 'Actions'. Actions are basic building blocks like, "Wait 10 Seconds" or "Move the Carousel to X" or "Turn on DO3". Putting together multiple actions give you a function, like "Move the Carousel to X, Turn on DO3, Wait 10 Seconds, Turn off DO3" would be called a Dispense. A group of Functions make up a step, Such that "Dispense, React, Dispense, Clean, Drain" makes up a Step called "Reaction. Put together a bunch of Steps and you have a 'Group', etc... The protocol is the top level and is just a JSON document that defines the whole thing. Hopefully that makes sense.

My thought was to have all of the components be actors. So, a protocol would keep track of groups, each group would keep track of its steps, etc... That way the Sequence Engine just get's the current Group, asks for it's Current Step, blah blah all the way down to the Action. Than the sequence engine sends a message to that Action telling it to do it's thing and let me know when you're done. When it's done it asks the Function for it's next Action, and so on and so forth.

There's some other stuff that's going on, Groups keep track of some other variables in the program. Functions need to know something about the physical realm. But basically, this is it. My biggest question though is if this type of architecture works, do I launch the actors all at once when I initialize the protocol, or do I just load the objects and launch them as we iterate to them, i.e. When the sequence asks for the next action, then the function sends a stop to it's current action and launches the next one, passing it's enqueuer back up the chain. Seems like launching them all up front means faster acting on them and it's easier to iterate forwards, backwards, or skipping either way. But that also sounds like a lot of actors just sitting around waiting to do something. The protocols could be big, multiple groups consisting or multiple steps, etc...

Sorry for the wall of text, hopefully it makes sense. Any thoughts on this, anyone? Or any questions to clarify any of it.

0 Kudos
Message 1 of 11
(5,709 Views)

Hi,

I might be way off base here, but why have actors at all? Do these Actions need to be done in parallel? If all you need is to do some actions in sequence, why not use regular OOP and dynamic dispatch?

For example (just off the top of my head, probably more elegant versions exist) have a parent class Action with a Do method, have all Actions inherit from it, create way to translate JSON command to Action Class*,run Do on the Action class, repeat as necessary.

* other than the obvious huge If structure method for doing this, another way would be to have your classes be plugins named the same as the command and load them dynamically, or load them all into memory and search all Actions in memory for one of name <JSON Command>.

Thanks,

Danielle

"Wisdom comes from experience. Experience is often a result of lack of wisdom.”
― Terry Pratchett
0 Kudos
Message 2 of 11
(4,248 Views)

Hi,

this problem _can_ be tackled with the actor framework AFW, but also with other techniques. Its basically a sequencer.

AFW has some advantages, as it allows parallel processes more easily, for example error or message handlers, report loggers, ressource managers and many more. Those run in parallel and the sequencer can do the sequencing alone, making the 'scrips' much easier to read and manage. But it comes with costs - parallel programming is harder to do and to debug.

Regarding the difference between monolithic and dynamically loaded components - as always: Its depends.

Monolithic programs need longer loading, but run faster as long as all fits into memory and no swapping is needed. Dynamic programs load faster, but need some extra time to load its dynamic components during execution. But when interacting with other (HW-) components, this is often not a problem.

I live in a regulated environment; i have to approve each new version of my test execution programs. In such cases monolithic programs are much harder to handle as you have to trest & approve the whole program over and over again. When loading your steps, groups etc. dynamically, you only have to approve changed components, which is probably much easier.

Just my € 0.02!

Greetings from Germany!

--

LuI

0 Kudos
Message 3 of 11
(4,248 Views)

My main reason for Actors is for the async communications. I need to have the ability to tell an Action to "Do" something, but I also need to be able to tell that Action to Pause, Stop, or Restart what it's doing as well. That seemed like a good fit for the AF. For example if I had a syncronous Action object called 'Wait' that all it did was wait for 10 minutes than when my user pressed pause all the sequence engine could do is wait for the Wait Action to finish than pause before calling the next action. Having an async process Action called 'Wait' I can now pause it in the middle of the wait and resume it from there.

Hopefully that makes sense, English isn't my first language.

0 Kudos
Message 4 of 11
(4,248 Views)

Hey Bob,

I think that you will find many people doing exactly what you want to do here given the focus of NI products on testing (in fact you can see this in action in Teststand).  A couple of years ago, I put something together that does just what you are talking about without AF.  I used something akin to the composite pattern in which the superclass was called STEP and one of the children was called SEQUENCE which executes a series of steps that are loaded in a queue.  Each step contains one method called Execute.  The steps are unloaded from the sequence queue and the method execute is called on those steps so each step is agnostic with respect to the other steps in the sequence.  I generally build my sequence from an XML file and the sequence runs when requested in a separate loop.  Commands to stop or change the sequence are sent via a queue that between the user interaction process loop and the sequence loop.

For what it's worth, this has served me well and I have dropped this into multiple projects rather seamlessly.  I would consider the use of AF for this case bigtime overkill....

I hope that this is clearer than mud.  But that seems unlikely.

Cheers, Matt

0 Kudos
Message 5 of 11
(4,248 Views)

mtat,

I think the problem with this is that my hierarchy levels aren't just a grouping of children. There's other properties that a Group has that a Step doesn't have or care about, etc... And there's some funny iteration things that have to occur whether we're incrementing a Group, Step, Function, or Action. Kind of like performing parralel testing on multiple DUT's but each DUT has it's own specific way to perform the test, but still using the same shared hardware to do the test, to frame it in the sense of TestStand (which I've used lots).

0 Kudos
Message 6 of 11
(4,248 Views)

Bob,

I guess I don't understand.  Step (an object) cares about what you tell it to care about.  It can contain whatever functionality that you require to be called in your step sequence execution.  It can contain queues for messaging, or DVRs for retaining state.  It will contain whatever properties or functionality you choose to provide it. 

Given your description above, I see nothing different than what I do.  You have the following:

  • Protocol
  • Group
  • Step
  • Function
  • Action

Each one of these can be represented by a single base object.  I chose the term Step in my own development, but you can call it whatever you like.  This object can be composed of other objects of the same type (or none at all).  So, at the very bottom of the hiearchy, you have the most pure unit - the 'Action'.  This performs a single task which must be executed.  Next up is a task ('Function') that is an array of tasks which must be executed.  And another level up we have yet another task ('Step') which is an array of tasks each consisting of an array of tasks which must be executed.  And on up we go.  (correct me if I am wrong about this description).

This is nothing new in software engineering and is done in many fields besides test and measurement.  Who cares if these tasks must be able to access data outside of their own little box?  Who cares if there is some functionality that is not shared between the tasks?  None of this matters. All that matters is that they share the same core function - they all must execute and therefore you can create an engine for them where they can be called in a repetetive manner. 

Based on your initial post, it is unclear to me why you might even consider using the AF.  The AF is for asynchronous processesAt the core of the AF is the actor which provides a promise that it will service a message, but it will not tell you when.  A sequence by it's very definition is synchronous - i.e. the next step will run only after the previous step is complete. 

Your example above of the wait step is not a good reason to try to force the AF into this box.  I will provide my use as an example: I too have a wait step in ALL of my sequences.  The loop servicing the sequence does not get bound up by this though (I won't get into the mechanics, but I can provide code if you really like); rather, the loop polls the current step at regular intervals to see if it has completed it's action and in the meantime is free to service other requests (such as stop, pause, reload, etc).  Only when the task indicates that it is complete is the next task loaded.

Anyway, upon further reflection, I can definitely say that I think this is not a use case for the AF. 

Cheers, Matt

0 Kudos
Message 7 of 11
(4,248 Views)

Matt,

This all makes sense, thanks for clarifying. One more question, the rest of the application that this seqeunce engine resides within is going to be written in the AF. It has multiple resources (Analog I/O, Digital I/O, some modbus instruments, etc...) all acting independant of one another but communicating amongst one another when needed, which seems like a good fit for the AF. Given that aspect would you still implement the sequence engine as a non-actor, would the sequence engine be an actor, but it's sequences be non-actors, or just continue the AF all the way through.

I considered AF for this portion of the application because the rest of it is built on AF and I've got a base actor that inherits from Actor that has some additional code for start up and shutdown that all of the rest of my actors inherit from.

0 Kudos
Message 8 of 11
(4,248 Views)

I agree with Matt that the steps in the sequence do not need to be actors.

I have done something with a "Recipe Manager" that was an actor, but it has "Recipe Steps" that are not. Use actors when you need to handle messages. Use classes when you need to do work of a certain type. Design (and redesign) your classes with a good interface (messages for AF and public methods for regular classes) and you are good to go.

Good luck.

Casey

Casey Lamers


Phoenix, LLC


casey.lamers@phoenixwi.com


CLA, LabVIEW Champion


Check Out the Software Engineering Processes, Architecture, and Design track at NIWeek. 2018 I guarantee you will learn things you can use daily! I will be presenting!

0 Kudos
Message 9 of 11
(4,248 Views)

I agree with Casey. I have an AF based system, that can run scripts in sequence. The script actions are not separate actors, they are just regular Actions.

Good luck,

Danielle

"Wisdom comes from experience. Experience is often a result of lack of wisdom.”
― Terry Pratchett
0 Kudos
Message 10 of 11
(4,248 Views)