patternMinor
How many builds does jenkins need to run before it has estimated times?
Viewed 0 times
howbuildsneedjenkinshastimesdoesmanybeforeestimated
Problem
We just updated our Jenkins to v2.207.1 and our build estimation times on pipeline jobs have stopped showing up. Rather than a blue bar that when hovered over shows an estimate, we are now seeing the blue-and-white striped barber pole and an estimation of N/A.
I believe this behavior might be only on pipeline jobs - we have so few freestyle jobs that I haven't seen them run yet.
What logic does Jenkins use to calculate those estimations? How many builds will we need before those times fill back in?
I believe this behavior might be only on pipeline jobs - we have so few freestyle jobs that I haven't seen them run yet.
What logic does Jenkins use to calculate those estimations? How many builds will we need before those times fill back in?
Solution
I checked out the Jenkins source code, and I believe Jenkins uses the last 3 successful or unstable builds for its estimation. If it out of the last 6 builds it can't find 3 successful or unstable builds, it uses 1 or more of the last completed (not aborted) builds. It then takes the total duration time of the "candidates" and simply divides it by the number of candidates (i.e. mean of the durations). Here is the code I based this off of that can be found in the Job.java file in the Jenkins repo:
/**
* Returns candidate build for calculating the estimated duration of the current run.
*
* Returns the 3 last successful (stable or unstable) builds, if there are any.
* Failing to find 3 of those, it will return up to 3 last unsuccessful builds.
*
* In any case it will not go more than 6 builds into the past to avoid costly build loading.
*/
@SuppressWarnings("unchecked")
protected List getEstimatedDurationCandidates() {
List candidates = new ArrayList(3);
RunT lastSuccessful = getLastSuccessfulBuild();
int lastSuccessfulNumber = -1;
if (lastSuccessful != null) {
candidates.add(lastSuccessful);
lastSuccessfulNumber = lastSuccessful.getNumber();
}
int i = 0;
RunT r = getLastBuild();
List fallbackCandidates = new ArrayList(3);
while (r != null && candidates.size() builds = getEstimatedDurationCandidates();
if(builds.isEmpty()) return -1;
long totalDuration = 0;
for (RunT b : builds) {
totalDuration += b.getDuration();
}
if(totalDuration==0) return -1;
return Math.round((double)totalDuration / builds.size());
}Code Snippets
/**
* Returns candidate build for calculating the estimated duration of the current run.
*
* Returns the 3 last successful (stable or unstable) builds, if there are any.
* Failing to find 3 of those, it will return up to 3 last unsuccessful builds.
*
* In any case it will not go more than 6 builds into the past to avoid costly build loading.
*/
@SuppressWarnings("unchecked")
protected List<RunT> getEstimatedDurationCandidates() {
List<RunT> candidates = new ArrayList<RunT>(3);
RunT lastSuccessful = getLastSuccessfulBuild();
int lastSuccessfulNumber = -1;
if (lastSuccessful != null) {
candidates.add(lastSuccessful);
lastSuccessfulNumber = lastSuccessful.getNumber();
}
int i = 0;
RunT r = getLastBuild();
List<RunT> fallbackCandidates = new ArrayList<RunT>(3);
while (r != null && candidates.size() < 3 && i < 6) {
if (!r.isBuilding() && r.getResult() != null && r.getNumber() != lastSuccessfulNumber) {
Result result = r.getResult();
if (result.isBetterOrEqualTo(Result.UNSTABLE)) {
candidates.add(r);
} else if (result.isCompleteBuild()) {
fallbackCandidates.add(r);
}
}
i++;
r = r.getPreviousBuild();
}
while (candidates.size() < 3) {
if (fallbackCandidates.isEmpty())
break;
RunT run = fallbackCandidates.remove(0);
candidates.add(run);
}
return candidates;
}
public long getEstimatedDuration() {
List<RunT> builds = getEstimatedDurationCandidates();
if(builds.isEmpty()) return -1;
long totalDuration = 0;
for (RunT b : builds) {
totalDuration += b.getDuration();
}
if(totalDuration==0) return -1;
return Math.round((double)totalDuration / builds.size());
}Context
StackExchange DevOps Q#3768, answer score: 5
Revisions (0)
No revisions yet.