Skip to content

Persistent Builds

Roman Kuzmin edited this page Jun 6, 2014 · 15 revisions

Long running or interactive workflows with expected interruptions can be automated with persistent builds which allow resuming after interruptions.


Starting persistent builds

In order to make a build persistent use the parameter Checkpoint with a path to the checkpoint file. The file is written after each completed task and removed after not interrupted builds.

For example, this command starts a persistent build with the default initial task and the default script:

Invoke-Build -Checkpoint checkpoint.clixml

Resuming persistent builds

In order to resume an interrupted build use the same parameter Checkpoint with an existing file which was created by a previously interrupted build and specify the switch Resume. In fact, the switch simply can be added to the command that started this build. The initial tasks, the script and its parameters, if any, are all ignored, their values are restored from the checkpoint file.

For example, this command resumes a build from the checkpoint file:

Invoke-Build -Checkpoint checkpoint.clixml -Resume

Do not keep unused checkpoints

If a persistent build fails and it is not going to be resumed then the created checkpoint file, if any, should be removed manually. Otherwise, there is a little chance that it can be eventually used for resuming unintentionally.

Example. A persistent build fails at the very first task. In this case resuming does not make much sense, the build should be simply invoked again. Thus, the checkpoint file is not written. As far as it is not written, it cannot be used for resuming by mistake, it does not exist ... unless it was created by an old build and not removed, as recommended.


Preparing build scripts

Scripts which do not set data shared between tasks, like script variables, global variables, etc. are ready for persistent builds unless they deal with something that may change between stopping and resuming in a way not suitable for resuming.

Scripts which deal only with script scope variables set by tasks and used by other tasks may make these variables persistent simply by declaring them as script parameters, even if they are not actually used as parameters. Script parameters are persistent because the engine takes care of this.

If nothing of the above is applicable then a script should define the functions Export-Build and Import-Build which maintain persistence of required states.

Export-Build is called after each task of a persistent build. It outputs data to be exported to a checkpoint file. Import-Build is called once on resuming. Its single argument contains the original data imported from a checkpoint file. It is called in the script scope, so that for restoring script scope variables it does not have to use the prefix script.

For example, a script uses two variables $Version and $Archive which are calculated by the task SetVariables:

# It is a good idea to declare them always, for Set-StrictMode or to hide
# existing in parent scopes and avoid export/import of irrelevant data

$Version = $null
$Archive = $null

task SetVariables {
    $script:Version = ...
    $script:Archive = ...
}

Other tasks reference this task and use these variables assuming they are set. If a persistent build is interrupted after SetVariables then on resuming the build the variables will not be set for those tasks. Export-Build and Import-Build solve this problem:

function Export-Build {
    $Version
    $Archive
}

function Import-Build {
    $Version, $Archive = $args[0]
}

As mentioned before, in this particular case it is possible and perhaps better to make $Version and $Archive persistent by declaring them as parameters:

param(
    # really used parameters
    $Platform,
    ...
    # just for persistence
    $Version,
    $Archive
)

This is it, if there is nothing else to persist then custom export and import functions are not needed, persistence of parameters is performed by the engine.


Caution

  • Think carefully of what the persistent build state is.
  • Some data are not suitable for persistence in clixml files.
  • Changes in stopped build scripts may cause incorrect resuming.
  • Checkpoint files must not be used with different engine versions.