A typical FlowForce job returns a result only after all processing steps have finished, assuming that no error was encountered. As long as there are running steps, the job must wait for them to finish before returning the result. For jobs exposed as Web services, this means that the HTTP transaction must be kept open for the entire duration of the job execution, which may take several minutes or even hours in some cases, depending on the volume of processed data.
To handle such cases gracefully, you can use a special kind of FlowForce step called a postponed step. Postponed steps do not prevent a job from returning a result right away, because their processing will take place only after the job has returned a result (hence the name "postponed"). When a job contains postponed steps, FlowForce will first process all non-postponed steps, then it will return the job result, and only afterwards proceed to running any postponed steps.
Even though a job with postponed steps might return a result early, the job is considered in progress until the execution of all postponed steps has completed. The job is considered to have finished successfully if all its postponed steps have finished successfully as well.
You can create postponed steps anywhere in the job where a step is allowed. To do this, create a new job or open an existing one, and then click the new Postpone step button, under Execution steps:
This adds a new "Postpone" sequence to the job configuration page:
Click inside of the "Postpone" sequence to create the actual step that is to be postponed. You can also create multiple postponed steps, which is useful if postponed steps depend on each other, like in the example below. You can also nest postponed sequences; however, the execution order might become non-trivial in that case, see "Advanced scenarios" below.
•A postponed sequence is just like another job within the current job, and it can have the same structure as a job. For example, it may include (or be part of) loops or error handling (protected) blocks.
•A job may contain multiple unrelated postponed sequences. This could be important for error handling: if an error occurs within a postponed sequence, the others will not be affected. For details, see the "Error handling" section below.
•All postponed sequences are executed after all non-postponed steps, from top to bottom. For special cases, see "Advanced scenarios" below.
•It is possible to postpone steps within called sub-jobs, which are executed after the main job returns a result.
Example: Postponed steps
The following example illustrates a possible usage of postponed steps. This job is a good candidate because it is exposed as a Web service, and can be invoked at any time by a client, including from the browser. For details about such jobs, see Exposing Jobs as Web Services.
Step A runs a time-consuming shell command that lists recursively all the directories and files within a large system directory. For this reason, step A was put inside a "Postpone" sequence. Step B takes the standard output (stdout) produced by A and writes it to a file. Step B depends on the output produced by A and, therefore, has to be part of the postponed sequence as well.
Step C informs callers of the service that the task has been submitted successfully. This step has been deliberately added as the last one, even though it will be executed the first when the job runs.
Namely, whenever the Web service is called, the steps above will run in the following sequence: C*, A, B. The reason is that A and B are postponed steps, so C is executed first. The asterisk marks the point where the job returns a result.
The advantage of this configuration is that the job returns a result immediately after running step C and the HTTP transaction can end, freeing up server resources for other requests. After returning the result of the job, FlowForce proceeds to running postponed steps A and B in the usual sequence.
As a confirmation, if you invoke the job above in your browser, you will notice that the message "Task has been submitted successfully" is displayed in the browser without any significant delay, while the job continues running until it creates the output.txt file (this may take from a few seconds to a few minutes, depending on the size of the listed directory). If neither A nor B fails, the output file will be created at the path C:\FlowForce\Postponed\output.txt.
|Note:||In this example, step C has to be the last one in the job because it produces the result to be sent to the browser when testing the Web service, namely, the string "Task has been submitted successfully". If you move step C to the very top, it is still executed first, and the postponed step B is still the last executed step of the job. However, this would change the job result and the browser would display some empty output similar to . The reason is that the result of a FlowForce job is always the result of the last executed step. Postponed steps do not have a return value but produce an empty sequence instead.|
A job may contain multiple postponed steps, not necessarily one after the other, or multiple sequences of postponed steps. For example, let's suppose a job consists of the following steps, in this order:
The steps above will run in the following order: A, C*, B, D. As you can see, non-postponed steps are executed first, followed by the postponed steps. The asterisk marks the point where the job returns a result.
You can also add postponed steps within conditions (choose steps). In this case, the postponed step will be run only if the respective "when" or "otherwise" branch is run as well.
In the abstract job above, if the expression evaluates to true, the steps will run in the following order: B, C*, A. Otherwise, the run order will be: E, F*, D. The asterisk indicates where the job returns a result.
In for each steps, the postponed steps will be processed after all non-postponed steps, in the same order as the loop that they were part of.
for each item in list
For example, assuming that the loop runs three times, then the steps above will in the following order: A1, A2, A3*, B1, B2, B3, where:
•The digit indicates the loop number
•The asterisk indicates where the job returns a result.
You can also nest postponed steps within other postponed steps. In this case, the rules are:
•Outer steps of the same depth are processed first
•Nested postponed steps will be executed only after their parent sequence has finished.
For example, let's suppose that a job consists of the following nested postponed steps:
According to the rules above, the steps will run in the following order: A, G, N*, B, D, F, C, E, H, K, M, J, L. The asterisk marks the point where the job returns a result.
If you need to create and test advanced configurations like the one above, remember that you can always track the execution order of steps from the FlowForce log.
As mentioned previously, postponed steps belong to a postponed sequence. A job may contain multiple postponed sequences, at various places in the job. When an error occurs, the general rules are as follows:
•If a postponed step encounters an error, it will be cancelled, along with any subsequent steps in the same postponed sequence, and the error will be logged. Note that this affects only the current sequence. If there are other postponed sequences in the same job, they will continue to run.
•If a postponed step within a protected block encounters an error, this will generally cancel all postponed steps that are part of that block. This acts as a rollback and is necessary, considering that a protected block may have been configured to be retried multiple times in case of error, see Retry on Error.
To illustrate how the first rule above works, let's look at the following example:
In the job above, step D runs first because it is the only non-postponed step.
Apart from step D, there are two "Postpone" sequences: the first one contains steps A and B and the second one contains step C. Let's now suppose that step A fails. In this case, FlowForce Server cancels the entire "Postpone" sequence and so it cancels step B as well. The sequence containing step C is not affected by the error, and will continue to run.