-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
63 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
85 changes: 42 additions & 43 deletions
85
src/test-support/java/com/lmax/solana4j/assertion/Waiter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,70 +1,69 @@ | ||
package com.lmax.solana4j.assertion; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.time.Duration; | ||
import java.time.ZonedDateTime; | ||
import java.util.Random; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.concurrent.locks.LockSupport; | ||
|
||
public class Waiter | ||
public final class Waiter | ||
{ | ||
private static final Logger LOGGER = LoggerFactory.getLogger(Waiter.class); | ||
private static final Random RANDOM = new Random(); | ||
private static final Duration DEFAULT_INITIAL_DELAY = Duration.ZERO; | ||
private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(30); | ||
private static final Duration DEFAULT_POLLING_INTERVAL = Duration.ofSeconds(3); | ||
|
||
private int retries = 10; | ||
private Duration maximumBackoff = Duration.ofSeconds(3); | ||
private Duration initialDelay = Duration.ofSeconds(0); | ||
private final Duration initialDelay; | ||
private final Duration timeout; | ||
private final Duration pollingInterval; | ||
|
||
public <T> T waitFor(final Assertion<T> assertion) | ||
private Waiter() | ||
{ | ||
LockSupport.parkNanos(this.initialDelay.toNanos()); | ||
this(DEFAULT_INITIAL_DELAY, DEFAULT_TIMEOUT, DEFAULT_POLLING_INTERVAL); | ||
} | ||
|
||
for (int i = 0; i < retries; i++) | ||
{ | ||
try | ||
{ | ||
assertion.doAssert(); | ||
return assertion.getActual(); | ||
} | ||
catch (final Throwable throwable) | ||
{ | ||
final long exponentialBackoff = calculateExponentialBackoffDelay(i + 1); | ||
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(exponentialBackoff)); | ||
} | ||
} | ||
throw new AssertionError("Waiting for condition that never happened. " + ZonedDateTime.now()); | ||
private Waiter(final Duration initialDelay, final Duration timeout, final Duration pollingInterval) | ||
{ | ||
this.initialDelay = initialDelay; | ||
this.timeout = timeout; | ||
this.pollingInterval = pollingInterval; | ||
} | ||
|
||
public Waiter withRetries(final int retries) | ||
public Waiter withInitialDelay(final Duration initialDelay) | ||
{ | ||
this.retries = retries; | ||
return this; | ||
return new Waiter(initialDelay, timeout, pollingInterval); | ||
} | ||
|
||
public Waiter withMaximumBackoff(final Duration maximumBackOff) | ||
public Waiter withTimeout(final Duration timeout) | ||
{ | ||
this.maximumBackoff = maximumBackOff; | ||
return this; | ||
return new Waiter(initialDelay, timeout, pollingInterval); | ||
} | ||
|
||
public Waiter withInitialDelay(final Duration initialDelay) | ||
public Waiter withPollingInterval(final Duration pollingInterval) | ||
{ | ||
this.initialDelay = initialDelay; | ||
return this; | ||
return new Waiter(initialDelay, timeout, pollingInterval); | ||
} | ||
|
||
private long calculateExponentialBackoffDelay(final int attempt) | ||
public <T> T waitForAssertion(final Assertion<T> assertion) | ||
{ | ||
long delay = (1L << (attempt - 1)); | ||
delay = Math.min(delay, maximumBackoff.toSeconds()); | ||
if (delay > 1) | ||
final long endTimeMillis = System.currentTimeMillis() + timeout.toMillis(); | ||
|
||
LockSupport.parkNanos(initialDelay.toNanos()); | ||
while (System.currentTimeMillis() < endTimeMillis) | ||
{ | ||
delay = delay / 2 + RANDOM.nextInt((int) delay / 2); | ||
try | ||
{ | ||
assertion.doAssert(); | ||
return assertion.getActual(); | ||
} | ||
catch (final Throwable throwable) | ||
{ | ||
LockSupport.parkNanos(pollingInterval.toNanos()); | ||
} | ||
} | ||
LOGGER.debug("Backing off, delay now is {} seconds.", delay); | ||
return delay; | ||
|
||
throw new AssertionError("Waiting for condition that never happened. " + ZonedDateTime.now()); | ||
} | ||
|
||
public static <T> T waitFor(final Assertion<T> assertion) | ||
{ | ||
return new Waiter().waitForAssertion(assertion); | ||
} | ||
} |