KBEC-00176 - Ending a step before it completes

Article ID:360032830512
3 minute readKnowledge base

Description

This article describes how to end a step when it prints specific text.

Symptom

You have a step with one of the following characteristics:

  1. a step you want to end after the certain text is printed

  2. a step never ends because of it:

    1. completed, printing its completed text however it never exits the step

    2. printed an error, warning, or status message before hanging

Solution

  1. Find a very recognizable message in the log of the build step that says something like:

     "finished with exit code X at "
  2. Create a parallel step that monitors a property and, when the right value appears, abort the other step. In pseudo-code, the step looks like this:

     Parallel Monitor Step
       $jobStepIdToAbort = getProperty /myJob/jobStepIdToAbort
       while(!$finished)
         $finished = getProperty(/myJob/finished)
         sleep 20
       abortJobStep $jobStepIdToAbort
  3. In the main build step, the step you want to end:

    1. Set the monitor property:

       setProperty /myJob/jobStepIdToAbort /myJobStep/jobStepId
    2. Implement a postp matcher that runs on the build step that

      1. matches for the "finished" message

      2. sets the /myJob/finished property

      3. extracts the exit code from the build

      4. sets a /myJob/exitCode property.

  4. For the step that will be ended, set its error handling to "ignore" so that the abort will not create a failed job.

  5. A subsequent step after the two parallel steps sets the correct exit status:

     $exitCode = getProperty /myJob/exitCode
     exit $exitCode

    This last step serves as a sort of status proxy step so that the job will end up with the correct outcome from the build even though the build step itself is always aborted.

Supplemental

Property changes via postp’s internal incValue() and setProperty() routines do not immediately take effect, as they are cached for efficiency. They also do not look-up previous values on the CloudBees CD (CloudBees Flow) server!

Here is a quick overview:

  1. When postp is in LiveUpdate mode (default) it will scan a log file line by line

  2. For each line it checks if any matchers exist that match the line

  3. If so, the actions for each of those matchers are executed

  4. Common actions are:

    1. incValue

       incValue (name,value):
                      This routine checks if the name "errors" or "warnings" is present in the internal property hash.
                      If not then this is the first time an error or warning has been detected and incValue sets an
                                     internal flag $::gUrgentPropertyChange to true.  We will see what this does later in the
                                     "updateServer" step.
                      Now incValue calls the internal setProperty command with a value of current + value
                      Note that incValue does not treat "name" as  a property path and does not lookup it's current value.
                      Name is simply a string for now
    2. setProperty

       setProperty(name, value)
                      This routine sets the value of an internal hash based on the name.
                      Note that the value is stored in the internal hash and no changes to the CloudBees CD (CloudBees Flow) server have been executed
                      Note also that this is NOT the same as calling the CloudBees CD (CloudBees Flow) perl API setProperty()
  5. Once all the matchers have been processed and before the next line of log is scanned, postp calls the internal routine "updateServer"

     updateServer()
    
     Update server checks to see if any changes have been posted to the internal hash.  If not it returns without updating the server
     Next it checks to see if an internal clock (30 seconds by default) has expired OR if the $::gUrgentPropertyChange flag is set to true
     If not, it returns without updating the server
     Otherwise the internal hash is flushed to the server with a batch API call

    For example, the call incValue("/myWorkflow/recover") in a matcher will only get posted after the timer expires. This can be anywhere between immediately and 30 seconds. You can bypass the postp property caching and call CloudBees CD (CloudBees Flow) directly from within your matcher

     $::gCommander->getProperty("/increment /myWorkflow/recover")

    If you attempt to set the UrgentPropertyChange value like this:

     {
         id => "ctsMatchUnknownReason",
         pattern => q{Installing met timeout due to Unknown reason},
         action => q{incValue("errors");
            incValue("/myWorkflow/recover");
            $::gUrgentPropertyChange = 1;
            $::gCommander->abortJobStep($::gStepId, {"reason" => "CTS hung while running"}); },
       },

You will not get the desired result. incValue() does not look up the current value on the CloudBees CD (CloudBees Flow) server first. It only increments it’s own internal notion of the value that it tracks during the scan of the log file. Any changes made outside postp and any pre-existing value will be ignored.