This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch v4
in repository https://gitbox.apache.org/repos/asf/causeway.git
The following commit(s) were added to refs/heads/v4 by this push:
new 4a80a4336a1 CAUSEWAY-3897: polishes RetryHandler
4a80a4336a1 is described below
commit 4a80a4336a1d702b779910a799932c3933a258ec
Author: Andi Huber <[email protected]>
AuthorDate: Wed Jul 9 08:15:40 2025 +0200
CAUSEWAY-3897: polishes RetryHandler
---
.../causeway/commons/handler/RetryHandler.java | 37 ++++++++++++++++------
1 file changed, 28 insertions(+), 9 deletions(-)
diff --git
a/commons/src/main/java/org/apache/causeway/commons/handler/RetryHandler.java
b/commons/src/main/java/org/apache/causeway/commons/handler/RetryHandler.java
index fd8bd11f90a..a4ddaa4ae9d 100644
---
a/commons/src/main/java/org/apache/causeway/commons/handler/RetryHandler.java
+++
b/commons/src/main/java/org/apache/causeway/commons/handler/RetryHandler.java
@@ -29,11 +29,15 @@
import org.apache.causeway.commons.internal.exceptions._Exceptions;
/**
+ * Retries a given task until its return value is valid.
*
* @since 4.0
*/
public record RetryHandler(
int maxAttempts,
+ /**
+ * Time delay between attempts.
+ */
Duration delay) {
// canonical constructor with argument validation
@@ -48,24 +52,39 @@ public RetryHandler(int maxAttempts, Duration delay) {
this.delay = delay;
}
- public <T, E extends Throwable> Try<T> retryUntilValid(Callable<T> task,
Predicate<T> isValid, Supplier<String> onInvalidMessage) {
+ /**
+ * Executes given {@code task} for {@link #maxAttempts} until the {@code
isValid} predicate passes its test on the
+ * {@code task}'s return value. If all attempts fail, returns a failed
{@link Try}, wrapping a {@link RetryException}
+ * with a message as provided by {@code onInvalidMessage}.
+ *
+ * <p> The initial {@code task} execution is without delay.
+ *
+ * <p> It the task throws any exception, this method immediately returns a
failed {@link Try}, wrapping that exception.
+ *
+ * <p> If the {@link Thread#sleep(long)}, as used for the delay, throws
any exception,
+ * this method immediately returns a failed {@link Try}, wrapping that
exception.
+ *
+ * @param <T> task return type
+ * @param task that will be retried until {@code isValid} predicate tests
positive
+ * @param isValid predicate to validate the task return value
+ * @param onInvalidMessage provides the exception message for when all
attempts had failed
+ */
+ public <T> Try<T> retryUntilValid(Callable<T> task, Predicate<T> isValid,
Supplier<String> onInvalidMessage) {
for(int attemptCount = 1; attemptCount<=maxAttempts; ++attemptCount) {
Try<T> tryT = Try.call(task);
if(tryT.isFailure()) return tryT; // if we don't even get to
validate, return immediately
- var optionalT = tryT.getValue();
+ var t = tryT.getValue().orElse(null);
- if(optionalT.isPresent()
- && isValid.test(optionalT.get())) {
- return Try.success(optionalT.get());
- }
+ if(isValid.test(t)) return Try.success(t);
- if(attemptCount < maxAttempts) {
- // if not last try, delay next try
+ // if not last attempt, delay next attempt (that is, if delay is
non-zero)
+ if(attemptCount < maxAttempts
+ && !delay.isZero()) {
try {
Thread.sleep(delay.toMillis());
- } catch (InterruptedException e) {
+ } catch (Throwable e) {
return Try.failure(e);
}
}