Jenkins Pipeline currentBuild duration time returns always 0

Tomas picture Tomas · Feb 7, 2017 · Viewed 10.9k times · Source

I am trying to get build duration for our report but it always returns 0.

From reading docs, going through Slack plugin source and reading other resources I should be able to do one of the following:

def duration = currentBuild.duration
def duration = currentBuild.durationString
def duration = currentBuild.durationString()
def duration = currentBuild.getDurationString()

none of which works. From my understanding this might be because I am calling this before the build actually finished and so th duration is not available yet.

Structure of the pipeline looks something like this:

node {
    try {
        stage("Stage 1"){}
        stage("Stage 2"){}
    } catch (e) {
        currentBuild.result = "FAILED"
        throw e
    } finally {
        notifyBuild(currentBuild.result)
    }
}

def notifyBuild(String buildStatus = 'STARTED') {
    def duration = currentBuild.duration;
}

My question is:

  1. Why don't I get the duration
  2. Is there a way in pipeline to specify "after build" step? From what I read try-catching should work that way

My temporary solution is to use:

int jobDuration = (System.currentTimeMillis() - currentBuild.startTimeInMillis)/1000;

Which works fine, but always gives time in seconds and I think the currentBuild.duration should be smart enough to give different units (?)

Answer

Jon S picture Jon S · Feb 7, 2017

Update 2018-02-19, this was fixed with 2.14 release of Pipeline Support API Plugin, see this issue

In unable to find any documentation about when duration is expected to be valid. But judging from the implementation it seems like it's set directly after the run/build completes. I'm guessing that it is available on the currentBuild object since it's the same object that is used for representing currentBuild.previousBuild, which may have completed.

So to answer your questions:

  1. The duration field is only valid after the build has completed.
  2. No, there is no way of specifying an "after build" step.

With that said, I think your workaround is a good solution (may be wrap it in a function and put it in an GPL (Global Public Library).

As for your final bonus question I think the currentBuild.duration should be smart enough to give different units (?). If you are referring to the nicely formatted string, like Took 10min 5sec, currentBuild.duration won't give you any nice formatting since it simply returns a long value with the number of seconds that has elapsed. Instead, what you can do is call hudson.Util#getTimeSpanString(long duration). Like this:

import hudson.Util;

...

echo "Took ${Util.getTimeSpanString(System.currentTimeMillis() - currentBuild.startTimeInMillis)}"

This will return a nicely formatted string with the current build duration.