-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5264 from entur/limit_retry_attempts_in_siri_sx_u…
…pdater Limit retry attempts in SIRI-SX updater
- Loading branch information
Showing
5 changed files
with
346 additions
and
36 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
72 changes: 72 additions & 0 deletions
72
src/main/java/org/opentripplanner/framework/retry/OtpRetry.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 |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package org.opentripplanner.framework.retry; | ||
|
||
import java.time.Duration; | ||
import java.util.function.Predicate; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
/** | ||
* Retry an operation with a configurable number of attempts. | ||
*/ | ||
public class OtpRetry { | ||
|
||
private static final Logger LOG = LoggerFactory.getLogger(OtpRetry.class); | ||
|
||
private final String name; | ||
private final int maxAttempts; | ||
private final Duration initialRetryInterval; | ||
private final int backoffMultiplier; | ||
private final Runnable onRetry; | ||
private final Predicate<Exception> retryableException; | ||
|
||
OtpRetry( | ||
String name, | ||
int maxAttempts, | ||
Duration initialRetryInterval, | ||
int backoffMultiplier, | ||
Predicate<Exception> retryableException, | ||
Runnable onRetry | ||
) { | ||
this.name = name; | ||
this.maxAttempts = maxAttempts; | ||
this.initialRetryInterval = initialRetryInterval; | ||
this.backoffMultiplier = backoffMultiplier; | ||
this.retryableException = retryableException; | ||
this.onRetry = onRetry; | ||
} | ||
|
||
public void execute(Runnable retryable) { | ||
int attempts = 0; | ||
long sleepTime = initialRetryInterval.toMillis(); | ||
while (true) { | ||
try { | ||
retryable.run(); | ||
return; | ||
} catch (Exception e) { | ||
if (!retryableException.test(e)) { | ||
throw new OtpRetryException("Operation failed with non-retryable exception", e); | ||
} | ||
attempts++; | ||
if (attempts > maxAttempts) { | ||
throw new OtpRetryException("Operation failed after " + attempts + " attempts", e); | ||
} | ||
LOG.info( | ||
"Operation {} failed with retryable exception: {}. Retrying {}/{} in {} millis", | ||
name, | ||
e.getMessage(), | ||
attempts, | ||
maxAttempts, | ||
sleepTime | ||
); | ||
onRetry.run(); | ||
try { | ||
Thread.sleep(sleepTime); | ||
} catch (InterruptedException ex) { | ||
Thread.currentThread().interrupt(); | ||
throw new OtpRetryException(ex); | ||
} | ||
sleepTime = sleepTime * backoffMultiplier; | ||
} | ||
} | ||
} | ||
} |
86 changes: 86 additions & 0 deletions
86
src/main/java/org/opentripplanner/framework/retry/OtpRetryBuilder.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 |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package org.opentripplanner.framework.retry; | ||
|
||
import java.time.Duration; | ||
import java.time.temporal.ChronoUnit; | ||
import java.util.function.Predicate; | ||
|
||
public class OtpRetryBuilder { | ||
|
||
public static final int DEFAULT_MAX_ATTEMPTS = 3; | ||
public static final Duration DEFAULT_INITIAL_RETRYABLE_INTERVAL = Duration.of( | ||
1, | ||
ChronoUnit.SECONDS | ||
); | ||
/** | ||
* Retry all exceptions by default. | ||
*/ | ||
public static final Predicate<Exception> DEFAULT_RETRYABLE_EXCEPTION = e -> true; | ||
public static final Runnable DEFAULT_ON_RETRY = () -> {}; | ||
private String name; | ||
private int maxAttempts = DEFAULT_MAX_ATTEMPTS; | ||
private Duration initialRetryInterval = DEFAULT_INITIAL_RETRYABLE_INTERVAL; | ||
private int backoffMultiplier; | ||
private Predicate<Exception> retryableException = DEFAULT_RETRYABLE_EXCEPTION; | ||
private Runnable onRetry = DEFAULT_ON_RETRY; | ||
|
||
/** | ||
* Name used in log messages to identify the retried operation. | ||
*/ | ||
public OtpRetryBuilder withName(String name) { | ||
this.name = name; | ||
return this; | ||
} | ||
|
||
/** | ||
* Maximum number of additional attempts after the initial failure. | ||
* With maxAttempts=0 no retry is performed after the initial failure. | ||
*/ | ||
public OtpRetryBuilder withMaxAttempts(int maxAttempts) { | ||
this.maxAttempts = maxAttempts; | ||
return this; | ||
} | ||
|
||
/** | ||
* Initial delay before the first retry. | ||
*/ | ||
public OtpRetryBuilder withInitialRetryInterval(Duration initialRetryInterval) { | ||
this.initialRetryInterval = initialRetryInterval; | ||
return this; | ||
} | ||
|
||
/** | ||
* Backoff multiplier applied to the initial delay. | ||
*/ | ||
public OtpRetryBuilder withBackoffMultiplier(int backoffMultiplier) { | ||
this.backoffMultiplier = backoffMultiplier; | ||
return this; | ||
} | ||
|
||
/** | ||
* Predicate identifying the exceptions that should be retried. | ||
* Other exceptions are re-thrown. | ||
*/ | ||
public OtpRetryBuilder withRetryableException(Predicate<Exception> retryableException) { | ||
this.retryableException = retryableException; | ||
return this; | ||
} | ||
|
||
/** | ||
* Callback invoked before executing each retry. | ||
*/ | ||
public OtpRetryBuilder withOnRetry(Runnable onRetry) { | ||
this.onRetry = onRetry; | ||
return this; | ||
} | ||
|
||
public OtpRetry build() { | ||
return new OtpRetry( | ||
name, | ||
maxAttempts, | ||
initialRetryInterval, | ||
backoffMultiplier, | ||
retryableException, | ||
onRetry | ||
); | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
src/main/java/org/opentripplanner/framework/retry/OtpRetryException.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 |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package org.opentripplanner.framework.retry; | ||
|
||
public class OtpRetryException extends RuntimeException { | ||
|
||
public OtpRetryException(String message, Throwable cause) { | ||
super(message, cause); | ||
} | ||
|
||
public OtpRetryException(Throwable cause) { | ||
super(cause); | ||
} | ||
} |
Oops, something went wrong.