Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Initial update to incorporate extensible retry rate model
  • Loading branch information
krotte1 authored and JoaoPPinto committed Aug 24, 2021
commit d87835b66cb75d62139b00d89ca634ba98043645
51 changes: 19 additions & 32 deletions src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStep.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,19 @@

package org.jenkinsci.plugins.workflow.steps;

import hudson.Extension;
import hudson.model.TaskListener;
import hudson.util.ListBoxModel;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.jenkinsci.plugins.workflow.support.steps.retry.RetryDelay;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

import hudson.Extension;
import hudson.model.Descriptor;
import hudson.model.TaskListener;

/**
* Executes the body up to N times.
*
Expand All @@ -44,9 +45,8 @@
public class RetryStep extends Step implements Serializable {

private final int count;
private int timeDelay;
private TimeUnit unit = TimeUnit.SECONDS;
private boolean useTimeDelay = false;
private RetryDelay delay;
private boolean useRetryDelay = false;

public int left;

Expand All @@ -60,28 +60,20 @@ public int getCount() {
return count;
}

@DataBoundSetter public void setUseTimeDelay(boolean useTimeDelay) {
this.useTimeDelay = useTimeDelay;
@DataBoundSetter public void setUseRetryDelay(boolean useRetryDelay) {
this.useRetryDelay = useRetryDelay;
}

public boolean isUseTimeDelay() {
return useTimeDelay;
public boolean isUseRetryDelay() {
return useRetryDelay;
}

@DataBoundSetter public void setTimeDelay(int timeDelay) {
this.timeDelay = timeDelay;
@DataBoundSetter public void setDelay(RetryDelay delay) {
this.delay = delay;
}

public int getTimeDelay() {
return timeDelay;
}

@DataBoundSetter public void setUnit(TimeUnit unit) {
this.unit = unit;
}

public TimeUnit getUnit() {
return unit;
public RetryDelay getDelay() {
return delay;
}

@Override
Expand Down Expand Up @@ -112,19 +104,14 @@ public String getDisplayName() {
return "Retry the body up to N times";
}

public ListBoxModel doFillUnitItems() {
ListBoxModel r = new ListBoxModel();
for (TimeUnit unit : TimeUnit.values()) {
r.add(unit.name());
}
return r;
}

@Override
public Set<? extends Class<?>> getRequiredContext() {
return Collections.singleton(TaskListener.class);
}

public Collection<? extends Descriptor<?>> getApplicableDescriptors() {
return RetryDelay.RetryDelayDescriptor.all();
}
}

private static final long serialVersionUID = 1L;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ private void retry(StepContext perBodyContext) {
try {
TaskListener l = getContext().get(TaskListener.class);
if(step.left>0) {
long delay = step.getUnit().toMillis(step.getTimeDelay());
long delay = step.getDelay().computeRetryDelay();
l.getLogger().println(
"Will try again after " +
Util.getTimeSpanString(delay));
Expand Down Expand Up @@ -127,8 +127,8 @@ private void retry(StepContext perBodyContext) {
} else if (task.isCancelled()) {
return "scheduled task was cancelled";
} else {
return "waiting to rerun; next recurrence period: " +
step.getUnit().toMillis(step.getTimeDelay()) + "ms";
return "waiting to rerun; next recurrence period will be calculated ms " +
"during the next run." ;
}
}

Expand Down Expand Up @@ -181,7 +181,7 @@ public void onFailure(StepContext context, Throwable t) {
} else {
Functions.printStackTrace(t, l.error("Execution failed"));
}
if(step != null && !step.isUseTimeDelay()) {
if(step != null && !step.isUseRetryDelay()) {
l.getLogger().println("Retrying");
context.newBodyInvoker().withCallback(this).start();
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package org.jenkinsci.plugins.workflow.support.steps.retry;

import javax.annotation.Nonnull;

import org.jenkinsci.Symbol;
import org.kohsuke.stapler.DataBoundConstructor;

import hudson.Extension;

/**
* {@link ExponentialDelay} allows the delay to exponentially grow
* larger for issues that cannot be immediately fixed. The delay
* starts out at the min and then increases 2^x * 1 {@TimeUnit}
* each round after until it reaches the max, then the max for the
* remaining rounds.
*/
@Extension
public class ExponentialDelay extends RetryDelay {

private final long min;
private final long max;
private final int multiplier;
private final int base = 2;
private int lastMultiplier = 0;

public ExponentialDelay() {
super();
this.multiplier = 0;
this.max = 0;
this.min = 0;
}

@DataBoundConstructor
public ExponentialDelay(int multiplier, long min, long max) {
this.multiplier = multiplier;
this.max = min;
this.min = max;
}

public int getMultiplier() {
return multiplier;
}

public long getMin() {
return min;
}

public long getMax() {
return max;
}

@Override
public long computeRetryDelay() {
if(lastMultiplier > 0) {
lastMultiplier += 1;
} else {
lastMultiplier = multiplier;
}
long delay = powerN(base, lastMultiplier) + min;

// Check to see if greater than max
if(delay > max) {
delay = max;
}
return unit.toMillis(delay);
}

protected static long powerN(long number, int power){
long res = 1;
long sq = number;
while(power > 0){
if(power % 2 == 1){
res *= sq;
}
sq = sq * sq;
power /= 2;
}
return res;
}

@Extension @Symbol("exponential")
public static class DescriptorImpl extends RetryDelayDescriptor {
@Override
@Nonnull
public String getDisplayName() {
return "Exponential";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.jenkinsci.plugins.workflow.support.steps.retry;

import javax.annotation.Nonnull;

import org.jenkinsci.Symbol;
import org.kohsuke.stapler.DataBoundConstructor;

import hudson.Extension;

@Extension
public class FixedDelay extends RetryDelay {

private final long delay;

public FixedDelay() {
super();
this.delay = 0;
}

@DataBoundConstructor
public FixedDelay(long delay) {
this.delay = delay;
}

public long getDelay() {
return delay;
}

@Override
public long computeRetryDelay() {
return unit.toMillis(delay);
}

@Extension @Symbol("fixed")
public static class DescriptorImpl extends RetryDelayDescriptor {
@Override
@Nonnull
public String getDisplayName() {
return "Fixed";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.jenkinsci.plugins.workflow.support.steps.retry;

import javax.annotation.Nonnull;

import org.jenkinsci.Symbol;
import org.kohsuke.stapler.DataBoundConstructor;

import hudson.Extension;

/**
* {@link IncrementalDelay} allows the delay to gradually get
* larger for issues that cannot be immediately fixed. The delay
* starts out at the min and then each round after that the
* increment is added to it until it reaches the max, and then
* the max for the remaining rounds.
*/
@Extension
public class IncrementalDelay extends RetryDelay {

private final long min;
private final long max;
private final long increment;
private long lastDelay = 0;

public IncrementalDelay() {
super();
this.increment = 0;
this.max = 0;
this.min = 0;
}

@DataBoundConstructor
public IncrementalDelay(long increment, long min, long max) {
this.increment = increment;
this.max = min;
this.min = max;
}

public long getIncrement() {
return increment;
}

public long getMin() {
return min;
}

public long getMax() {
return max;
}

@Override
public long computeRetryDelay() {
long delay = min;
if(lastDelay > 0) {
delay = lastDelay;
}
lastDelay = delay + increment;

// Check to see if greater than max
if(lastDelay > max) {
lastDelay = max;
}
return unit.toMillis(lastDelay);
}

@Extension @Symbol("incremental")
public static class DescriptorImpl extends RetryDelayDescriptor {
@Override
@Nonnull
public String getDisplayName() {
return "Incremental";
}
}
}
Loading