QueryRunner re-factor

This commit is contained in:
Travis Burtrum 2017-07-03 01:57:52 -04:00
parent 345a4120c8
commit 08e2c9354d
2 changed files with 56 additions and 30 deletions

View File

@ -13,52 +13,70 @@ import static com.moparisthebest.jdbc.TryClose.tryClose;
*/ */
public class QueryRunner<T extends JdbcMapper> { public class QueryRunner<T extends JdbcMapper> {
private static final int defaultRetryCount = 10;
private static final DelayStrategy defaultDelayStrategy = exponentialBackoff(1000, 30000, 2000, 10); private static final DelayStrategy defaultDelayStrategy = exponentialBackoff(1000, 30000, 2000, 10);
private static final ExecutorService defaultExecutorService = Executors.newCachedThreadPool(); // todo: good or bad default? private static final ExecutorService defaultExecutorService =
Executors.newCachedThreadPool()
//ForkJoinPool.commonPool()
; // todo: good or bad default?
private final Factory<T> factory; private final Factory<T> factory;
private final DelayStrategy delayStrategy; private final DelayStrategy delayStrategy;
private final int retryCount; private final int retryCount;
private final ExecutorService executorService; private final ExecutorService executorService;
public QueryRunner(final Factory<T> factory, final DelayStrategy delayStrategy, final ExecutorService executorService, final int retryCount) { private QueryRunner(final Factory<T> factory, final int retryCount, final DelayStrategy delayStrategy, final ExecutorService executorService) {
if (factory == null) if (factory == null)
throw new NullPointerException("factory must be non-null"); throw new NullPointerException("factory must be non-null");
if (delayStrategy == null) if (delayStrategy == null)
throw new NullPointerException("delayStrategy must be non-null"); throw new NullPointerException("delayStrategy must be non-null");
if (executorService == null) if (executorService == null)
throw new NullPointerException("executorService must be non-null"); throw new NullPointerException("executorService must be non-null");
if (retryCount < 1) if (retryCount < 0)
throw new IllegalArgumentException("retryCount must be > 0"); throw new IllegalArgumentException("retryCount must be >= 0");
this.factory = factory; this.factory = factory;
this.delayStrategy = delayStrategy; this.delayStrategy = delayStrategy;
this.retryCount = retryCount; this.retryCount = retryCount;
this.executorService = Executors.newSingleThreadExecutor(); this.executorService = executorService;
} }
public QueryRunner(final Factory<T> factory) { public static <T extends JdbcMapper> QueryRunner<T> noRetry(final Factory<T> factory, final ExecutorService executorService) {
this(factory, defaultDelayStrategy, defaultExecutorService, defaultRetryCount); return new QueryRunner<T>(factory, 0, defaultDelayStrategy, executorService);
} }
public QueryRunner(final Factory<T> factory, final DelayStrategy delayStrategy) { public static <T extends JdbcMapper> QueryRunner<T> noRetry(final Factory<T> factory) {
this(factory, delayStrategy, defaultExecutorService, defaultRetryCount); return noRetry(factory, defaultExecutorService);
} }
public QueryRunner(final Factory<T> factory, final int retryCount) { public static <T extends JdbcMapper> QueryRunner<T> withRetry(final Factory<T> factory, final int retryCount, final DelayStrategy delayStrategy, final ExecutorService executorService) {
this(factory, defaultDelayStrategy, defaultExecutorService, retryCount); return new QueryRunner<T>(factory, retryCount, delayStrategy, executorService);
} }
public QueryRunner(final Factory<T> factory, final ExecutorService executorService) { public static <T extends JdbcMapper> QueryRunner<T> withRetry(final Factory<T> factory, final int retryCount, final DelayStrategy delayStrategy) {
this(factory, defaultDelayStrategy, executorService, defaultRetryCount); return withRetry(factory, retryCount, delayStrategy, defaultExecutorService);
} }
public QueryRunner(final Factory<T> factory, final DelayStrategy delayStrategy, final ExecutorService executorService) { public static <T extends JdbcMapper> QueryRunner<T> withRetry(final Factory<T> factory, final int retryCount) {
this(factory, delayStrategy, executorService, defaultRetryCount); return withRetry(factory, retryCount, defaultDelayStrategy, defaultExecutorService);
} }
public QueryRunner(final Factory<T> factory, final ExecutorService executorService, final int retryCount) { public static <T extends JdbcMapper> QueryRunner<T> withRetry(final Factory<T> factory, final int retryCount, final ExecutorService executorService) {
this(factory, defaultDelayStrategy, executorService, retryCount); return withRetry(factory, retryCount, defaultDelayStrategy, executorService);
}
public QueryRunner<T> withRetryCount(final int retryCount) {
return new QueryRunner<T>(factory, retryCount, delayStrategy, executorService);
}
public QueryRunner<T> withDelayStrategy(final DelayStrategy delayStrategy) {
return new QueryRunner<T>(factory, retryCount, delayStrategy, executorService);
}
public QueryRunner<T> withExecutorService(final ExecutorService executorService) {
return new QueryRunner<T>(factory, retryCount, delayStrategy, executorService);
}
public <T extends JdbcMapper> QueryRunner<T> withFactory(final Factory<T> factory) {
return new QueryRunner<T>(factory, retryCount, delayStrategy, executorService);
} }
public <E> E run(final Runner<T, E> query) throws SQLException { public <E> E run(final Runner<T, E> query) throws SQLException {
@ -109,21 +127,20 @@ public class QueryRunner<T extends JdbcMapper> {
} }
public <E> E runRetry(final Runner<T, E> query) throws SQLException { public <E> E runRetry(final Runner<T, E> query) throws SQLException {
SQLException lastException = null;
int x = 0; int x = 0;
do { while(true) {
try { try {
return runInTransaction(query); return runInTransaction(query);
} catch (SQLException e) { } catch (SQLException e) {
lastException = e; if(x == retryCount)
throw e;
try { try {
Thread.sleep(delayStrategy.getDelay(++x)); Thread.sleep(delayStrategy.getDelay(++x));
} catch (InterruptedException e2) { } catch (InterruptedException e2) {
Thread.interrupted(); Thread.interrupted();
} }
} }
} while (x <= retryCount); }
throw lastException;
} }
public <E> Future<E> runRetryFuture(final Runner<T, E> query) { public <E> Future<E> runRetryFuture(final Runner<T, E> query) {
@ -170,6 +187,9 @@ public class QueryRunner<T extends JdbcMapper> {
return QueryRunner.withJitter(this, maxJitterMs); return QueryRunner.withJitter(this, maxJitterMs);
} }
//IFJAVA8_END //IFJAVA8_END
/*IFJAVA6_START
DelayStrategy withJitter(final int maxJitterMs);
IFJAVA6_END*/
} }
public static DelayStrategy exponentialBackoff() { public static DelayStrategy exponentialBackoff() {
@ -186,7 +206,7 @@ public class QueryRunner<T extends JdbcMapper> {
public static DelayStrategy exponentialBackoff(final long minBackoff, final long maxBackoff, final long slotTime, final long maxContentionPeriods) { public static DelayStrategy exponentialBackoff(final long minBackoff, final long maxBackoff, final long slotTime, final long maxContentionPeriods) {
return return
/*IFJAVA6_START /*IFJAVA6_START
new DelayStrategy() { new AbstractDelayStrategy() {
@Override @Override
public long getDelay(final int attempt) { public long getDelay(final int attempt) {
return return
@ -204,7 +224,7 @@ public class QueryRunner<T extends JdbcMapper> {
public static DelayStrategy fixedDelay(final long delay) { public static DelayStrategy fixedDelay(final long delay) {
return return
/*IFJAVA6_START /*IFJAVA6_START
new DelayStrategy() { new AbstractDelayStrategy() {
@Override @Override
public long getDelay(final int attempt) { public long getDelay(final int attempt) {
return return
@ -222,7 +242,7 @@ public class QueryRunner<T extends JdbcMapper> {
public static DelayStrategy incrementalDelay(final long initialInterval, final long incrementalInterval) { public static DelayStrategy incrementalDelay(final long initialInterval, final long incrementalInterval) {
return return
/*IFJAVA6_START /*IFJAVA6_START
new DelayStrategy() { new AbstractDelayStrategy() {
@Override @Override
public long getDelay(final int attempt) { public long getDelay(final int attempt) {
return return
@ -237,10 +257,10 @@ public class QueryRunner<T extends JdbcMapper> {
IFJAVA6_END*/ IFJAVA6_END*/
} }
public static DelayStrategy withJitter(final DelayStrategy toWrap, final int maxJitterMs) { private static DelayStrategy withJitter(final DelayStrategy toWrap, final int maxJitterMs) {
return return
/*IFJAVA6_START /*IFJAVA6_START
new DelayStrategy() { new AbstractDelayStrategy() {
@Override @Override
public long getDelay(final int attempt) { public long getDelay(final int attempt) {
return return
@ -269,6 +289,11 @@ public class QueryRunner<T extends JdbcMapper> {
return randomThreadLocal.get(); return randomThreadLocal.get();
} }
} }
private static abstract class AbstractDelayStrategy implements DelayStrategy {
public DelayStrategy withJitter(final int maxJitterMs) {
return QueryRunner.withJitter(this, maxJitterMs);
}
}
IFJAVA6_END*/ IFJAVA6_END*/
} }

View File

@ -14,14 +14,15 @@ import static com.moparisthebest.jdbc.QueryMapperTest.*;
* Created by mopar on 7/1/17. * Created by mopar on 7/1/17.
*/ */
public class QueryRunnerTest { public class QueryRunnerTest {
public static final QueryRunner<QueryMapper> qr = new QueryRunner<QueryMapper>(new JdbcMapperFactory<QueryMapper>(QueryMapper.class, new Factory<Connection>() { public static final QueryRunner<QueryMapper> qr = QueryRunner.withRetry(new JdbcMapperFactory<QueryMapper>(QueryMapper.class, new Factory<Connection>() {
@Override @Override
public Connection create() throws SQLException { public Connection create() throws SQLException {
return QueryMapperTest.getConnection(); return QueryMapperTest.getConnection();
} }
}), QueryRunner.withJitter(QueryRunner.fixedDelay(5), 5)); }), 10, QueryRunner.fixedDelay(5).withJitter(5));
private void testPerson(final Person expected, final String query) throws Throwable { private void testPerson(final Person expected, final String query) throws Throwable {
//final QueryRunner<ListQueryMapper> lqr = qr.withFactory(() -> new ListQueryMapper(QueryMapperTest::getConnection));
final Person actual = final Person actual =
//qr.run( //qr.run(
//qr.runRetry( //qr.runRetry(