Tasks and plans
A task is a grouping of actions that fail or succeed as a group. A plan is an ordered list of tasks that instructs Puffin how to execute the tasks. The best way to understand both is to see a brief example.
Listing 6 is a simple plan called simplePlan.txt:Listing 6. Simple plan
But wait! These aren't tasks. These are just the actions we defined in the last section. In the simple plan format you simply list actions you wish Puffin to execute, and Puffin executes them one after another. It won't stop if one fails, but it will manage inputs/outputs as described in the last section. Simple format plans are useful for testing actions and for simple setups where very little is involved in running your plan.
Just for information, Puffin really does treat these individual elements as tasks, just tasks that involve the execution of only a single action apiece. You don't need to worry about that, though, as that happens in the background.
Now the action definitions plus this simple format
for plans is of some use in simple scenarios, but often you would like
to short-circuit the process if something fails. For example, it is
useless to have Puffin execute the
getSalesByUser action if the
USER_ID output is not successfully extracted from the results of the
This is where the advanced plan format comes into play. The advanced plan format allows you to wrap one or more actions into a task element that Puffin executes as a unit. All its actions must succeed for the wrapper task to succeed.
Listing 7 puts the
login actions together into a task in an advanced plan:
You now have a
login task made up of the two actions
login. For this task to succeed, both
login will both have to succeed.
Now add a second task. This second task will be made up of only the
getSalesByUser action, but it will be dependent on the
login task above:
This second task demonstrates two things. The first is the
abbreviated format for tasks in an advanced plan that contain only a
single action. The second is the inclusion of the
dependsList attribute. This attribute instructs Puffin that the
getSalesByUser task should be executed only if the tasks (comma-separated) listed in the
dependsList attribute all succeed.
That's enough on tasks for now. Let's look at some other powerful features for advanced plans. The first is the repetition of tasks.
I should warn the XML seniors among you that the
tag makes for UGLY xml. However, it allows for some incredibly powerful
execution scenarios. If you want to repeat a task, all that is required
is for you to insert that task inside a repeat tag like this:
You can wrap any task or group of tasks in a repeat tag. The repeat tag can have a
attribute (optional), which is used in reporting, and a second
attribute that indicates when Puffin should stop repeating the contents
of this repeat tag. The example above uses a
count attribute to indicate to Puffin that it should execute the
getSalesByUser task twice.
The count will do what you need in most cases. There are also
repeat attributes that take the name of an action token as a value.
These work on whether the token evaluates to TRUE or FALSE as you'd
predict. For example, suppose you want to run a set of tasks that
affect every record in a table one at a time. At the end of these
tasks, one of the outputs updates an action token with the remaining
records. If that token evaluates to TRUE (there are more records), you
want it to repeat. If not, you want it to stop. In this case, you'd use
while attribute in the repeat tag.
There are other features of the repeat tag (including the ability to repeat a task or set of tasks until one fails, for example), and you can, of course, include a repeat inside other repeat tags. Needless to say, the use of repeat tags can make for some very complex and powerful Puffin plans.
As a last example of a plan file, take a look at this advanced plan (from the Puffin distribution) in Listing 10:Listing 10. Complex plan
Spend some time looking into this plan when you start working seriously with Puffin. Until then, use the simple format.
leaving plans, I want to introduce one last concept. Many Puffin users
have indicated that they want to be able to extend the framework in
Python and thus completely control how plans are executed. This allows
you even more flexible control over plans and task execution. Until I
can cover this topic in a future article, I will simply say that the
Puffin plan is a class called (not surprisingly)
Plan. This plan can be subclassed to make your very own custom
plan class, like this one shown in Listing 11 (special thanks to
Webware's Chuck Esterbrook for his suggestions on how this should work):
If you don't know (or care) about Python, you can safely skip to Results processing below (though I strongly encourage to try Python and come back!).
Listing 11 is a simple subclassing of the Puffin
With this subclass, you have everything that the Puffin framework gives
you (tasks, task dependencies, etc). For example, even if you use
executeTask to execute the
getSalesByUser task, Puffin will handle dependencies (such as not executing
that task if the login task failed) and other complexities. However, in
this example, you can see how I've introduced my own spin on execution.
In this example, if my
starsAligned() method comes back false, then the task execution isn't attempted. Although a simple example, you can see how subclassing
Plan will allow you very powerful control over how Puffin handles your tasks.
To execute the custom plan, you must call the
execute() method, but override the
executePlan() method. The
execute() method (part of the
base class) handles initialization of the various results-processing
mechanisms (described in the next section) and some other housecleaning