You can help by commenting or suggesting your edit directly into the transcript. We'll review any changes before posting them. All comments are completely anonymous. For any comments that need a reply, consider emailing training@inductiveautomation.com.
Version:
LESSON
Action Step Best Practices
Description
Learn important best practices about how to make a chart that is responsive to the pause command. Breaking tasks into smaller chunks using Loop Refactoring will help Gateway shutdown events better able to Persist the state of the SFC.
Video recorded using: Ignition 8.1
Transcript
(open in window)[00:00] In this lesson, we'll discuss Sequential Function Chart best practices, and in particular, one of the most important rules to follow when designing our charts. When designing SFCs, we want to design our charts so that they are responsive. What this means is that our charts respond quickly to the Pause and Cancel commands. If we remember from earlier lessons, when we try to pause a chart, the chart goes into Pausing state and it waits for any currently executing steps to finish up what they're working on. So for the case of an Action Step, that means that any currently executing script needs to finish before the chart can go into Paused state. Likewise, for canceling, if we try to cancel a chart, it goes into Canceling state until the currently executing step has finished with any work that it's doing. The reason it's important to respond quickly to the Pause command is that when we shut down an Ignition gateway and it tries to persist the state of our chart so that it can be restarted upon startup, the gateway needs to pause our chart before it can save the state of the chart.
[01:11] So we need to pause quickly because the operating system typically only gives the Ignition gateway a short time window in which to shut down before it will just kill the process. That's why it's important to design our charts to be paused quickly. A chart will not be responsive to the Pause and Cancel commands if it has a step that runs a script that takes a long time to finish. For example, let's say we have this very simple chart that has an Action Step Do_Work, which has an onStart action, which executes a loop that has a half second delay on each iteration. Since the script is going to loop 60 times waiting a half second each time, this is going to take 30 seconds or half a minute. There are a number of things that could cause a script to take a while to run: maybe a long running database query, maybe a lot of individual queries which take a half second each, or doing a whole bunch of I/O.
[02:04] This is just a simulation of some action which consumes some time. But typically it's going to happen if we're trying to do lots of things, and oftentimes that involves a loop. If we now start this chart, we see that it's now in a Running state, but if we try to pause it, it goes to a Pausing state, but still remains Running, and it's going to remain there until the script finishes executing, which is gonna happen when the itemsCount is 60 and 30 seconds of runtime have elapsed. That's finally happened, so it's finally in the Paused state. So the remainder of this lesson will focus on strategies whereby we can do the same amount of work, but in a different structure that keeps our chart responsive.
[03:05] We call this process refactoring. The first strategy to refactor loops and scripts is by using a loop in the chart itself. Here, this refactored chart has an Action Step called Loop_Init whose onStart action is going to initialize our counter to 0 as before. This is what will count up to 60 to process our 60 imaginary items. Then the second Action Step, Do_Work, again has an onStart action, which performs the same simulated work as before. It's just sleeping for a half second and incrementing our counter. The difference now is that instead of having the for loop in a Python script, now the loop has been implemented in the chart itself. Each time through the loop, it simply carries out these two simple statements. The chart loop now follows the left transition for itemCount less than 60, at which point the chart loop will end once the itemCount reaches 60.
[04:04] Okay, let's run this chart and see how it works. We see that our Do_Work step is active. It's actually running over and over again in the loop. We can't see it directly, but we do see that our item counter is incrementing. This time, if we try to pause our chart, we see that it goes to Pausing state for a half a second, and then it successfully pauses, and then we are also able to resume its execution. That's the big difference between this chart and the last one, because we made the Do_Work action much more atomic, now this chart can break into the execution cycle to pause or resume. And then as before, after 30 seconds or 60 items counted, the chart will finish. It's done the exact same work in the exact same amount of time as the other chart, but this chart is now responsive.
[05:04] There's one more way that we can refactor the same loop. This method doesn't have an advantage over the other method other than it's a bit more compact, and on a really busy chart, sometimes minimizing the amount of chart structure can be advantageous. In this case, we have a single Action Step Do_Work, and within it are two actions this time: the onStart action initializes our counter variable as before. Then there is a timer action at a 0 millisecond delay. So this timer action will run just as fast as possible, but within it, it's doing the inner part of the loop that is sleeping for a half a second. Then it increments the itemCount as before, and then the chart uses a transition that's just waiting for the count to reach 60, in order for the loop to stop. So this is a much more compact way to refactor our original loop than we had implemented scripting. Once again, let's run this chart and see how it behaves. So we'll go ahead and click Start, then Running.
[06:06] As before the Action Step is shown as running, our itemCount is incrementing and our transition is waiting for the looping to be finished. Then once again, when we Pause the execution, we see that our chart pauses almost immediately. Our chart is nice and responsive due to the refactoring we performed. So to recap, the thing we want to keep in mind as a chart best practice is, instead of writing looping scripts in Action Steps, that might take a long time, it works a lot better to refactor such a script. Two ways we've seen of doing this are: implementing the looping using a chart structure loop instead, or using an Action Step timer with a 0 millisecond delay and a following transition. By using either of these approaches instead, our charts can remain responsive, and we can make sure that the Ignition gateway can stop in a timely manner.