(NEW) Module "retry"
(NEW) Illustrative classes: - App: simulates a production application - BusinessOperation<T>: abstraction over any operation that can potentially fail - FindCustomer <: BusinessOperation<String>: illustrative operation that can throw an error - Retry <: BusinessOperation<T>: transparently implements the retry mechanism - Several "business" exceptions: - BusinessException: top-level - CustomerNotFoundException: can be ignored - DatabaseNotAvailableException: fatal error (NEW) .puml and .png for UML
This commit is contained in:
107
retry/src/main/java/com/iluwatar/retry/App.java
Normal file
107
retry/src/main/java/com/iluwatar/retry/App.java
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.retry;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The <em>Retry</em> pattern enables applications to handle potentially recoverable failures from
|
||||
* the environment if the business requirements and nature of the failures allow it. By retrying
|
||||
* failed operations on external dependencies, the application may maintain stability and minimize
|
||||
* negative impact on the user experience.
|
||||
* <p>
|
||||
* In our example, we have the {@link BusinessOperation} interface as an abstraction over
|
||||
* all operations that our application performs involving remote systems. The calling code should
|
||||
* remain decoupled from implementations.
|
||||
* <p>
|
||||
* {@link FindCustomer} is a business operation that looks up a customer's record and returns
|
||||
* its ID. Imagine its job is performed by looking up the customer in our local database and
|
||||
* returning its ID. We can pass {@link CustomerNotFoundException} as one of its
|
||||
* {@link FindCustomer#FindCustomer(java.lang.String, com.iluwatar.retry.BusinessException...)
|
||||
* constructor parameters} in order to simulate not finding the customer.
|
||||
* <p>
|
||||
* Imagine that, lately, this operation has experienced intermittent failures due to some weird
|
||||
* corruption and/or locking in the data. After retrying a few times the customer is found. The
|
||||
* database is still, however, expected to always be available. While a definitive solution is
|
||||
* found to the problem, our engineers advise us to retry the operation a set number
|
||||
* of times with a set delay between retries, although not too many retries otherwise the end user
|
||||
* will be left waiting for a long time, while delays that are too short will not allow the database
|
||||
* to recover from the load.
|
||||
* <p>
|
||||
* To keep the calling code as decoupled as possible from this workaround, we have implemented the
|
||||
* retry mechanism as a {@link BusinessOperation} named {@link Retry}.
|
||||
*
|
||||
* @author George Aristy (george.aristy@gmail.com)
|
||||
* @see <a href="https://docs.microsoft.com/en-us/azure/architecture/patterns/retry">Retry pattern (Microsoft Azure Docs)</a>
|
||||
* @since 1.17.0
|
||||
*/
|
||||
public final class App {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(App.class);
|
||||
private static BusinessOperation<String> op;
|
||||
|
||||
/**
|
||||
* Entry point.
|
||||
*
|
||||
* @param args not used
|
||||
* @throws Exception not expected
|
||||
* @since 1.17.0
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
noErrors();
|
||||
errorNoRetry();
|
||||
errorWithRetry();
|
||||
}
|
||||
|
||||
private static void noErrors() throws Exception {
|
||||
op = new FindCustomer("123");
|
||||
op.perform();
|
||||
LOG.info("Sometimes the operation executes with no errors.");
|
||||
}
|
||||
|
||||
private static void errorNoRetry() throws Exception {
|
||||
op = new FindCustomer("123", new CustomerNotFoundException("not found"));
|
||||
try {
|
||||
op.perform();
|
||||
} catch (CustomerNotFoundException e) {
|
||||
LOG.info("Yet the operation will throw an error every once in a while.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void errorWithRetry() throws Exception {
|
||||
final Retry<String> retry = new Retry<>(
|
||||
new FindCustomer("123", new CustomerNotFoundException("not found")),
|
||||
3, //3 attempts
|
||||
100, //100 ms delay between attempts
|
||||
e -> CustomerNotFoundException.class.isAssignableFrom(e.getClass())
|
||||
);
|
||||
op = retry;
|
||||
final String customerId = op.perform();
|
||||
LOG.info(String.format(
|
||||
"However, retrying the operation while ignoring a recoverable error will eventually yield "
|
||||
+ "the result %s after a number of attempts %s", customerId, retry.attempts()
|
||||
));
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.retry;
|
||||
|
||||
/**
|
||||
* The top-most type in our exception hierarchy that signifies that an unexpected error
|
||||
* condition occurred. Its use is reserved as a "catch-all" for cases where no other subtype
|
||||
* captures the specificity of the error condition in question. Calling code is not expected to
|
||||
* be able to handle this error and should be reported to the maintainers immediately.
|
||||
*
|
||||
* @author George Aristy (george.aristy@gmail.com)
|
||||
* @since 1.17.0
|
||||
*/
|
||||
public class BusinessException extends Exception {
|
||||
private static final long serialVersionUID = 6235833142062144336L;
|
||||
|
||||
/**
|
||||
* Ctor
|
||||
*
|
||||
* @param message the error message
|
||||
* @since 1.17.0
|
||||
*/
|
||||
public BusinessException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.retry;
|
||||
|
||||
/**
|
||||
* Performs some business operation.
|
||||
*
|
||||
* @author George Aristy (george.aristy@gmail.com)
|
||||
* @param <T> the return type
|
||||
* @since 1.17.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface BusinessOperation<T> {
|
||||
/**
|
||||
* Performs some business operation, returning a value {@code T} if successful, otherwise throwing
|
||||
* an exception if an error occurs.
|
||||
*
|
||||
* @return the return value
|
||||
* @throws BusinessException if the operation fails. Implementations are allowed to throw more
|
||||
* specific subtypes depending on the error conditions
|
||||
* @since 1.17.0
|
||||
*/
|
||||
T perform() throws BusinessException;
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.retry;
|
||||
|
||||
/**
|
||||
* Indicates that the customer was not found.
|
||||
* <p>
|
||||
* The severity of this error is bounded by its context: was the search for the customer triggered
|
||||
* by an input from some end user, or were the search parameters pulled from your database?
|
||||
*
|
||||
* @author George Aristy (george.aristy@gmail.com)
|
||||
* @since 1.17.0
|
||||
*/
|
||||
public final class CustomerNotFoundException extends BusinessException {
|
||||
private static final long serialVersionUID = -6972888602621778664L;
|
||||
|
||||
/**
|
||||
* Ctor.
|
||||
*
|
||||
* @param message the error message
|
||||
* @since 1.17.0
|
||||
*/
|
||||
public CustomerNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.retry;
|
||||
|
||||
/**
|
||||
* Catastrophic error indicating that we have lost connection to our database.
|
||||
*
|
||||
* @author George Aristy (george.aristy@gmail.com)
|
||||
* @since 1.17.0
|
||||
*/
|
||||
public final class DatabaseNotAvailableException extends BusinessException {
|
||||
private static final long serialVersionUID = -3750769625095997799L;
|
||||
|
||||
/**
|
||||
* Ctor.
|
||||
*
|
||||
* @param message the error message
|
||||
* @since 1.17.0
|
||||
*/
|
||||
public DatabaseNotAvailableException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
65
retry/src/main/java/com/iluwatar/retry/FindCustomer.java
Normal file
65
retry/src/main/java/com/iluwatar/retry/FindCustomer.java
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.retry;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Arrays;
|
||||
import java.util.Deque;
|
||||
|
||||
/**
|
||||
* Finds a customer, returning its ID from our records.
|
||||
* <p>
|
||||
* This is an imaginary operation that, for some imagined input, returns the ID for a customer.
|
||||
* However, this is a "flaky" operation that is supposed to fail intermittently, but for the
|
||||
* purposes of this example it fails in a programmed way depending on the constructor parameters.
|
||||
*
|
||||
* @author George Aristy (george.aristy@gmail.com)
|
||||
* @since 1.17.0
|
||||
*/
|
||||
public final class FindCustomer implements BusinessOperation<String> {
|
||||
private final String customerId;
|
||||
private final Deque<BusinessException> errors;
|
||||
|
||||
/**
|
||||
* Ctor.
|
||||
*
|
||||
* @param customerId the final result of the remote operation
|
||||
* @param errors the errors to throw before returning {@code customerId}
|
||||
* @since 1.17.0
|
||||
*/
|
||||
public FindCustomer(String customerId, BusinessException... errors) {
|
||||
this.customerId = customerId;
|
||||
this.errors = new ArrayDeque<>(Arrays.asList(errors));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String perform() throws BusinessException {
|
||||
if (!this.errors.isEmpty()) {
|
||||
throw this.errors.pop();
|
||||
}
|
||||
|
||||
return this.customerId;
|
||||
}
|
||||
}
|
114
retry/src/main/java/com/iluwatar/retry/Retry.java
Normal file
114
retry/src/main/java/com/iluwatar/retry/Retry.java
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.retry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Decorates {@link BusinessOperation business operation} with "retry" capabilities.
|
||||
*
|
||||
* @author George Aristy (george.aristy@gmail.com)
|
||||
* @param <T> the remote op's return type
|
||||
* @since 1.17.0
|
||||
*/
|
||||
public final class Retry<T> implements BusinessOperation<T> {
|
||||
private final BusinessOperation<T> op;
|
||||
private final int maxAttempts;
|
||||
private final long delay;
|
||||
private final AtomicInteger attempts;
|
||||
private final Predicate<Exception> test;
|
||||
private final List<Exception> errors;
|
||||
|
||||
/**
|
||||
* Ctor.
|
||||
*
|
||||
* @param op the {@link BusinessOperation} to retry
|
||||
* @param maxAttempts number of times to retry
|
||||
* @param delay delay (in milliseconds) between attempts
|
||||
* @param ignoreTests tests to check whether the remote exception can be ignored. No exceptions
|
||||
* will be ignored if no tests are given
|
||||
* @since 1.17.0
|
||||
*/
|
||||
@SafeVarargs
|
||||
public Retry(
|
||||
BusinessOperation<T> op,
|
||||
int maxAttempts,
|
||||
long delay,
|
||||
Predicate<Exception>... ignoreTests
|
||||
) {
|
||||
this.op = op;
|
||||
this.maxAttempts = maxAttempts;
|
||||
this.delay = delay;
|
||||
this.attempts = new AtomicInteger();
|
||||
this.test = Arrays.stream(ignoreTests).reduce(Predicate::or).orElse(e -> false);
|
||||
this.errors = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* The errors encountered while retrying, in the encounter order.
|
||||
*
|
||||
* @return the errors encountered while retrying
|
||||
* @since 1.17.0
|
||||
*/
|
||||
public List<Exception> errors() {
|
||||
return Collections.unmodifiableList(this.errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of retries performed.
|
||||
*
|
||||
* @return the number of retries performed
|
||||
* @since 1.17.0
|
||||
*/
|
||||
public int attempts() {
|
||||
return this.attempts.intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T perform() throws BusinessException {
|
||||
do {
|
||||
try {
|
||||
return this.op.perform();
|
||||
} catch (BusinessException e) {
|
||||
this.errors.add(e);
|
||||
|
||||
if (this.attempts.incrementAndGet() >= this.maxAttempts || !this.test.test(e)) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(this.delay);
|
||||
} catch (InterruptedException f) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
}
|
91
retry/src/test/java/com/iluwatar/retry/FindCustomerTest.java
Normal file
91
retry/src/test/java/com/iluwatar/retry/FindCustomerTest.java
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.retry;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link FindCustomer}.
|
||||
*
|
||||
* @author George Aristy (george.aristy@gmail.com)
|
||||
* @since 1.17.0
|
||||
*/
|
||||
public class FindCustomerTest {
|
||||
/**
|
||||
* Returns the given result with no exceptions.
|
||||
*
|
||||
* @since 1.17.0
|
||||
*/
|
||||
@Test
|
||||
public void noExceptions() throws Exception {
|
||||
assertThat(
|
||||
new FindCustomer("123").perform(),
|
||||
is("123")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws the given exception.
|
||||
*
|
||||
* @throws Exception the expected exception
|
||||
* @since 1.17.0
|
||||
*/
|
||||
@Test(expected = BusinessException.class)
|
||||
public void oneException() throws Exception {
|
||||
new FindCustomer("123", new BusinessException("test")).perform();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should first throw the given exceptions, then return the given result.
|
||||
*
|
||||
* @throws Exception not an expected exception
|
||||
* @since 1.17.0
|
||||
*/
|
||||
@Test
|
||||
public void resultAfterExceptions() throws Exception {
|
||||
final BusinessOperation<String> op = new FindCustomer(
|
||||
"123",
|
||||
new CustomerNotFoundException("not found"),
|
||||
new DatabaseNotAvailableException("not available")
|
||||
);
|
||||
try {
|
||||
op.perform();
|
||||
} catch (CustomerNotFoundException e) {
|
||||
//ignore
|
||||
}
|
||||
try {
|
||||
op.perform();
|
||||
} catch (DatabaseNotAvailableException e) {
|
||||
//ignore
|
||||
}
|
||||
|
||||
assertThat(
|
||||
op.perform(),
|
||||
is("123")
|
||||
);
|
||||
}
|
||||
}
|
117
retry/src/test/java/com/iluwatar/retry/RetryTest.java
Normal file
117
retry/src/test/java/com/iluwatar/retry/RetryTest.java
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.retry;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.hasItem;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link Retry}.
|
||||
*
|
||||
* @author George Aristy (george.aristy@gmail.com)
|
||||
* @since 1.17.0
|
||||
*/
|
||||
public class RetryTest {
|
||||
/**
|
||||
* Should contain all errors thrown.
|
||||
*
|
||||
* @since 1.17.0
|
||||
*/
|
||||
@Test
|
||||
public void errors() throws Exception {
|
||||
final BusinessException e = new BusinessException("unhandled");
|
||||
final Retry<String> retry = new Retry<>(
|
||||
() -> { throw e; },
|
||||
2,
|
||||
0
|
||||
);
|
||||
try {
|
||||
retry.perform();
|
||||
} catch (BusinessException ex) {
|
||||
//ignore
|
||||
}
|
||||
|
||||
assertThat(
|
||||
retry.errors(),
|
||||
hasItem(e)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* No exceptions will be ignored, hence final number of attempts should be 1 even if we're asking
|
||||
* it to attempt twice.
|
||||
*
|
||||
* @since 1.17.0
|
||||
*/
|
||||
@Test
|
||||
public void attempts() {
|
||||
final BusinessException e = new BusinessException("unhandled");
|
||||
final Retry<String> retry = new Retry<>(
|
||||
() -> { throw e; },
|
||||
2,
|
||||
0
|
||||
);
|
||||
try {
|
||||
retry.perform();
|
||||
} catch (BusinessException ex) {
|
||||
//ignore
|
||||
}
|
||||
|
||||
assertThat(
|
||||
retry.attempts(),
|
||||
is(1)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Final number of attempts should be equal to the number of attempts asked because we are
|
||||
* asking it to ignore the exception that will be thrown.
|
||||
*
|
||||
* @since 1.17.0
|
||||
*/
|
||||
@Test
|
||||
public void ignore() throws Exception {
|
||||
final BusinessException e = new CustomerNotFoundException("customer not found");
|
||||
final Retry<String> retry = new Retry<>(
|
||||
() -> { throw e; },
|
||||
2,
|
||||
0,
|
||||
ex -> CustomerNotFoundException.class.isAssignableFrom(ex.getClass())
|
||||
);
|
||||
try {
|
||||
retry.perform();
|
||||
} catch (BusinessException ex) {
|
||||
//ignore
|
||||
}
|
||||
|
||||
assertThat(
|
||||
retry.attempts(),
|
||||
is(2)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user