diff --git a/src/main/java/org/jenkinsci/plugins/workflow/steps/WaitForConditionStep.java b/src/main/java/org/jenkinsci/plugins/workflow/steps/WaitForConditionStep.java index 76a78020..95b9db8b 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/steps/WaitForConditionStep.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/steps/WaitForConditionStep.java @@ -40,9 +40,10 @@ public final class WaitForConditionStep extends Step { static final long MIN_RECURRENCE_PERIOD = 250; // ¼s - static final long MAX_RECURRENCE_PERIOD = 15000; // ¼min + static final long DEFAULT_MAX_RECURRENCE_PERIOD = 15000; // ¼min private long initialRecurrencePeriod = MIN_RECURRENCE_PERIOD; + private long maxRecurrencePeriod = DEFAULT_MAX_RECURRENCE_PERIOD; private boolean quiet = false; @DataBoundConstructor @@ -50,14 +51,22 @@ public WaitForConditionStep() {} @DataBoundSetter public void setInitialRecurrencePeriod(long initialRecurrencePeriod) { - this.initialRecurrencePeriod = - Math.max(MIN_RECURRENCE_PERIOD, Math.min(initialRecurrencePeriod, MAX_RECURRENCE_PERIOD)); + this.initialRecurrencePeriod = Math.max(MIN_RECURRENCE_PERIOD, initialRecurrencePeriod); } public long getInitialRecurrencePeriod() { return initialRecurrencePeriod; } + @DataBoundSetter + public void setMaxRecurrencePeriod(long maxRecurrencePeriod) { + this.maxRecurrencePeriod = maxRecurrencePeriod; + } + + public long getMaxRecurrencePeriod(long maxRecurrencePeriod) { + return maxRecurrencePeriod; + } + @DataBoundSetter public void setQuiet(boolean quiet) { this.quiet = quiet; @@ -69,7 +78,11 @@ public boolean getQuiet() { @Override public StepExecution start(StepContext context) throws Exception { - return new Execution(context, initialRecurrencePeriod, this.quiet); + if (maxRecurrencePeriod < initialRecurrencePeriod) { + throw new IllegalStateException("The initial recurrance period must not be greater than the maximum."); + } + long initial = Math.max(MIN_RECURRENCE_PERIOD, Math.min(initialRecurrencePeriod, maxRecurrencePeriod)); + return new Execution(context, initial, maxRecurrencePeriod, this.quiet); } public static final class Execution extends AbstractStepExecutionImpl { @@ -85,12 +98,14 @@ public static final class Execution extends AbstractStepExecutionImpl { private static final float RECURRENCE_PERIOD_BACKOFF = 1.2f; private long initialRecurrencePeriod; + private long maxRecurrencePeriod; long recurrencePeriod; private final boolean quiet; - Execution(StepContext context, long initialRecurrencePeriod, boolean quiet) { + Execution(StepContext context, long initialRecurrencePeriod, long maxRecurrencePeriod, boolean quiet) { super(context); this.initialRecurrencePeriod = initialRecurrencePeriod; + this.maxRecurrencePeriod = maxRecurrencePeriod; recurrencePeriod = initialRecurrencePeriod; this.quiet = quiet; } @@ -100,6 +115,9 @@ private Object readResolve() { if (initialRecurrencePeriod == 0) { initialRecurrencePeriod = MIN_RECURRENCE_PERIOD; } + if (maxRecurrencePeriod == 0) { + maxRecurrencePeriod = DEFAULT_MAX_RECURRENCE_PERIOD; + } return this; } @@ -162,7 +180,7 @@ private void retry(StepContext perBodyContext) { }, recurrencePeriod, TimeUnit.MILLISECONDS); - recurrencePeriod = Math.min((long) (recurrencePeriod * RECURRENCE_PERIOD_BACKOFF), MAX_RECURRENCE_PERIOD); + recurrencePeriod = Math.min((long) (recurrencePeriod * RECURRENCE_PERIOD_BACKOFF), maxRecurrencePeriod); } @Override diff --git a/src/main/resources/org/jenkinsci/plugins/workflow/steps/WaitForConditionStep/config.jelly b/src/main/resources/org/jenkinsci/plugins/workflow/steps/WaitForConditionStep/config.jelly index 4a4ec2c0..4ed94dfe 100644 --- a/src/main/resources/org/jenkinsci/plugins/workflow/steps/WaitForConditionStep/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/workflow/steps/WaitForConditionStep/config.jelly @@ -28,6 +28,9 @@ THE SOFTWARE. + + + diff --git a/src/test/java/org/jenkinsci/plugins/workflow/steps/WaitForConditionStepTest.java b/src/test/java/org/jenkinsci/plugins/workflow/steps/WaitForConditionStepTest.java index e28a7962..163803a3 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/steps/WaitForConditionStepTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/steps/WaitForConditionStepTest.java @@ -92,6 +92,27 @@ void initialRecurrence() throws Throwable { }); } + @Test + void maxRecurrence() throws Throwable { + sessions.then(j -> { + WorkflowJob p = j.createProject(WorkflowJob.class, "p"); + p.setDefinition(new CpsFlowDefinition( + "waitUntil(initialRecurrencePeriod: 250, maxRecurrencePeriod: 255) {semaphore 'wait'}; semaphore 'waited'", true)); + WorkflowRun b = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait/1", b); + SemaphoreStep.success("wait/1", false); + SemaphoreStep.waitForStart("wait/2", b); + SemaphoreStep.success("wait/2", false); + SemaphoreStep.waitForStart("wait/3", b); + SemaphoreStep.success("wait/3", true); + SemaphoreStep.waitForStart("waited/1", b); + SemaphoreStep.success("waited/1", null); + WorkflowRun run = j.assertBuildStatusSuccess(j.waitForCompletion(b)); + j.assertLogContains("Will try again after " + Util.getTimeSpanString(250), run); + j.assertLogContains("Will try again after " + Util.getTimeSpanString(255), run); + }); + } + @Test void failure() throws Throwable { sessions.then(j -> {