Top  | Previous | Next

Action Step

The action step may have any number of scripts associated with it. Each of these scripts is called an action. There are various kinds of actions. The different kinds of actions execute at different times in the step’s lifecycle. During the lifecycle of the step, many actions may run, but only one action is ever allowed to run at a time.

 

The scripts configured in the action step have access to the chart's scope, as well as a special scope that is private to the step. This scope, called "step scope" is initialized when the step starts and destroyed when the step stops, but retained while the step is running. This is a good place for timer actions to store intermediate results.

 

On Start

This action runs when the step is started. These actions always run to completion before flow can move beyond the step, and before any other scripts on the action step will run.

On Stop

When flow is ready to move beyond the step, it is told to stop. The step will then wait for any currently executing action (e.g. "On Start" or "Timer" actions) to finish. Then it will execute its "On Stop" action (if configured). Only after these actions complete will the chart be allowed to move on.

Timer

Timer actions run every so often while the action step is running. The timer actions only start running after the "On Start" action finishes (if there is one). In addition to the timer action's script, it must have a rate, specified in milliseconds. This is the amount of time to wait between running the timer action's script. The clock starts after the "On Start" action finishes.

It is important to realize that, unlike "On Start" and "On Stop" scripts, a timer action may not run at all for an action step. If the step is ready to stop before the timer is ready, it will never run.

Error Handler

This action will run only if any of the other actions throw an unexpected error. This provides a chance for chart designers to do their own error handling, and gracefully recover from an error. If this script throws an error, the chart will abort. See section on chart concepts for more information.

 

Design Tips

When designing SFCs, the Action step will be the primary workhorse of your charts. There are a few tips to keep in mind while writing your scripts for the action step:

 

Don't Block / Pause / Wait / Sleep

This is the primary rule for SFCs. You want your scripts to run as quickly as possible. This means that you don't want to use any sort of sleep() or wait() call. Pausing or waiting is the job of transactions in an SFC.

 

Some sorts of blocking is, of course, unavoidable. For example, running a SQL query that takes some time to execute, or writing to a device over a slow radio connection. These sorts of activities are fine, however, this brings us to tip 2.

 

Refactor Loops

This is really just an extension of the don't block rule. Imagine that you have 100 widgets that need processing. Each widget takes some non-trivial amount of time (let's say, 20seconds) to process. The most obvious way to handle this would be with an "On Start" script that had a while loop from 1 to 100, processing each widget. This script would take about 33 minutes to run.

 

Instead of processing the 100 items in a while loop, you could solves this problem in two different ways with SFCs:

 

1.Option 1: Timer action. In this option, you have a single action step, but instead of having your loop from 1 to 100 in a while loop, you initialize a counter to 1 in the "On Start" action. Then you write a timer action with a rate of 0ms. The timer action processes one widget, and then increments the counter. You place a transition beneath the step whose expression is:
{counter} >= 100
This step will do the same work as the loop, but without blocking for more than 20 seconds at a time.
2.Option 2: Chart loop. Similar to option 1, you can design the loop in the chart itself. Have one action step do your initialization work, in our example: chart.counter = 0
Have another step do the processing work for one item in its On Start script. Use two transitions, the one on the left set to {counter} < 100 and the one on the right set to true. The loop action will run 100 times, and then the flow will continue down the other path.

 

Option 2 Illustrated

Option 2 Illustrated

 

Rationale

By now you should understand that you want to keep your individual script duration to a minimum. You may be wondering why this is so important. After all, in the example above, it still will take 33 minutes to complete the given work after refactoring the loop as shown.

 

The reason this is important is to support pausing, persistence, and redundancy. Charts can only be paused after any running script finishes. Similarly, a chart's state only gets synchronized with the redundancy system between script executions. If you had a script that took half an hour to run, you couldn't pause that chart until the script ended, and the redundancy system would be very out of date and not able to recover as well if the Gateway went offline.

 

As a bonus, breaking your work up into smaller units helps make the chart easier to debug and more visible for monitoring.