From d393f1b84d4f2b4930abf25a030433220c72b5a5 Mon Sep 17 00:00:00 2001 From: Kyle Rotte Date: Sun, 22 Sep 2019 12:32:04 -0600 Subject: [PATCH 01/12] Added delay capability to retry --- .../plugins/workflow/steps/RetryStep.java | 49 +++++- .../workflow/steps/RetryStepExecution.java | 146 +++++++++++++++--- .../workflow/steps/RetryStep/config.jelly | 9 ++ .../steps/RetryStep/help-useTimeDelay.html | 3 + .../plugins/workflow/steps/RetryStepTest.java | 84 ++++++++++ .../pipelineOptionsRetryWithTimeout.groovy | 19 +++ .../pipelineRetryStepWithTimeout.groovy | 18 +++ .../stageOptionsRetryWithTimeout copy.groovy | 19 +++ 8 files changed, 325 insertions(+), 22 deletions(-) create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-useTimeDelay.html create mode 100644 src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/pipelineOptionsRetryWithTimeout.groovy create mode 100644 src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/pipelineRetryStepWithTimeout.groovy create mode 100644 src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/stageOptionsRetryWithTimeout copy.groovy diff --git a/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStep.java b/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStep.java index b26aa998..9068e1dd 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStep.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStep.java @@ -26,28 +26,64 @@ import hudson.Extension; import hudson.model.TaskListener; +import hudson.util.ListBoxModel; + +import java.io.Serializable; import java.util.Collections; import java.util.Set; +import java.util.concurrent.TimeUnit; + import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; /** * Executes the body up to N times. * * @author Kohsuke Kawaguchi */ -public class RetryStep extends Step { +public class RetryStep extends Step implements Serializable { private final int count; + private int timeDelay; + private TimeUnit unit = TimeUnit.SECONDS; + private boolean useTimeDelay = false; + + public int left; @DataBoundConstructor public RetryStep(int count) { this.count = count; + this.left = count; } public int getCount() { return count; } + @DataBoundSetter public void setUseTimeDelay(boolean useTimeDelay) { + this.useTimeDelay = useTimeDelay; + } + + public boolean isUseTimeDelay() { + return useTimeDelay; + } + + @DataBoundSetter public void setTimeDelay(int timeDelay) { + this.timeDelay = timeDelay; + } + + public int getTimeDelay() { + return timeDelay; + } + + @DataBoundSetter public void setUnit(TimeUnit unit) { + this.unit = unit; + } + + public TimeUnit getUnit() { + return unit; + } + @Override public DescriptorImpl getDescriptor() { return (DescriptorImpl)super.getDescriptor(); @@ -55,7 +91,7 @@ public DescriptorImpl getDescriptor() { @Override public StepExecution start(StepContext context) throws Exception { - return new RetryStepExecution(count, context); + return new RetryStepExecution(this, context); } @Extension @@ -76,6 +112,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> getRequiredContext() { return Collections.singleton(TaskListener.class); @@ -83,4 +127,5 @@ public Set> getRequiredContext() { } + private static final long serialVersionUID = 1L; } diff --git a/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java b/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java index 0490aec7..0628ebcc 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java @@ -4,50 +4,151 @@ import hudson.AbortException; import hudson.Functions; import hudson.model.Run; +import hudson.Util; import hudson.model.TaskListener; import jenkins.model.CauseOfInterruption; +import java.util.UUID; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import javax.annotation.Nonnull; + +import com.google.common.base.Function; + +import jenkins.util.Timer; + /** * @author Kohsuke Kawaguchi */ public class RetryStepExecution extends AbstractStepExecutionImpl { - - @SuppressFBWarnings(value="SE_TRANSIENT_FIELD_NOT_RESTORED", justification="Only used when starting.") + + @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "Only used when starting.") + private transient final RetryStep step; private transient final int count; + private transient volatile ScheduledFuture task; + + private boolean executing = false; + /** Token for {@link #activity} callbacks. */ + private final String id = UUID.randomUUID().toString(); + + @Deprecated RetryStepExecution(int count, StepContext context) { super(context); - this.count = count; + this.count =count; + this.step = null; + } + + RetryStepExecution(@Nonnull RetryStep step, StepContext context) { + super(context); + this.step = step; + this.count = step.getCount(); } - @Override - public boolean start() throws Exception { + @Override public boolean start() throws Exception { StepContext context = getContext(); - context.newBodyInvoker() - .withCallback(new Callback(count)) - .start(); + if(step == null) { + context.newBodyInvoker() + .withCallback(new Callback(count)) + .start(); + } else { + executing = true; + context.newBodyInvoker() + .withCallback(new Callback(id,step)) + .start(); + } return false; // execution is asynchronous } + + @Override public void stop(Throwable cause) throws Exception { + if (task != null) { + task.cancel(false); + } + super.stop(cause); + } + + @Override public void onResume() { + if (!executing && step != null) { + // Restarted while waiting for the timer to go off. Rerun now. + getContext().newBodyInvoker().withCallback(new Callback(id, step)).start(); + executing = true; + } // otherwise we are in the middle of the body already, so let it run + } - @Override public void onResume() {} + private static void retry(final String id, final StepContext context) { + StepExecution.applyAll(RetryStepExecution.class, new Function() { + @Override public Void apply(@Nonnull RetryStepExecution execution) { + if (execution.id.equals(id)) { + execution.retry(context); + } + return null; + } + }); + } + + private void retry(StepContext perBodyContext) { + executing = false; + getContext().saveState(); + + try { + TaskListener l = getContext().get(TaskListener.class); + if(step.left>0) { + long delay = step.getUnit().toMillis(step.getTimeDelay()); + l.getLogger().println( + "Will try again after " + + Util.getTimeSpanString(delay)); + task = Timer.get().schedule(new Runnable() { + @Override public void run() { + task = null; + try { + l.getLogger().println("Retrying"); + } catch (Exception x) { + getContext().onFailure(x); + return; + } + getContext().newBodyInvoker().withCallback(new Callback(id,step)).start(); + executing = true; + } + }, delay, TimeUnit.MILLISECONDS); + } + } catch (Throwable p) { + getContext().onFailure(p); + } + } + + @Override public String getStatus() { + if (executing) { + return "running body"; + } else if (task == null) { + return "no body, no task, not sure what happened"; + } else if (task.isDone()) { + return "scheduled task is done, but no body"; + } else if (task.isCancelled()) { + return "scheduled task was cancelled"; + } else { + return "waiting to rerun; next recurrence period: " + + step.getUnit().toMillis(step.getTimeDelay()) + "ms"; + } + } private static class Callback extends BodyExecutionCallback { + private final RetryStep step; private int left; + private final String id; + @Deprecated Callback(int count) { left = count; + this.step = null; + this.id = "-1"; } - /* Could be added, but seems unnecessary, given the message already printed in onFailure: - @Override public void onStart(StepContext context) { - try { - context.get(TaskListener.class).getLogger().println(left + " tries left"); - } catch (Exception x) { - context.onFailure(x); - } + Callback(String id, RetryStep step) { + this.id = id; + this.step = step; + left = step.getCount(); } - */ @Override public void onSuccess(StepContext context, Object result) { @@ -62,7 +163,8 @@ public void onFailure(StepContext context, Throwable t) { return; } left--; - if (left>0) { + step.left--; + if ((left>0) || (step != null && step.left>0)) { TaskListener l = context.get(TaskListener.class); if (t instanceof AbortException) { l.error(t.getMessage()); @@ -72,8 +174,12 @@ public void onFailure(StepContext context, Throwable t) { } else { Functions.printStackTrace(t, l.error("Execution failed")); } - l.getLogger().println("Retrying"); - context.newBodyInvoker().withCallback(this).start(); + if(step == null || !step.isUseTimeDelay()) { + l.getLogger().println("Retrying"); + context.newBodyInvoker().withCallback(this).start(); + } else { + RetryStepExecution.retry(id, context); + } } else { // No need to print anything in this case, since it will be thrown up anyway. context.onFailure(t); diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/config.jelly b/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/config.jelly index a734bff4..92cd587b 100644 --- a/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/config.jelly @@ -28,4 +28,13 @@ THE SOFTWARE. + + + + + + + + + diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-useTimeDelay.html b/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-useTimeDelay.html new file mode 100644 index 00000000..4ed1dac9 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-useTimeDelay.html @@ -0,0 +1,3 @@ +
+ Use a time delay in between retries. +
diff --git a/src/test/java/org/jenkinsci/plugins/workflow/steps/RetryStepTest.java b/src/test/java/org/jenkinsci/plugins/workflow/steps/RetryStepTest.java index 9191fa59..c608fa0c 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/steps/RetryStepTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/steps/RetryStepTest.java @@ -19,6 +19,7 @@ import org.jvnet.hudson.test.BuildWatcher; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; +import java.util.concurrent.TimeUnit; import static org.junit.Assert.*; @@ -225,4 +226,87 @@ public void shouldRetryAfterInnerTimeout() throws Exception { r.assertLogContains("try 1", run); r.assertLogContains("try 2", run); } + + @Test + public void retryTimeout() throws Exception { + WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition(new CpsFlowDefinition( + "int i = 0;\n" + + "retry(count: 3, timeDelay: 10, unit: 'SECONDS', useTimeDelay: true) {\n" + + " println 'Trying!'\n" + + " if (i++ < 2) error('oops');\n" + + " println 'Done!'\n" + + "}\n" + + "println 'Over!'" + , true)); + + long before = System.currentTimeMillis(); + QueueTaskFuture f = p.scheduleBuild2(0); + long after = System.currentTimeMillis(); + long difference = after - before; + long timeInSeconds = TimeUnit.MILLISECONDS.convert(difference, TimeUnit.SECONDS); + assertTrue(timeInSeconds > 20); + WorkflowRun b = r.assertBuildStatusSuccess(f); + + String log = JenkinsRule.getLog(b); + r.assertLogNotContains("\tat ", b); + + int idx = 0; + for (String msg : new String[] { + "Trying!", + "oops", + "Will try again", + "Retrying", + "Trying!", + "oops", + "Will try again", + "Retrying", + "Trying!", + "Done!", + "Over!", + }) { + idx = log.indexOf(msg, idx + 1); + assertTrue(msg + " not found", idx != -1); + } + + idx = 0; + for (String msg : new String[] { + "[Pipeline] retry", + "[Pipeline] {", + "[Pipeline] }", + "[Pipeline] {", + "[Pipeline] }", + "[Pipeline] {", + "[Pipeline] }", + "[Pipeline] // retry", + }) { + idx = log.indexOf(msg, idx + 1); + assertTrue(msg + " not found", idx != -1); + } + } + + @Test + public void stackTraceOnErrorWithTimeout() throws Exception { + WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( + new CpsFlowDefinition( + "def count = 0\n" + + "retry(count: 2, timeDelay: 10, unit: 'SECONDS', useTimeDelay: true) {\n" + + " count += 1\n" + + " echo 'Try #' + count\n" + + " if (count == 1) {\n" + + " throw new Exception('foo')\n" + + " }\n" + + " echo 'Done!'\n" + + "}\n", + true)); + + WorkflowRun run = r.buildAndAssertSuccess(p); + r.assertLogContains("Try #1", run); + r.assertLogContains("ERROR: Execution failed", run); + r.assertLogContains("java.lang.Exception: foo", run); + r.assertLogContains("\tat ", run); + r.assertLogContains("Try #2", run); + r.assertLogContains("Done!", run); + } } diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/pipelineOptionsRetryWithTimeout.groovy b/src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/pipelineOptionsRetryWithTimeout.groovy new file mode 100644 index 00000000..c86ba44c --- /dev/null +++ b/src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/pipelineOptionsRetryWithTimeout.groovy @@ -0,0 +1,19 @@ +pipeline { + agent any + options { + retry(count: 3, timeDelay: 10, unit: 'SECONDS', useTimeDelay: true) + } + stages { + stage('x') { + steps { + echo 'Trying!' + error('oops') + } + } + } + post { + always { + echo 'Done!' + } + } +} \ No newline at end of file diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/pipelineRetryStepWithTimeout.groovy b/src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/pipelineRetryStepWithTimeout.groovy new file mode 100644 index 00000000..ac3edefa --- /dev/null +++ b/src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/pipelineRetryStepWithTimeout.groovy @@ -0,0 +1,18 @@ +pipeline { + agent any + stages { + stage('x') { + steps { + retry(count: 3, timeDelay: 10, unit: 'SECONDS', useTimeDelay: true) { + echo 'Trying!' + error('oops') + } + } + } + } + post { + always { + echo 'Done!' + } + } +} \ No newline at end of file diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/stageOptionsRetryWithTimeout copy.groovy b/src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/stageOptionsRetryWithTimeout copy.groovy new file mode 100644 index 00000000..e351c00a --- /dev/null +++ b/src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/stageOptionsRetryWithTimeout copy.groovy @@ -0,0 +1,19 @@ +pipeline { + agent any + stages { + stage('x') { + options { + retry(count: 3, timeDelay: 10, unit: 'SECONDS', useTimeDelay: true) + } + steps { + echo 'Trying!' + error('oops') + } + } + } + post { + always { + echo 'Done!' + } + } +} \ No newline at end of file From 653203033d3190d7f84c6bf21410dc8a71cf0acd Mon Sep 17 00:00:00 2001 From: Kyle Rotte Date: Sun, 22 Sep 2019 12:57:58 -0600 Subject: [PATCH 02/12] Adding documentation for the new variables --- .../jenkinsci/plugins/workflow/steps/RetryStep/help-count.html | 3 +++ .../plugins/workflow/steps/RetryStep/help-timeDelay.html | 3 +++ .../jenkinsci/plugins/workflow/steps/RetryStep/help-unit.html | 3 +++ 3 files changed, 9 insertions(+) create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-count.html create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-timeDelay.html create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-unit.html diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-count.html b/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-count.html new file mode 100644 index 00000000..c6b0eca4 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-count.html @@ -0,0 +1,3 @@ +
+ The number of times to retry if an exception happens dury its body of execution. +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-timeDelay.html b/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-timeDelay.html new file mode 100644 index 00000000..d5bb6757 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-timeDelay.html @@ -0,0 +1,3 @@ +
+ The time delay that will be used in between retries. The default unit is 'SECONDS'. +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-unit.html b/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-unit.html new file mode 100644 index 00000000..7501d2e5 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-unit.html @@ -0,0 +1,3 @@ +
+ The unit of time to be applied to the time delay. +
From b4e80a99a51710e0955376a5ef80bb8894ba7d67 Mon Sep 17 00:00:00 2001 From: Kyle Rotte Date: Sun, 22 Sep 2019 13:34:48 -0600 Subject: [PATCH 03/12] Fixed links in variable comments --- .../jenkinsci/plugins/workflow/steps/RetryStepExecution.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java b/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java index 0628ebcc..a0a808eb 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java @@ -27,8 +27,9 @@ public class RetryStepExecution extends AbstractStepExecutionImpl { private transient final int count; private transient volatile ScheduledFuture task; + /** Used to track whether this is timing out on inactivity without needing to reference {@link #step}. */ private boolean executing = false; - /** Token for {@link #activity} callbacks. */ + /** Token for {@link #executing} callbacks. */ private final String id = UUID.randomUUID().toString(); From ef38438b5bdc99f47507c6a6937e365fd2cdb708 Mon Sep 17 00:00:00 2001 From: Kyle Rotte Date: Sun, 22 Sep 2019 13:57:46 -0600 Subject: [PATCH 04/12] Made updates based on findbugs scan --- .../workflow/steps/RetryStepExecution.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java b/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java index a0a808eb..84f8d8d9 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java @@ -1,5 +1,7 @@ package org.jenkinsci.plugins.workflow.steps; + +import com.google.common.base.Function; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.AbortException; import hudson.Functions; @@ -13,8 +15,6 @@ import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; -import com.google.common.base.Function; - import jenkins.util.Timer; /** @@ -24,6 +24,7 @@ public class RetryStepExecution extends AbstractStepExecutionImpl { @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "Only used when starting.") private transient final RetryStep step; + @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "Only used when starting.") private transient final int count; private transient volatile ScheduledFuture task; @@ -163,9 +164,15 @@ public void onFailure(StepContext context, Throwable t) { context.onFailure(t); return; } - left--; - step.left--; - if ((left>0) || (step != null && step.left>0)) { + int remaining = 0; + if(step != null) { + step.left--; + remaining = step.left; + } else { + left--; + remaining = left; + } + if (remaining>0) { TaskListener l = context.get(TaskListener.class); if (t instanceof AbortException) { l.error(t.getMessage()); @@ -175,7 +182,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.isUseTimeDelay()) { l.getLogger().println("Retrying"); context.newBodyInvoker().withCallback(this).start(); } else { From 2e35b88a0698edbade002c5a0ec9c57281f1ac57 Mon Sep 17 00:00:00 2001 From: Kyle Rotte Date: Mon, 23 Sep 2019 20:08:39 -0600 Subject: [PATCH 05/12] Making update to trigger build --- .../org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java b/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java index 84f8d8d9..360eaca1 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java @@ -1,6 +1,5 @@ package org.jenkinsci.plugins.workflow.steps; - import com.google.common.base.Function; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.AbortException; From d87835b66cb75d62139b00d89ca634ba98043645 Mon Sep 17 00:00:00 2001 From: Kyle Rotte Date: Thu, 26 Sep 2019 21:16:53 -0600 Subject: [PATCH 06/12] Initial update to incorporate extensible retry rate model --- .../plugins/workflow/steps/RetryStep.java | 51 ++--- .../workflow/steps/RetryStepExecution.java | 8 +- .../support/steps/retry/ExponentialDelay.java | 89 ++++++++ .../support/steps/retry/FixedDelay.java | 42 ++++ .../support/steps/retry/IncrementalDelay.java | 74 +++++++ .../support/steps/retry/RandomDelay.java | 63 ++++++ .../steps/retry/RandomExponentialDelay.java | 79 +++++++ .../support/steps/retry/RetryDelay.java | 68 ++++++ .../workflow/steps/RetryStep/config.jelly | 9 +- ...TimeDelay.html => help-useRetryDelay.html} | 0 .../steps/retry/ExponentialDelay/config.jelly | 40 ++++ .../retry/ExponentialDelay/help-max.html | 3 + .../retry/ExponentialDelay/help-min.html | 3 + .../ExponentialDelay/help-multiplier.html | 3 + .../retry/ExponentialDelay}/help-unit.html | 0 .../steps/retry/ExponentialDelay/help.html | 15 ++ .../steps/retry/FixedDelay/config.jelly | 34 +++ .../steps/retry/FixedDelay/help-delay.html} | 0 .../steps/retry/FixedDelay/help-unit.html | 3 + .../support/steps/retry/FixedDelay/help.html | 12 + .../steps/retry/IncrementalDelay/config.jelly | 40 ++++ .../IncrementalDelay/help-increment.html | 4 + .../retry/IncrementalDelay/help-max.html | 3 + .../retry/IncrementalDelay/help-min.html | 3 + .../retry/IncrementalDelay/help-unit.html | 3 + .../steps/retry/IncrementalDelay/help.html | 15 ++ .../steps/retry/RandomDelay/config.jelly | 37 ++++ .../steps/retry/RandomDelay/help-max.html | 3 + .../steps/retry/RandomDelay/help-min.html | 3 + .../steps/retry/RandomDelay/help-unit.html | 3 + .../support/steps/retry/RandomDelay/help.html | 16 ++ .../retry/RandomExponentialDelay/config.jelly | 37 ++++ .../RandomExponentialDelay/help-max.html | 3 + .../help-multiplier.html | 3 + .../retry/RandomExponentialDelay/help.html | 16 ++ .../steps/retry/RetryStepDelayTest.java | 206 ++++++++++++++++++ 36 files changed, 948 insertions(+), 43 deletions(-) create mode 100644 src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay.java create mode 100644 src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay.java create mode 100644 src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay.java create mode 100644 src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay.java create mode 100644 src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay.java create mode 100644 src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryDelay.java rename src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/{help-useTimeDelay.html => help-useRetryDelay.html} (100%) create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/config.jelly create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help-max.html create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help-min.html create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help-multiplier.html rename src/main/resources/org/jenkinsci/plugins/workflow/{steps/RetryStep => support/steps/retry/ExponentialDelay}/help-unit.html (100%) create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help.html create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/config.jelly rename src/main/resources/org/jenkinsci/plugins/workflow/{steps/RetryStep/help-timeDelay.html => support/steps/retry/FixedDelay/help-delay.html} (100%) create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/help-unit.html create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/help.html create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/config.jelly create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-increment.html create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-max.html create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-min.html create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-unit.html create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help.html create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/config.jelly create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help-max.html create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help-min.html create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help-unit.html create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help.html create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/config.jelly create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/help-max.html create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/help-multiplier.html create mode 100644 src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/help.html create mode 100644 src/test/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryStepDelayTest.java diff --git a/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStep.java b/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStep.java index 9068e1dd..7becfdb5 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStep.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStep.java @@ -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. * @@ -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; @@ -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 @@ -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> getRequiredContext() { return Collections.singleton(TaskListener.class); } + public Collection> getApplicableDescriptors() { + return RetryDelay.RetryDelayDescriptor.all(); + } } private static final long serialVersionUID = 1L; diff --git a/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java b/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java index 360eaca1..f1dbf7e3 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java @@ -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)); @@ -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." ; } } @@ -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 { diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay.java new file mode 100644 index 00000000..210c35c7 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay.java @@ -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"; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay.java new file mode 100644 index 00000000..56be367d --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay.java @@ -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"; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay.java new file mode 100644 index 00000000..64465806 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay.java @@ -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"; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay.java new file mode 100644 index 00000000..b0132674 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay.java @@ -0,0 +1,63 @@ +package org.jenkinsci.plugins.workflow.support.steps.retry; + +import java.util.Random; + +import javax.annotation.Nonnull; + +import org.jenkinsci.Symbol; +import org.kohsuke.stapler.DataBoundConstructor; + +import hudson.Extension; + +/** + * {@link RandomDelay} allows the delay to vary between the + * min and max range. + */ +@Extension +public class RandomDelay extends RetryDelay { + + private final int min; + private final int max; + private Random random = new Random(); + + public RandomDelay() { + super(); + this.max = 0; + this.min = 0; + } + + @DataBoundConstructor + public RandomDelay(int min, int max) { + this.max = max; + this.min = min; + } + + public long getMin() { + return min; + } + + public long getMax() { + return max; + } + + @Override + public long computeRetryDelay() { + long delay = min; + if(min == max) { + delay = min; + } else { + delay = random.nextInt(max-min) + min; + } + + return unit.toMillis(delay); + } + + @Extension @Symbol("random") + public static class DescriptorImpl extends RetryDelayDescriptor { + @Override + @Nonnull + public String getDisplayName() { + return "Random"; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay.java new file mode 100644 index 00000000..ed3197e1 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay.java @@ -0,0 +1,79 @@ +package org.jenkinsci.plugins.workflow.support.steps.retry; + +import java.util.Random; + +import javax.annotation.Nonnull; + +import org.jenkinsci.Symbol; +import org.kohsuke.stapler.DataBoundConstructor; + +import hudson.Extension; + +/** + * {@link RandomExponentialDelay} The delay starts out at the + * 2^0 {@TimeUnit} and then increases 2^x * 1 {@TimeUnit} + * each round after until it reaches the max, then each round after + * it reaches the max, the delay is a random number between 0 and max. + */ +@Extension +public class RandomExponentialDelay extends RetryDelay { + + private final int multiplier; + private final int max; + private final int base = 2; + private boolean largerThanMax = false; + private int lastMultiplier = 0; + private Random random = new Random(); + + public RandomExponentialDelay() { + super(); + this.multiplier = 0; + this.max = 0; + } + + @DataBoundConstructor + public RandomExponentialDelay(int multiplier, int max) { + this.multiplier = multiplier; + this.max = max; + } + + public int getMultiplier() { + return multiplier; + } + + public long getMax() { + return max; + } + + @Override + public long computeRetryDelay() { + long delay = 0; + if(largerThanMax) { + delay = random.nextInt(max); + } else { + if(lastMultiplier > 0) { + lastMultiplier += 1; + } else { + lastMultiplier = multiplier; + } + delay = ExponentialDelay.powerN(base, lastMultiplier); + + // Check to see if greater than max + if(delay > max) { + delay = max; + largerThanMax = true; + } + } + + return unit.toMillis(delay); + } + + @Extension @Symbol("randomExponential") + public static class DescriptorImpl extends RetryDelayDescriptor { + @Override + @Nonnull + public String getDisplayName() { + return "Random Exponential"; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryDelay.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryDelay.java new file mode 100644 index 00000000..177d8a77 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryDelay.java @@ -0,0 +1,68 @@ +package org.jenkinsci.plugins.workflow.support.steps.retry; + +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; + +import org.jenkinsci.plugins.structs.SymbolLookup; +import org.kohsuke.stapler.DataBoundSetter; + +import hudson.ExtensionList; +import hudson.ExtensionPoint; +import hudson.model.AbstractDescribableImpl; +import hudson.model.Descriptor; +import hudson.util.ListBoxModel; + +public abstract class RetryDelay extends AbstractDescribableImpl implements ExtensionPoint { + + protected TimeUnit unit = TimeUnit.SECONDS; + + @DataBoundSetter public void setUnit(TimeUnit unit) { + this.unit = unit; + } + + public TimeUnit getUnit() { + return unit; + } + + /** + * Computes the delay in MILLISECONDS + * @return Returns an integer for the time delay in MILLISECONDS + */ + public abstract long computeRetryDelay(); + + public static abstract class RetryDelayDescriptor extends Descriptor { + + public @Nonnull String getName() { + Set symbolValues = SymbolLookup.getSymbolValue(this); + if (symbolValues.isEmpty()) { + throw new IllegalArgumentException("Retry Delay descriptor class " + this.getClass().getName() + + " does not have a @Symbol and does not override getName()."); + } + return symbolValues.iterator().next(); + } + + /** + * Get all {@link RetryDelayDescriptor}s. + * + * @return a List of {@link RetryDelayDescriptor}s + */ + public static List all() { + ExtensionList descs = ExtensionList.lookup(RetryDelayDescriptor.class); + return descs.stream().sorted(Comparator.comparing(RetryDelayDescriptor::getName)).collect(Collectors.toList()); + } + + public ListBoxModel doFillUnitItems() { + ListBoxModel r = new ListBoxModel(); + for (TimeUnit unit : TimeUnit.values()) { + r.add(unit.name()); + } + return r; + } + } + +} \ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/config.jelly b/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/config.jelly index 92cd587b..105c77c8 100644 --- a/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/config.jelly @@ -29,12 +29,7 @@ THE SOFTWARE. - - - - - - - + + diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-useTimeDelay.html b/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-useRetryDelay.html similarity index 100% rename from src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-useTimeDelay.html rename to src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-useRetryDelay.html diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/config.jelly b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/config.jelly new file mode 100644 index 00000000..bad00870 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/config.jelly @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help-max.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help-max.html new file mode 100644 index 00000000..dbe59fc3 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help-max.html @@ -0,0 +1,3 @@ +
+ The maximum time delay that will be used in between retries. The default unit is 'SECONDS'. +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help-min.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help-min.html new file mode 100644 index 00000000..42b1424e --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help-min.html @@ -0,0 +1,3 @@ +
+ The minimum time delay that will be used in between retries. The default unit is 'SECONDS'. +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help-multiplier.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help-multiplier.html new file mode 100644 index 00000000..3bf6a749 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help-multiplier.html @@ -0,0 +1,3 @@ +
+ The exponent for calculate the additional delay in 2^x * 1 TimeUnit +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-unit.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help-unit.html similarity index 100% rename from src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-unit.html rename to src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help-unit.html diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help.html new file mode 100644 index 00000000..accb3fce --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help.html @@ -0,0 +1,15 @@ +
+ Exponential Delay allows the delay between retries 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. + An example of the exponential(multiplier, min, max, unit) + usage in a pipeline retry step looks like: + + retry(count: 4, + delay: exponential(max: 50000, min: 10, multiplier: 2, unit: 'SECONDS'), + useRetryDelay: true) { + error("oops") + } + +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/config.jelly b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/config.jelly new file mode 100644 index 00000000..d2a9531f --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/config.jelly @@ -0,0 +1,34 @@ + + + + + + + + + + + + diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-timeDelay.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/help-delay.html similarity index 100% rename from src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/help-timeDelay.html rename to src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/help-delay.html diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/help-unit.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/help-unit.html new file mode 100644 index 00000000..7501d2e5 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/help-unit.html @@ -0,0 +1,3 @@ +
+ The unit of time to be applied to the time delay. +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/help.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/help.html new file mode 100644 index 00000000..ab0c2e27 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/help.html @@ -0,0 +1,12 @@ +
+ Fixed Delay is a Retry Delay option that allows the you to configure the Retry + so that there is a fixed amount of time TimeUnitbefore the system + tries to execute an action in which an exception was thrown in the previous + execution. An example of the usage of fixed(delay,unit) in a + pipeline retry step looks like: + + retry(count: 4, delay: fixed(2, unit: 'SECONDS'), useRetryDelay: true) { + error("oops") + } + +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/config.jelly b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/config.jelly new file mode 100644 index 00000000..019d1fdb --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/config.jelly @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-increment.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-increment.html new file mode 100644 index 00000000..f17c4688 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-increment.html @@ -0,0 +1,4 @@ +
+ The amount of time in TimeUnit the delay will be increased between + each recurring retry. +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-max.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-max.html new file mode 100644 index 00000000..dbe59fc3 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-max.html @@ -0,0 +1,3 @@ +
+ The maximum time delay that will be used in between retries. The default unit is 'SECONDS'. +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-min.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-min.html new file mode 100644 index 00000000..b1f2c538 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-min.html @@ -0,0 +1,3 @@ +
+ The mimimum time delay that will be used in between retries. The default unit is 'SECONDS'. +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-unit.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-unit.html new file mode 100644 index 00000000..7501d2e5 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-unit.html @@ -0,0 +1,3 @@ +
+ The unit of time to be applied to the time delay. +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help.html new file mode 100644 index 00000000..2537bd19 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help.html @@ -0,0 +1,15 @@ +
+ Incremental Delay allows the delay to be increased by a specific amount + of time TimeUnit between reach recurring retry. The delay + starts out at the min and then increases by the increment each round + after until it reaches the max, then the max for the remaining rounds. + An example of the incremental(increment, min, max, unit) + usage in a pipeline retry step looks like: + + retry(count: 4, + delay: incremental(increment: 60, max: 10, min: 50000, unit: 'SECONDS'), + useRetryDelay: true) { + error("oops") + } + +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/config.jelly b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/config.jelly new file mode 100644 index 00000000..fef8c866 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/config.jelly @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help-max.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help-max.html new file mode 100644 index 00000000..dbe59fc3 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help-max.html @@ -0,0 +1,3 @@ +
+ The maximum time delay that will be used in between retries. The default unit is 'SECONDS'. +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help-min.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help-min.html new file mode 100644 index 00000000..d5bb6757 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help-min.html @@ -0,0 +1,3 @@ +
+ The time delay that will be used in between retries. The default unit is 'SECONDS'. +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help-unit.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help-unit.html new file mode 100644 index 00000000..7501d2e5 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help-unit.html @@ -0,0 +1,3 @@ +
+ The unit of time to be applied to the time delay. +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help.html new file mode 100644 index 00000000..5bac13c9 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help.html @@ -0,0 +1,16 @@ +
+ Random Delay allows for jitter between retries to help in cases where there + might be contention with external forces. A random number will be chosen + between the min and max values and will be used as the time in + TimeUnit delay. An example of the usage of + random(min, max, unit) in a + pipeline retry step looks like: + + + retry(count: 4, delay: + random(max: 60, min: 4, unit: 'SECONDS'), + useRetryDelay: true) { + error("oops") + } + +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/config.jelly b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/config.jelly new file mode 100644 index 00000000..109edd9a --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/config.jelly @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/help-max.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/help-max.html new file mode 100644 index 00000000..dbe59fc3 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/help-max.html @@ -0,0 +1,3 @@ +
+ The maximum time delay that will be used in between retries. The default unit is 'SECONDS'. +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/help-multiplier.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/help-multiplier.html new file mode 100644 index 00000000..3bf6a749 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/help-multiplier.html @@ -0,0 +1,3 @@ +
+ The exponent for calculate the additional delay in 2^x * 1 TimeUnit +
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/help.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/help.html new file mode 100644 index 00000000..1f76d2f0 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/help.html @@ -0,0 +1,16 @@ +
+ Random Exponential Delay starts out at the 2^0 {@TimeUnit} and then + increases 2^x * 1 {@TimeUnit} each recurring failure. The x is + incremented after each round giving you larger delay until it reaches + the max delay. At that point a random number between zero and max in + TimeUnit is generated for the delay foreach remaining retry. + An example of the randomExponential(multiplier, max, unit) + usage in a pipeline retry step looks like: + + retry(count: 4, delay: + randomExponential(max: 50000, multiplier: 2), + useRetryDelay: true, unit: 'SECONDS') { + error("oops") + } + +
diff --git a/src/test/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryStepDelayTest.java b/src/test/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryStepDelayTest.java new file mode 100644 index 00000000..6d2050b1 --- /dev/null +++ b/src/test/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryStepDelayTest.java @@ -0,0 +1,206 @@ +package org.jenkinsci.plugins.workflow.support.steps.retry; + +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.TimeUnit; + +import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; +import org.jenkinsci.plugins.workflow.job.WorkflowJob; +import org.jenkinsci.plugins.workflow.job.WorkflowRun; +import org.jenkinsci.plugins.workflow.steps.RetryStep; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.BuildWatcher; +import org.jvnet.hudson.test.JenkinsRule; + +import hudson.model.queue.QueueTaskFuture; + +/** + * Tests {@link RetryStep}. + */ +public class RetryStepDelayTest { + + @ClassRule + public static BuildWatcher buildWatcher = new BuildWatcher(); + @Rule + public JenkinsRule r = new JenkinsRule(); + + @Test + public void retryFixedDelay() throws Exception { + WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition(new CpsFlowDefinition( + "int i = 0;\n" + + "retry(count: 3, delay: fixed(10, unit: 'SECONDS'), useTimeDelay: true) {\n" + + " println 'Trying!'\n" + + " if (i++ < 2) error('oops');\n" + + " println 'Done!'\n" + + "}\n" + + "println 'Over!'" + , true)); + + long before = System.currentTimeMillis(); + QueueTaskFuture f = p.scheduleBuild2(0); + long after = System.currentTimeMillis(); + long difference = after - before; + long timeInSeconds = TimeUnit.MILLISECONDS.convert(difference, TimeUnit.SECONDS); + assertTrue(timeInSeconds > 20); + WorkflowRun b = r.assertBuildStatusSuccess(f); + + String log = JenkinsRule.getLog(b); + r.assertLogNotContains("\tat ", b); + + int idx = 0; + for (String msg : new String[] { + "Trying!", + "oops", + "Will try again", + "Retrying", + "Trying!", + "oops", + "Will try again", + "Retrying", + "Trying!", + "Done!", + "Over!", + }) { + idx = log.indexOf(msg, idx + 1); + assertTrue(msg + " not found", idx != -1); + } + + idx = 0; + for (String msg : new String[] { + "[Pipeline] retry", + "[Pipeline] {", + "[Pipeline] }", + "[Pipeline] {", + "[Pipeline] }", + "[Pipeline] {", + "[Pipeline] }", + "[Pipeline] // retry", + }) { + idx = log.indexOf(msg, idx + 1); + assertTrue(msg + " not found", idx != -1); + } + } + + @Test + public void stackTraceOnErrorWithTimeout() throws Exception { + WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( new CpsFlowDefinition( + "def count = 0\n" + + "retry(count: 2, delay: fixed(10, unit: 'SECONDS'), useTimeDelay: true) {\n" + + " count += 1\n" + + " echo 'Try #' + count\n" + + " if (count == 1) {\n" + + " throw new Exception('foo')\n" + + " }\n" + + " echo 'Done!'\n" + + "}\n", + true)); + + WorkflowRun run = r.buildAndAssertSuccess(p); + r.assertLogContains("Try #1", run); + r.assertLogContains("ERROR: Execution failed", run); + r.assertLogContains("java.lang.Exception: foo", run); + r.assertLogContains("\tat ", run); + r.assertLogContains("Try #2", run); + r.assertLogContains("Done!", run); + } + + @Test + public void retryRandomDelay() throws Exception { + WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( new CpsFlowDefinition( + "def count = 0\n" + + "retry(count: 4, delay: random(max: 15, min: 5, unit: 'SECONDS'), useRetryDelay: true) {\n" + + " count += 1\n" + + " echo 'Try #' + count\n" + + " if (count == 1) {\n" + + " throw new Exception('foo')\n" + + " }\n" + + " echo 'Done!'\n" + + "}\n", + true)); + + WorkflowRun run = r.buildAndAssertSuccess(p); + r.assertLogContains("Try #1", run); + r.assertLogContains("ERROR: Execution failed", run); + r.assertLogContains("java.lang.Exception: foo", run); + r.assertLogContains("\tat ", run); + r.assertLogContains("Try #2", run); + r.assertLogContains("Done!", run); + } + + @Test + public void retryExponentialDelay() throws Exception { + WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( new CpsFlowDefinition( + "def count = 0\n" + + "retry(count: 4, delay: exponential(max: 20, min: 1, multiplier: 2, unit: 'SECONDS'), useRetryDelay: true) {\n" + + " count += 1\n" + + " echo 'Try #' + count\n" + + " if (count == 1) {\n" + + " throw new Exception('foo')\n" + + " }\n" + + " echo 'Done!'\n" + + "}\n", + true)); + + WorkflowRun run = r.buildAndAssertSuccess(p); + r.assertLogContains("Try #1", run); + r.assertLogContains("ERROR: Execution failed", run); + r.assertLogContains("java.lang.Exception: foo", run); + r.assertLogContains("\tat ", run); + r.assertLogContains("Try #2", run); + r.assertLogContains("Done!", run); + } + + @Test + public void retryIncrementalDelay() throws Exception { + WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( new CpsFlowDefinition( + "def count = 0\n" + + "retry(count: 4, delay: incremental(increment: 2, max: 10, min: 1, unit: 'SECONDS'), useRetryDelay: true) {\n" + + " count += 1\n" + + " echo 'Try #' + count\n" + + " if (count == 1) {\n" + + " throw new Exception('foo')\n" + + " }\n" + + " echo 'Done!'\n" + + "}\n", + true)); + + WorkflowRun run = r.buildAndAssertSuccess(p); + r.assertLogContains("Try #1", run); + r.assertLogContains("ERROR: Execution failed", run); + r.assertLogContains("java.lang.Exception: foo", run); + r.assertLogContains("\tat ", run); + r.assertLogContains("Try #2", run); + r.assertLogContains("Done!", run); + } + + @Test + public void retryRandomExponentialDelay() throws Exception { + WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition( new CpsFlowDefinition( + "def count = 0\n" + + "retry(count: 6, delay: randomExponential(max: 10, multiplier: 2), useRetryDelay: true, unit: 'SECONDS') {\n" + + " count += 1\n" + + " echo 'Try #' + count\n" + + " if (count == 1) {\n" + + " throw new Exception('foo')\n" + + " }\n" + + " echo 'Done!'\n" + + "}\n", + true)); + + WorkflowRun run = r.buildAndAssertSuccess(p); + r.assertLogContains("Try #1", run); + r.assertLogContains("ERROR: Execution failed", run); + r.assertLogContains("java.lang.Exception: foo", run); + r.assertLogContains("\tat ", run); + r.assertLogContains("Try #2", run); + r.assertLogContains("Done!", run); + } +} \ No newline at end of file From ce5e21178de753cbbdbfb78e49370253f6fdfad1 Mon Sep 17 00:00:00 2001 From: Kyle Rotte Date: Sun, 29 Sep 2019 11:51:28 -0600 Subject: [PATCH 07/12] fixed unit tests and related classes --- .../support/steps/retry/ExponentialDelay.java | 10 +- .../support/steps/retry/FixedDelay.java | 20 ++-- .../support/steps/retry/IncrementalDelay.java | 18 ++- .../support/steps/retry/RandomDelay.java | 8 +- .../steps/retry/RandomExponentialDelay.java | 9 +- .../support/steps/retry/RetryDelay.java | 11 +- .../steps/retry/ExponentialDelay/config.jelly | 23 ---- .../steps/retry/ExponentialDelay/help.html | 2 +- .../steps/retry/FixedDelay/config.jelly | 25 +--- .../{help-delay.html => help-time.html} | 0 .../support/steps/retry/FixedDelay/help.html | 2 +- .../steps/retry/IncrementalDelay/config.jelly | 23 ---- .../retry/IncrementalDelay/help-min.html | 2 +- .../steps/retry/IncrementalDelay/help.html | 2 +- .../steps/retry/RandomDelay/config.jelly | 23 ---- .../steps/retry/RandomDelay/help-min.html | 2 +- .../support/steps/retry/RandomDelay/help.html | 2 +- .../retry/RandomExponentialDelay/config.jelly | 23 ---- .../retry/RandomExponentialDelay/help.html | 8 +- .../plugins/workflow/steps/RetryStepTest.java | 4 +- .../steps/retry/RetryStepDelayTest.java | 110 ++++++++++-------- ...ipelineOptionsRetryExponentialDelay.groovy | 19 +++ .../pipelineOptionsRetryFixedDelay.groovy} | 2 +- ...eOptionsRetryRandomExponentialDelay.groovy | 19 +++ .../pipelineRetryStepFixedDelay.groovy} | 2 +- .../pipelineRetryStepIncrementalDelay.groovy | 18 +++ .../stageOptionsRetryStepFixedDelay.groovy} | 2 +- .../stageOptionsRetryStepRandomDelay.groovy | 19 +++ 28 files changed, 202 insertions(+), 206 deletions(-) rename src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/{help-delay.html => help-time.html} (100%) create mode 100644 src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryExponentialDelay.groovy rename src/test/resources/org/jenkinsci/plugins/workflow/{steps/RetryStepTest/pipelineOptionsRetryWithTimeout.groovy => support/RetryStepDelayTest/pipelineOptionsRetryFixedDelay.groovy} (75%) create mode 100644 src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryRandomExponentialDelay.groovy rename src/test/resources/org/jenkinsci/plugins/workflow/{steps/RetryStepTest/pipelineRetryStepWithTimeout.groovy => support/RetryStepDelayTest/pipelineRetryStepFixedDelay.groovy} (73%) create mode 100644 src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineRetryStepIncrementalDelay.groovy rename src/test/resources/org/jenkinsci/plugins/workflow/{steps/RetryStepTest/stageOptionsRetryWithTimeout copy.groovy => support/RetryStepDelayTest/stageOptionsRetryStepFixedDelay.groovy} (74%) create mode 100644 src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/stageOptionsRetryStepRandomDelay.groovy diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay.java index 210c35c7..cb20e645 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay.java @@ -1,5 +1,7 @@ package org.jenkinsci.plugins.workflow.support.steps.retry; +import java.io.Serializable; + import javax.annotation.Nonnull; import org.jenkinsci.Symbol; @@ -15,7 +17,7 @@ * remaining rounds. */ @Extension -public class ExponentialDelay extends RetryDelay { +public class ExponentialDelay extends RetryDelay implements Serializable { private final long min; private final long max; @@ -33,8 +35,8 @@ public ExponentialDelay() { @DataBoundConstructor public ExponentialDelay(int multiplier, long min, long max) { this.multiplier = multiplier; - this.max = min; - this.min = max; + this.max = max; + this.min = min; } public int getMultiplier() { @@ -85,5 +87,7 @@ public static class DescriptorImpl extends RetryDelayDescriptor { public String getDisplayName() { return "Exponential"; } + private static final long serialVersionUID = 1L; } + private static final long serialVersionUID = 1L; } \ No newline at end of file diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay.java index 56be367d..9b628c8f 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay.java @@ -1,5 +1,7 @@ package org.jenkinsci.plugins.workflow.support.steps.retry; +import java.io.Serializable; + import javax.annotation.Nonnull; import org.jenkinsci.Symbol; @@ -8,27 +10,27 @@ import hudson.Extension; @Extension -public class FixedDelay extends RetryDelay { +public class FixedDelay extends RetryDelay implements Serializable { - private final long delay; + private final long time; public FixedDelay() { super(); - this.delay = 0; + this.time = 0; } @DataBoundConstructor - public FixedDelay(long delay) { - this.delay = delay; + public FixedDelay(long time) { + this.time = time; } - public long getDelay() { - return delay; + public long getTime() { + return time; } @Override public long computeRetryDelay() { - return unit.toMillis(delay); + return unit.toMillis(time); } @Extension @Symbol("fixed") @@ -38,5 +40,7 @@ public static class DescriptorImpl extends RetryDelayDescriptor { public String getDisplayName() { return "Fixed"; } + private static final long serialVersionUID = 1L; } + private static final long serialVersionUID = 1L; } \ No newline at end of file diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay.java index 64465806..e6f3b702 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay.java @@ -1,5 +1,7 @@ package org.jenkinsci.plugins.workflow.support.steps.retry; +import java.io.Serializable; + import javax.annotation.Nonnull; import org.jenkinsci.Symbol; @@ -15,7 +17,7 @@ * the max for the remaining rounds. */ @Extension -public class IncrementalDelay extends RetryDelay { +public class IncrementalDelay extends RetryDelay implements Serializable { private final long min; private final long max; @@ -32,8 +34,8 @@ public IncrementalDelay() { @DataBoundConstructor public IncrementalDelay(long increment, long min, long max) { this.increment = increment; - this.max = min; - this.min = max; + this.max = max; + this.min = min; } public long getIncrement() { @@ -51,10 +53,12 @@ public long getMax() { @Override public long computeRetryDelay() { long delay = min; - if(lastDelay > 0) { + if(lastDelay == 0) { + lastDelay = min; + } else { delay = lastDelay; - } - lastDelay = delay + increment; + lastDelay = delay + increment; + } // Check to see if greater than max if(lastDelay > max) { @@ -70,5 +74,7 @@ public static class DescriptorImpl extends RetryDelayDescriptor { public String getDisplayName() { return "Incremental"; } + private static final long serialVersionUID = 1L; } + private static final long serialVersionUID = 1L; } \ No newline at end of file diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay.java index b0132674..24ddd0c4 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay.java @@ -1,5 +1,6 @@ package org.jenkinsci.plugins.workflow.support.steps.retry; +import java.io.Serializable; import java.util.Random; import javax.annotation.Nonnull; @@ -10,11 +11,10 @@ import hudson.Extension; /** - * {@link RandomDelay} allows the delay to vary between the - * min and max range. + * {@link RandomDelay} allows the delay to vary between the min and max range. */ @Extension -public class RandomDelay extends RetryDelay { +public class RandomDelay extends RetryDelay implements Serializable { private final int min; private final int max; @@ -59,5 +59,7 @@ public static class DescriptorImpl extends RetryDelayDescriptor { public String getDisplayName() { return "Random"; } + private static final long serialVersionUID = 1L; } + private static final long serialVersionUID = 1L; } \ No newline at end of file diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay.java index ed3197e1..f414539a 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay.java @@ -1,5 +1,6 @@ package org.jenkinsci.plugins.workflow.support.steps.retry; +import java.io.Serializable; import java.util.Random; import javax.annotation.Nonnull; @@ -13,10 +14,10 @@ * {@link RandomExponentialDelay} The delay starts out at the * 2^0 {@TimeUnit} and then increases 2^x * 1 {@TimeUnit} * each round after until it reaches the max, then each round after - * it reaches the max, the delay is a random number between 0 and max. + * it reaches the max, the delay is a random number between 1 and max. */ @Extension -public class RandomExponentialDelay extends RetryDelay { +public class RandomExponentialDelay extends RetryDelay implements Serializable { private final int multiplier; private final int max; @@ -49,7 +50,7 @@ public long getMax() { public long computeRetryDelay() { long delay = 0; if(largerThanMax) { - delay = random.nextInt(max); + delay = 1 + random.nextInt(max); } else { if(lastMultiplier > 0) { lastMultiplier += 1; @@ -75,5 +76,7 @@ public static class DescriptorImpl extends RetryDelayDescriptor { public String getDisplayName() { return "Random Exponential"; } + private static final long serialVersionUID = 1L; } + private static final long serialVersionUID = 1L; } \ No newline at end of file diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryDelay.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryDelay.java index 177d8a77..0b8004fb 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryDelay.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryDelay.java @@ -1,5 +1,6 @@ package org.jenkinsci.plugins.workflow.support.steps.retry; +import java.io.Serializable; import java.util.Comparator; import java.util.List; import java.util.Set; @@ -19,13 +20,13 @@ public abstract class RetryDelay extends AbstractDescribableImpl implements ExtensionPoint { - protected TimeUnit unit = TimeUnit.SECONDS; + @Nonnull protected TimeUnit unit = TimeUnit.SECONDS; - @DataBoundSetter public void setUnit(TimeUnit unit) { + @DataBoundSetter public void setUnit(@Nonnull TimeUnit unit) { this.unit = unit; } - public TimeUnit getUnit() { + @Nonnull public TimeUnit getUnit() { return unit; } @@ -35,7 +36,7 @@ public TimeUnit getUnit() { */ public abstract long computeRetryDelay(); - public static abstract class RetryDelayDescriptor extends Descriptor { + public static abstract class RetryDelayDescriptor extends Descriptor implements Serializable { public @Nonnull String getName() { Set symbolValues = SymbolLookup.getSymbolValue(this); @@ -63,6 +64,6 @@ public ListBoxModel doFillUnitItems() { } return r; } + private static final long serialVersionUID = 1L; } - } \ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/config.jelly b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/config.jelly index bad00870..e3227ec8 100644 --- a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/config.jelly @@ -1,27 +1,4 @@ - diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help.html index accb3fce..1861f9ef 100644 --- a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help.html +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay/help.html @@ -7,7 +7,7 @@ usage in a pipeline retry step looks like: retry(count: 4, - delay: exponential(max: 50000, min: 10, multiplier: 2, unit: 'SECONDS'), + delay: exponential(multiplier: 2, min: 10, max: 50000, unit: 'SECONDS'), useRetryDelay: true) { error("oops") } diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/config.jelly b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/config.jelly index d2a9531f..c32c7db2 100644 --- a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/config.jelly @@ -1,31 +1,8 @@ - - + diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/help-delay.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/help-time.html similarity index 100% rename from src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/help-delay.html rename to src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/help-time.html diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/help.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/help.html index ab0c2e27..8cbe8df4 100644 --- a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/help.html +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/FixedDelay/help.html @@ -5,7 +5,7 @@ execution. An example of the usage of fixed(delay,unit) in a pipeline retry step looks like: - retry(count: 4, delay: fixed(2, unit: 'SECONDS'), useRetryDelay: true) { + retry(count: 4, delay: fixed(time: 2, unit: 'SECONDS'), useRetryDelay: true) { error("oops") } diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/config.jelly b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/config.jelly index 019d1fdb..37d19b0b 100644 --- a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/config.jelly @@ -1,27 +1,4 @@ - diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-min.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-min.html index b1f2c538..42b1424e 100644 --- a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-min.html +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help-min.html @@ -1,3 +1,3 @@
- The mimimum time delay that will be used in between retries. The default unit is 'SECONDS'. + The minimum time delay that will be used in between retries. The default unit is 'SECONDS'.
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help.html index 2537bd19..e20b659a 100644 --- a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help.html +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/IncrementalDelay/help.html @@ -7,7 +7,7 @@ usage in a pipeline retry step looks like: retry(count: 4, - delay: incremental(increment: 60, max: 10, min: 50000, unit: 'SECONDS'), + delay: incremental(increment: 60, min: 10, max: 50000, unit: 'SECONDS'), useRetryDelay: true) { error("oops") } diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/config.jelly b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/config.jelly index fef8c866..d38e8eb1 100644 --- a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/config.jelly @@ -1,27 +1,4 @@ - diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help-min.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help-min.html index d5bb6757..42b1424e 100644 --- a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help-min.html +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help-min.html @@ -1,3 +1,3 @@
- The time delay that will be used in between retries. The default unit is 'SECONDS'. + The minimum time delay that will be used in between retries. The default unit is 'SECONDS'.
diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help.html index 5bac13c9..58156e36 100644 --- a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help.html +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay/help.html @@ -8,7 +8,7 @@ retry(count: 4, delay: - random(max: 60, min: 4, unit: 'SECONDS'), + random(min: 4, max: 60, unit: 'SECONDS'), useRetryDelay: true) { error("oops") } diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/config.jelly b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/config.jelly index 109edd9a..d0a41b3e 100644 --- a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/config.jelly @@ -1,27 +1,4 @@ - diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/help.html b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/help.html index 1f76d2f0..834f14e2 100644 --- a/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/help.html +++ b/src/main/resources/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay/help.html @@ -2,14 +2,14 @@ Random Exponential Delay starts out at the 2^0 {@TimeUnit} and then increases 2^x * 1 {@TimeUnit} each recurring failure. The x is incremented after each round giving you larger delay until it reaches - the max delay. At that point a random number between zero and max in + the max delay. At that point a random number between one and max in TimeUnit is generated for the delay foreach remaining retry. An example of the randomExponential(multiplier, max, unit) usage in a pipeline retry step looks like: - retry(count: 4, delay: - randomExponential(max: 50000, multiplier: 2), - useRetryDelay: true, unit: 'SECONDS') { + retry(count: 4, + delay: randomExponential(max: 50000, multiplier: 2, unit: 'SECONDS'), + useRetryDelay: true) { error("oops") } diff --git a/src/test/java/org/jenkinsci/plugins/workflow/steps/RetryStepTest.java b/src/test/java/org/jenkinsci/plugins/workflow/steps/RetryStepTest.java index c608fa0c..a6d106c6 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/steps/RetryStepTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/steps/RetryStepTest.java @@ -232,7 +232,7 @@ public void retryTimeout() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition( "int i = 0;\n" + - "retry(count: 3, timeDelay: 10, unit: 'SECONDS', useTimeDelay: true) {\n" + + "retry(count: 3, timeDelay: 10, unit: 'SECONDS', useRetryDelay: true) {\n" + " println 'Trying!'\n" + " if (i++ < 2) error('oops');\n" + " println 'Done!'\n" + @@ -291,7 +291,7 @@ public void stackTraceOnErrorWithTimeout() throws Exception { p.setDefinition( new CpsFlowDefinition( "def count = 0\n" - + "retry(count: 2, timeDelay: 10, unit: 'SECONDS', useTimeDelay: true) {\n" + + "retry(count: 2, timeDelay: 10, unit: 'SECONDS', useRetryDelay: true) {\n" + " count += 1\n" + " echo 'Try #' + count\n" + " if (count == 1) {\n" diff --git a/src/test/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryStepDelayTest.java b/src/test/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryStepDelayTest.java index 6d2050b1..bcf3b3c1 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryStepDelayTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryStepDelayTest.java @@ -31,7 +31,7 @@ public void retryFixedDelay() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition( "int i = 0;\n" + - "retry(count: 3, delay: fixed(10, unit: 'SECONDS'), useTimeDelay: true) {\n" + + "retry(count: 3, delay: fixed(time: 10, unit: 'SECONDS'), useRetryDelay: true) {\n" + " println 'Trying!'\n" + " if (i++ < 2) error('oops');\n" + " println 'Done!'\n" + @@ -43,8 +43,8 @@ public void retryFixedDelay() throws Exception { QueueTaskFuture f = p.scheduleBuild2(0); long after = System.currentTimeMillis(); long difference = after - before; - long timeInSeconds = TimeUnit.MILLISECONDS.convert(difference, TimeUnit.SECONDS); - assertTrue(timeInSeconds > 20); + long minimumTimeMilliseconds = TimeUnit.SECONDS.convert(20, TimeUnit.MILLISECONDS); + assertTrue(difference > minimumTimeMilliseconds); WorkflowRun b = r.assertBuildStatusSuccess(f); String log = JenkinsRule.getLog(b); @@ -54,11 +54,11 @@ public void retryFixedDelay() throws Exception { for (String msg : new String[] { "Trying!", "oops", - "Will try again", + "Will try again after 10 sec", "Retrying", "Trying!", "oops", - "Will try again", + "Will try again after 10 sec", "Retrying", "Trying!", "Done!", @@ -70,12 +70,19 @@ public void retryFixedDelay() throws Exception { idx = 0; for (String msg : new String[] { + "[Pipeline] Start of Pipeline", "[Pipeline] retry", "[Pipeline] {", + "[Pipeline] echo", + "[Pipeline] error", "[Pipeline] }", "[Pipeline] {", + "[Pipeline] echo", + "[Pipeline] error", "[Pipeline] }", "[Pipeline] {", + "[Pipeline] echo", + "[Pipeline] echo", "[Pipeline] }", "[Pipeline] // retry", }) { @@ -85,14 +92,14 @@ public void retryFixedDelay() throws Exception { } @Test - public void stackTraceOnErrorWithTimeout() throws Exception { + public void stackTraceOnErrorWithRetry() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( - "def count = 0\n" - + "retry(count: 2, delay: fixed(10, unit: 'SECONDS'), useTimeDelay: true) {\n" - + " count += 1\n" - + " echo 'Try #' + count\n" - + " if (count == 1) {\n" + "int i = 0\n" + + "retry(count: 2, delay: fixed(time: 5, unit: 'SECONDS'), useRetryDelay: true) {\n" + + " i += 1\n" + + " echo 'Try #' + i\n" + + " if (i == 1) {\n" + " throw new Exception('foo')\n" + " }\n" + " echo 'Done!'\n" @@ -112,23 +119,23 @@ public void stackTraceOnErrorWithTimeout() throws Exception { public void retryRandomDelay() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( - "def count = 0\n" + "int i = 0\n" + "retry(count: 4, delay: random(max: 15, min: 5, unit: 'SECONDS'), useRetryDelay: true) {\n" - + " count += 1\n" - + " echo 'Try #' + count\n" - + " if (count == 1) {\n" - + " throw new Exception('foo')\n" + + " if (i++ < 3) {\n" + + " echo 'Try #' + i\n" + + " error('oops');\n" + " }\n" - + " echo 'Done!'\n" + + " println 'Done!'\n" + "}\n", true)); WorkflowRun run = r.buildAndAssertSuccess(p); r.assertLogContains("Try #1", run); - r.assertLogContains("ERROR: Execution failed", run); - r.assertLogContains("java.lang.Exception: foo", run); - r.assertLogContains("\tat ", run); + r.assertLogContains("ERROR: oops", run); + r.assertLogContains("Will try again after", run); + r.assertLogContains("Retrying", run); r.assertLogContains("Try #2", run); + r.assertLogContains("Try #3", run); r.assertLogContains("Done!", run); } @@ -136,23 +143,25 @@ public void retryRandomDelay() throws Exception { public void retryExponentialDelay() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( - "def count = 0\n" + "int i = 0\n" + "retry(count: 4, delay: exponential(max: 20, min: 1, multiplier: 2, unit: 'SECONDS'), useRetryDelay: true) {\n" - + " count += 1\n" - + " echo 'Try #' + count\n" - + " if (count == 1) {\n" - + " throw new Exception('foo')\n" + + " if (i++ < 3) {\n" + + " echo 'Try #' + i\n" + + " error('oops');\n" + " }\n" - + " echo 'Done!'\n" + + " println 'Done!'\n" + "}\n", true)); WorkflowRun run = r.buildAndAssertSuccess(p); r.assertLogContains("Try #1", run); - r.assertLogContains("ERROR: Execution failed", run); - r.assertLogContains("java.lang.Exception: foo", run); - r.assertLogContains("\tat ", run); + r.assertLogContains("ERROR: oops", run); + r.assertLogContains("Will try again after 5 sec", run); + r.assertLogContains("Retrying", run); r.assertLogContains("Try #2", run); + r.assertLogContains("Will try again after 9 sec", run); + r.assertLogContains("Try #3", run); + r.assertLogContains("Will try again after 17 sec", run); r.assertLogContains("Done!", run); } @@ -160,23 +169,25 @@ public void retryExponentialDelay() throws Exception { public void retryIncrementalDelay() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( - "def count = 0\n" + "int i = 0\n" + "retry(count: 4, delay: incremental(increment: 2, max: 10, min: 1, unit: 'SECONDS'), useRetryDelay: true) {\n" - + " count += 1\n" - + " echo 'Try #' + count\n" - + " if (count == 1) {\n" - + " throw new Exception('foo')\n" + + " if (i++ < 3) {\n" + + " echo 'Try #' + i\n" + + " error('oops');\n" + " }\n" - + " echo 'Done!'\n" + + " println 'Done!'\n" + "}\n", true)); WorkflowRun run = r.buildAndAssertSuccess(p); r.assertLogContains("Try #1", run); - r.assertLogContains("ERROR: Execution failed", run); - r.assertLogContains("java.lang.Exception: foo", run); - r.assertLogContains("\tat ", run); + r.assertLogContains("ERROR: oops", run); + r.assertLogContains("Will try again after 1 sec", run); + r.assertLogContains("Retrying", run); r.assertLogContains("Try #2", run); + r.assertLogContains("Will try again after 3 sec", run); + r.assertLogContains("Try #3", run); + r.assertLogContains("Will try again after 5 sec", run); r.assertLogContains("Done!", run); } @@ -184,23 +195,28 @@ public void retryIncrementalDelay() throws Exception { public void retryRandomExponentialDelay() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( - "def count = 0\n" + "int i = 0\n" + "retry(count: 6, delay: randomExponential(max: 10, multiplier: 2), useRetryDelay: true, unit: 'SECONDS') {\n" - + " count += 1\n" - + " echo 'Try #' + count\n" - + " if (count == 1) {\n" - + " throw new Exception('foo')\n" + + " if (i++ < 5) {\n" + + " echo 'Try #' + i\n" + + " error('oops');\n" + " }\n" - + " echo 'Done!'\n" + + " println 'Done!'\n" + "}\n", true)); WorkflowRun run = r.buildAndAssertSuccess(p); + r.assertLogContains("Try #1", run); - r.assertLogContains("ERROR: Execution failed", run); - r.assertLogContains("java.lang.Exception: foo", run); - r.assertLogContains("\tat ", run); + r.assertLogContains("ERROR: oops", run); + r.assertLogContains("Will try again after 4 sec", run); + r.assertLogContains("Retrying", run); r.assertLogContains("Try #2", run); + r.assertLogContains("Will try again after 8 sec", run); + r.assertLogContains("Try #3", run); + r.assertLogContains("Will try again after 10 sec", run); + r.assertLogContains("Try #4", run); + r.assertLogContains("Try #5", run); r.assertLogContains("Done!", run); } } \ No newline at end of file diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryExponentialDelay.groovy b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryExponentialDelay.groovy new file mode 100644 index 00000000..b3e6dce4 --- /dev/null +++ b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryExponentialDelay.groovy @@ -0,0 +1,19 @@ +pipeline { + agent any + options { + retry(count: 6, delay: randomExponential(max: 10, multiplier: 2), useRetryDelay: true, unit: 'SECONDS') + } + stages { + stage('x') { + steps { + echo 'Trying!' + error('oops') + } + } + } + post { + always { + echo 'Done!' + } + } +} \ No newline at end of file diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/pipelineOptionsRetryWithTimeout.groovy b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryFixedDelay.groovy similarity index 75% rename from src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/pipelineOptionsRetryWithTimeout.groovy rename to src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryFixedDelay.groovy index c86ba44c..ee27479f 100644 --- a/src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/pipelineOptionsRetryWithTimeout.groovy +++ b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryFixedDelay.groovy @@ -1,7 +1,7 @@ pipeline { agent any options { - retry(count: 3, timeDelay: 10, unit: 'SECONDS', useTimeDelay: true) + retry(count: 3, delay: fixed(time: 10, unit: 'SECONDS'), useRetryDelay: true) } stages { stage('x') { diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryRandomExponentialDelay.groovy b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryRandomExponentialDelay.groovy new file mode 100644 index 00000000..ee27479f --- /dev/null +++ b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryRandomExponentialDelay.groovy @@ -0,0 +1,19 @@ +pipeline { + agent any + options { + retry(count: 3, delay: fixed(time: 10, unit: 'SECONDS'), useRetryDelay: true) + } + stages { + stage('x') { + steps { + echo 'Trying!' + error('oops') + } + } + } + post { + always { + echo 'Done!' + } + } +} \ No newline at end of file diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/pipelineRetryStepWithTimeout.groovy b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineRetryStepFixedDelay.groovy similarity index 73% rename from src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/pipelineRetryStepWithTimeout.groovy rename to src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineRetryStepFixedDelay.groovy index ac3edefa..f36d0cc0 100644 --- a/src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/pipelineRetryStepWithTimeout.groovy +++ b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineRetryStepFixedDelay.groovy @@ -3,7 +3,7 @@ pipeline { stages { stage('x') { steps { - retry(count: 3, timeDelay: 10, unit: 'SECONDS', useTimeDelay: true) { + retry(count: 3, delay: fixed(time: 10, unit: 'SECONDS'), useRetryDelay: true) { echo 'Trying!' error('oops') } diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineRetryStepIncrementalDelay.groovy b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineRetryStepIncrementalDelay.groovy new file mode 100644 index 00000000..a5147961 --- /dev/null +++ b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineRetryStepIncrementalDelay.groovy @@ -0,0 +1,18 @@ +pipeline { + agent any + stages { + stage('x') { + steps { + retry(count: 4, delay: incremental(increment: 2, max: 10, min: 1, unit: 'SECONDS'), useRetryDelay: true) { + echo 'Trying!' + error('oops') + } + } + } + } + post { + always { + echo 'Done!' + } + } +} \ No newline at end of file diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/stageOptionsRetryWithTimeout copy.groovy b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/stageOptionsRetryStepFixedDelay.groovy similarity index 74% rename from src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/stageOptionsRetryWithTimeout copy.groovy rename to src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/stageOptionsRetryStepFixedDelay.groovy index e351c00a..46c797f1 100644 --- a/src/test/resources/org/jenkinsci/plugins/workflow/steps/RetryStepTest/stageOptionsRetryWithTimeout copy.groovy +++ b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/stageOptionsRetryStepFixedDelay.groovy @@ -3,7 +3,7 @@ pipeline { stages { stage('x') { options { - retry(count: 3, timeDelay: 10, unit: 'SECONDS', useTimeDelay: true) + retry(count: 3, delay: fixed(time: 10, unit: 'SECONDS'), useRetryDelay: true) } steps { echo 'Trying!' diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/stageOptionsRetryStepRandomDelay.groovy b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/stageOptionsRetryStepRandomDelay.groovy new file mode 100644 index 00000000..5969e62a --- /dev/null +++ b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/stageOptionsRetryStepRandomDelay.groovy @@ -0,0 +1,19 @@ +pipeline { + agent any + stages { + stage('x') { + options { + retry(count: 4, delay: random(max: 15, min: 5, unit: 'SECONDS'), useRetryDelay: true) + } + steps { + echo 'Trying!' + error('oops') + } + } + } + post { + always { + echo 'Done!' + } + } +} \ No newline at end of file From c6ea76c942b67f6f653f55f7074e5b89c822b6cf Mon Sep 17 00:00:00 2001 From: Kyle Rotte Date: Sun, 29 Sep 2019 12:13:37 -0600 Subject: [PATCH 08/12] Removed tests that were moved to RetryStepDelayTest --- .../plugins/workflow/steps/RetryStepTest.java | 83 ------------------- 1 file changed, 83 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/workflow/steps/RetryStepTest.java b/src/test/java/org/jenkinsci/plugins/workflow/steps/RetryStepTest.java index a6d106c6..2508ec72 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/steps/RetryStepTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/steps/RetryStepTest.java @@ -19,7 +19,6 @@ import org.jvnet.hudson.test.BuildWatcher; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; -import java.util.concurrent.TimeUnit; import static org.junit.Assert.*; @@ -227,86 +226,4 @@ public void shouldRetryAfterInnerTimeout() throws Exception { r.assertLogContains("try 2", run); } - @Test - public void retryTimeout() throws Exception { - WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition( - "int i = 0;\n" + - "retry(count: 3, timeDelay: 10, unit: 'SECONDS', useRetryDelay: true) {\n" + - " println 'Trying!'\n" + - " if (i++ < 2) error('oops');\n" + - " println 'Done!'\n" + - "}\n" + - "println 'Over!'" - , true)); - - long before = System.currentTimeMillis(); - QueueTaskFuture f = p.scheduleBuild2(0); - long after = System.currentTimeMillis(); - long difference = after - before; - long timeInSeconds = TimeUnit.MILLISECONDS.convert(difference, TimeUnit.SECONDS); - assertTrue(timeInSeconds > 20); - WorkflowRun b = r.assertBuildStatusSuccess(f); - - String log = JenkinsRule.getLog(b); - r.assertLogNotContains("\tat ", b); - - int idx = 0; - for (String msg : new String[] { - "Trying!", - "oops", - "Will try again", - "Retrying", - "Trying!", - "oops", - "Will try again", - "Retrying", - "Trying!", - "Done!", - "Over!", - }) { - idx = log.indexOf(msg, idx + 1); - assertTrue(msg + " not found", idx != -1); - } - - idx = 0; - for (String msg : new String[] { - "[Pipeline] retry", - "[Pipeline] {", - "[Pipeline] }", - "[Pipeline] {", - "[Pipeline] }", - "[Pipeline] {", - "[Pipeline] }", - "[Pipeline] // retry", - }) { - idx = log.indexOf(msg, idx + 1); - assertTrue(msg + " not found", idx != -1); - } - } - - @Test - public void stackTraceOnErrorWithTimeout() throws Exception { - WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition( - new CpsFlowDefinition( - "def count = 0\n" - + "retry(count: 2, timeDelay: 10, unit: 'SECONDS', useRetryDelay: true) {\n" - + " count += 1\n" - + " echo 'Try #' + count\n" - + " if (count == 1) {\n" - + " throw new Exception('foo')\n" - + " }\n" - + " echo 'Done!'\n" - + "}\n", - true)); - - WorkflowRun run = r.buildAndAssertSuccess(p); - r.assertLogContains("Try #1", run); - r.assertLogContains("ERROR: Execution failed", run); - r.assertLogContains("java.lang.Exception: foo", run); - r.assertLogContains("\tat ", run); - r.assertLogContains("Try #2", run); - r.assertLogContains("Done!", run); - } } From 9bf2e3090fb9f1a95f44f1e1c6cdd8a30e9e7c2d Mon Sep 17 00:00:00 2001 From: Kyle Rotte Date: Sun, 29 Sep 2019 14:49:51 -0600 Subject: [PATCH 09/12] Fixed test script so it calls the correct RetryDelay --- .../pipelineOptionsRetryExponentialDelay.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryExponentialDelay.groovy b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryExponentialDelay.groovy index b3e6dce4..f9399f8c 100644 --- a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryExponentialDelay.groovy +++ b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryExponentialDelay.groovy @@ -1,7 +1,7 @@ pipeline { agent any options { - retry(count: 6, delay: randomExponential(max: 10, multiplier: 2), useRetryDelay: true, unit: 'SECONDS') + retry(count: 4, delay: exponential(max: 20, min: 1, multiplier: 2, unit: 'SECONDS'), useRetryDelay: true) } stages { stage('x') { From bbf120a4f264eb9f8ebf68f1cceac5307ad49f1a Mon Sep 17 00:00:00 2001 From: jpinto Date: Tue, 24 Aug 2021 14:04:54 +0100 Subject: [PATCH 10/12] removed useRetryDelay variable --- .../jenkinsci/plugins/workflow/steps/RetryStep.java | 11 +---------- .../plugins/workflow/steps/RetryStepExecution.java | 2 +- .../plugins/workflow/steps/RetryStep/config.jelly | 2 +- .../support/steps/retry/RetryStepDelayTest.java | 12 ++++++------ .../pipelineOptionsRetryExponentialDelay.groovy | 2 +- .../pipelineOptionsRetryFixedDelay.groovy | 2 +- ...pipelineOptionsRetryRandomExponentialDelay.groovy | 2 +- .../pipelineRetryStepFixedDelay.groovy | 2 +- .../pipelineRetryStepIncrementalDelay.groovy | 2 +- .../stageOptionsRetryStepFixedDelay.groovy | 2 +- .../stageOptionsRetryStepRandomDelay.groovy | 2 +- 11 files changed, 16 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStep.java b/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStep.java index 7becfdb5..a2f74cca 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStep.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStep.java @@ -45,8 +45,7 @@ public class RetryStep extends Step implements Serializable { private final int count; - private RetryDelay delay; - private boolean useRetryDelay = false; + private RetryDelay delay = null; public int left; @@ -60,14 +59,6 @@ public int getCount() { return count; } - @DataBoundSetter public void setUseRetryDelay(boolean useRetryDelay) { - this.useRetryDelay = useRetryDelay; - } - - public boolean isUseRetryDelay() { - return useRetryDelay; - } - @DataBoundSetter public void setDelay(RetryDelay delay) { this.delay = delay; } diff --git a/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java b/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java index f1dbf7e3..b6b83ba6 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/steps/RetryStepExecution.java @@ -181,7 +181,7 @@ public void onFailure(StepContext context, Throwable t) { } else { Functions.printStackTrace(t, l.error("Execution failed")); } - if(step != null && !step.isUseRetryDelay()) { + if(step != null && step.getDelay() == null) { l.getLogger().println("Retrying"); context.newBodyInvoker().withCallback(this).start(); } else { diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/config.jelly b/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/config.jelly index 105c77c8..0cce5faa 100644 --- a/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/workflow/steps/RetryStep/config.jelly @@ -29,7 +29,7 @@ THE SOFTWARE.
- +
diff --git a/src/test/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryStepDelayTest.java b/src/test/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryStepDelayTest.java index bcf3b3c1..af77c2f3 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryStepDelayTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/support/steps/retry/RetryStepDelayTest.java @@ -31,7 +31,7 @@ public void retryFixedDelay() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition( "int i = 0;\n" + - "retry(count: 3, delay: fixed(time: 10, unit: 'SECONDS'), useRetryDelay: true) {\n" + + "retry(count: 3, delay: fixed(time: 10, unit: 'SECONDS')) {\n" + " println 'Trying!'\n" + " if (i++ < 2) error('oops');\n" + " println 'Done!'\n" + @@ -96,7 +96,7 @@ public void stackTraceOnErrorWithRetry() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( "int i = 0\n" - + "retry(count: 2, delay: fixed(time: 5, unit: 'SECONDS'), useRetryDelay: true) {\n" + + "retry(count: 2, delay: fixed(time: 5, unit: 'SECONDS')) {\n" + " i += 1\n" + " echo 'Try #' + i\n" + " if (i == 1) {\n" @@ -120,7 +120,7 @@ public void retryRandomDelay() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( "int i = 0\n" - + "retry(count: 4, delay: random(max: 15, min: 5, unit: 'SECONDS'), useRetryDelay: true) {\n" + + "retry(count: 4, delay: random(max: 15, min: 5, unit: 'SECONDS')) {\n" + " if (i++ < 3) {\n" + " echo 'Try #' + i\n" + " error('oops');\n" @@ -144,7 +144,7 @@ public void retryExponentialDelay() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( "int i = 0\n" - + "retry(count: 4, delay: exponential(max: 20, min: 1, multiplier: 2, unit: 'SECONDS'), useRetryDelay: true) {\n" + + "retry(count: 4, delay: exponential(max: 20, min: 1, multiplier: 2, unit: 'SECONDS')) {\n" + " if (i++ < 3) {\n" + " echo 'Try #' + i\n" + " error('oops');\n" @@ -170,7 +170,7 @@ public void retryIncrementalDelay() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( "int i = 0\n" - + "retry(count: 4, delay: incremental(increment: 2, max: 10, min: 1, unit: 'SECONDS'), useRetryDelay: true) {\n" + + "retry(count: 4, delay: incremental(increment: 2, max: 10, min: 1, unit: 'SECONDS')) {\n" + " if (i++ < 3) {\n" + " echo 'Try #' + i\n" + " error('oops');\n" @@ -196,7 +196,7 @@ public void retryRandomExponentialDelay() throws Exception { WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); p.setDefinition( new CpsFlowDefinition( "int i = 0\n" - + "retry(count: 6, delay: randomExponential(max: 10, multiplier: 2), useRetryDelay: true, unit: 'SECONDS') {\n" + + "retry(count: 6, delay: randomExponential(max: 10, multiplier: 2, unit: 'SECONDS')) {\n" + " if (i++ < 5) {\n" + " echo 'Try #' + i\n" + " error('oops');\n" diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryExponentialDelay.groovy b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryExponentialDelay.groovy index f9399f8c..0d1c8da6 100644 --- a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryExponentialDelay.groovy +++ b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryExponentialDelay.groovy @@ -1,7 +1,7 @@ pipeline { agent any options { - retry(count: 4, delay: exponential(max: 20, min: 1, multiplier: 2, unit: 'SECONDS'), useRetryDelay: true) + retry(count: 4, delay: exponential(max: 20, min: 1, multiplier: 2, unit: 'SECONDS')) } stages { stage('x') { diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryFixedDelay.groovy b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryFixedDelay.groovy index ee27479f..f0dd199f 100644 --- a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryFixedDelay.groovy +++ b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryFixedDelay.groovy @@ -1,7 +1,7 @@ pipeline { agent any options { - retry(count: 3, delay: fixed(time: 10, unit: 'SECONDS'), useRetryDelay: true) + retry(count: 3, delay: fixed(time: 10, unit: 'SECONDS')) } stages { stage('x') { diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryRandomExponentialDelay.groovy b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryRandomExponentialDelay.groovy index ee27479f..f0dd199f 100644 --- a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryRandomExponentialDelay.groovy +++ b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineOptionsRetryRandomExponentialDelay.groovy @@ -1,7 +1,7 @@ pipeline { agent any options { - retry(count: 3, delay: fixed(time: 10, unit: 'SECONDS'), useRetryDelay: true) + retry(count: 3, delay: fixed(time: 10, unit: 'SECONDS')) } stages { stage('x') { diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineRetryStepFixedDelay.groovy b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineRetryStepFixedDelay.groovy index f36d0cc0..98069380 100644 --- a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineRetryStepFixedDelay.groovy +++ b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineRetryStepFixedDelay.groovy @@ -3,7 +3,7 @@ pipeline { stages { stage('x') { steps { - retry(count: 3, delay: fixed(time: 10, unit: 'SECONDS'), useRetryDelay: true) { + retry(count: 3, delay: fixed(time: 10, unit: 'SECONDS')) { echo 'Trying!' error('oops') } diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineRetryStepIncrementalDelay.groovy b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineRetryStepIncrementalDelay.groovy index a5147961..24813a04 100644 --- a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineRetryStepIncrementalDelay.groovy +++ b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/pipelineRetryStepIncrementalDelay.groovy @@ -3,7 +3,7 @@ pipeline { stages { stage('x') { steps { - retry(count: 4, delay: incremental(increment: 2, max: 10, min: 1, unit: 'SECONDS'), useRetryDelay: true) { + retry(count: 4, delay: incremental(increment: 2, max: 10, min: 1, unit: 'SECONDS')) { echo 'Trying!' error('oops') } diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/stageOptionsRetryStepFixedDelay.groovy b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/stageOptionsRetryStepFixedDelay.groovy index 46c797f1..37892bb3 100644 --- a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/stageOptionsRetryStepFixedDelay.groovy +++ b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/stageOptionsRetryStepFixedDelay.groovy @@ -3,7 +3,7 @@ pipeline { stages { stage('x') { options { - retry(count: 3, delay: fixed(time: 10, unit: 'SECONDS'), useRetryDelay: true) + retry(count: 3, delay: fixed(time: 10, unit: 'SECONDS')) } steps { echo 'Trying!' diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/stageOptionsRetryStepRandomDelay.groovy b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/stageOptionsRetryStepRandomDelay.groovy index 5969e62a..1ebeb6c9 100644 --- a/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/stageOptionsRetryStepRandomDelay.groovy +++ b/src/test/resources/org/jenkinsci/plugins/workflow/support/RetryStepDelayTest/stageOptionsRetryStepRandomDelay.groovy @@ -3,7 +3,7 @@ pipeline { stages { stage('x') { options { - retry(count: 4, delay: random(max: 15, min: 5, unit: 'SECONDS'), useRetryDelay: true) + retry(count: 4, delay: random(max: 15, min: 5, unit: 'SECONDS')) } steps { echo 'Trying!' From 35933b95694753bc4ecc863d7d86e70af7b86000 Mon Sep 17 00:00:00 2001 From: jpinto Date: Tue, 24 Aug 2021 15:26:54 +0100 Subject: [PATCH 11/12] updated ExponentialDelay and RandomExponentialDelay javadocs --- .../plugins/workflow/support/steps/retry/ExponentialDelay.java | 2 +- .../workflow/support/steps/retry/RandomExponentialDelay.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay.java index cb20e645..5893cb70 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay.java @@ -12,7 +12,7 @@ /** * {@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} + * starts out at the min and then increases 2^x * 1 {@link java.util.concurrent.TimeUnit} * each round after until it reaches the max, then the max for the * remaining rounds. */ diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay.java index f414539a..5b00f5fb 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay.java @@ -12,7 +12,7 @@ /** * {@link RandomExponentialDelay} The delay starts out at the - * 2^0 {@TimeUnit} and then increases 2^x * 1 {@TimeUnit} + * 2^0 {@link java.util.concurrent.TimeUnit} and then increases 2^x * 1 {@link java.util.concurrent.TimeUnit} * each round after until it reaches the max, then each round after * it reaches the max, the delay is a random number between 1 and max. */ From 773c708ed1d9f920289ee628fc0f75ef2ff79a74 Mon Sep 17 00:00:00 2001 From: jpinto Date: Tue, 24 Aug 2021 15:27:49 +0100 Subject: [PATCH 12/12] fix findbugs warnings in ExponentialDelay, RandomDelay and RandomExponentialDelay --- .../workflow/support/steps/retry/ExponentialDelay.java | 3 ++- .../workflow/support/steps/retry/RandomDelay.java | 7 ++++--- .../support/steps/retry/RandomExponentialDelay.java | 9 +++++---- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay.java index 5893cb70..73c679ed 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/ExponentialDelay.java @@ -19,10 +19,11 @@ @Extension public class ExponentialDelay extends RetryDelay implements Serializable { + private static final int base = 2; + private final long min; private final long max; private final int multiplier; - private final int base = 2; private int lastMultiplier = 0; public ExponentialDelay() { diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay.java index 24ddd0c4..1919c3b4 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomDelay.java @@ -16,9 +16,10 @@ @Extension public class RandomDelay extends RetryDelay implements Serializable { + private static final Random RANDOM = new Random(); + private final int min; private final int max; - private Random random = new Random(); public RandomDelay() { super(); @@ -42,11 +43,11 @@ public long getMax() { @Override public long computeRetryDelay() { - long delay = min; + long delay; if(min == max) { delay = min; } else { - delay = random.nextInt(max-min) + min; + delay = RANDOM.nextInt(max-min) + min; } return unit.toMillis(delay); diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay.java b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay.java index 5b00f5fb..9b842714 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/steps/retry/RandomExponentialDelay.java @@ -19,12 +19,13 @@ @Extension public class RandomExponentialDelay extends RetryDelay implements Serializable { + private static final int base = 2; + private static final Random RANDOM = new Random(); + private final int multiplier; private final int max; - private final int base = 2; private boolean largerThanMax = false; private int lastMultiplier = 0; - private Random random = new Random(); public RandomExponentialDelay() { super(); @@ -48,9 +49,9 @@ public long getMax() { @Override public long computeRetryDelay() { - long delay = 0; + long delay; if(largerThanMax) { - delay = 1 + random.nextInt(max); + delay = 1 + RANDOM.nextInt(max); } else { if(lastMultiplier > 0) { lastMultiplier += 1;