mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 13:19:52 +01:00
Replace Supplier<Boolean> with more legible ApiCall interface.
This commit is contained in:
@@ -1,9 +0,0 @@
|
|||||||
package org.briarproject.bramble.api;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
|
||||||
public interface Supplier<T> {
|
|
||||||
|
|
||||||
T get();
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
|
import org.briarproject.bramble.mailbox.MailboxApi.TolerableFailureException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for calling an API endpoint with the option to retry the call.
|
||||||
|
*/
|
||||||
|
interface ApiCall {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method makes a synchronous call to an API endpoint and returns
|
||||||
|
* true if the call should be retried, in which case the method may be
|
||||||
|
* called again on the same {@link ApiCall} instance after a delay.
|
||||||
|
*
|
||||||
|
* @return True if the API call needs to be retried, or false if the API
|
||||||
|
* call succeeded or {@link TolerableFailureException failed tolerably}.
|
||||||
|
*/
|
||||||
|
@IoExecutor
|
||||||
|
boolean callApi();
|
||||||
|
}
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
package org.briarproject.bramble.mailbox;
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.Cancellable;
|
import org.briarproject.bramble.api.Cancellable;
|
||||||
import org.briarproject.bramble.api.Supplier;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.mailbox.MailboxApi.TolerableFailureException;
|
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.DAYS;
|
import static java.util.concurrent.TimeUnit.DAYS;
|
||||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||||
@@ -23,15 +21,12 @@ interface MailboxApiCaller {
|
|||||||
long MAX_RETRY_INTERVAL_MS = DAYS.toMillis(1);
|
long MAX_RETRY_INTERVAL_MS = DAYS.toMillis(1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronously calls the given supplier, automatically retrying at
|
* Asynchronously calls the given API call on the {@link IoExecutor},
|
||||||
* increasing intervals until the supplier returns false. The returned
|
* automatically retrying at increasing intervals until the API call
|
||||||
* {@link Cancellable} can be used to cancel any future retries.
|
* returns false or retries are cancelled.
|
||||||
*
|
*
|
||||||
* @param supplier A wrapper for an API call. The supplier's
|
* @return A {@link Cancellable} that can be used to cancel any future
|
||||||
* {@link Supplier#get() get()} method will be called on the
|
* retries.
|
||||||
* {@link IoExecutor}. It should return true if the API call needs to be
|
|
||||||
* retried, or false if the API call succeeded or
|
|
||||||
* {@link TolerableFailureException failed tolerably}.
|
|
||||||
*/
|
*/
|
||||||
Cancellable retryWithBackoff(Supplier<Boolean> supplier);
|
Cancellable retryWithBackoff(ApiCall apiCall);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.bramble.mailbox;
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.Cancellable;
|
import org.briarproject.bramble.api.Cancellable;
|
||||||
import org.briarproject.bramble.api.Supplier;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.system.TaskScheduler;
|
import org.briarproject.bramble.api.system.TaskScheduler;
|
||||||
@@ -31,15 +30,15 @@ class MailboxApiCallerImpl implements MailboxApiCaller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Cancellable retryWithBackoff(Supplier<Boolean> supplier) {
|
public Cancellable retryWithBackoff(ApiCall apiCall) {
|
||||||
Task task = new Task(supplier);
|
Task task = new Task(apiCall);
|
||||||
task.start();
|
task.start();
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Task implements Cancellable {
|
private class Task implements Cancellable {
|
||||||
|
|
||||||
private final Supplier<Boolean> supplier;
|
private final ApiCall apiCall;
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
|
|
||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
@@ -52,8 +51,8 @@ class MailboxApiCallerImpl implements MailboxApiCaller {
|
|||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
private long retryIntervalMs = MIN_RETRY_INTERVAL_MS;
|
private long retryIntervalMs = MIN_RETRY_INTERVAL_MS;
|
||||||
|
|
||||||
private Task(Supplier<Boolean> supplier) {
|
private Task(ApiCall apiCall) {
|
||||||
this.supplier = supplier;
|
this.apiCall = apiCall;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void start() {
|
private void start() {
|
||||||
@@ -68,8 +67,8 @@ class MailboxApiCallerImpl implements MailboxApiCaller {
|
|||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
}
|
}
|
||||||
// The supplier returns true if we should retry
|
// The call returns true if we should retry
|
||||||
if (supplier.get()) {
|
if (apiCall.callApi()) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
scheduledTask = taskScheduler.schedule(this::callApi,
|
scheduledTask = taskScheduler.schedule(this::callApi,
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.briarproject.bramble.mailbox;
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.Supplier;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.mailbox.MailboxApi.ApiException;
|
import org.briarproject.bramble.mailbox.MailboxApi.ApiException;
|
||||||
import org.briarproject.bramble.mailbox.MailboxApi.TolerableFailureException;
|
import org.briarproject.bramble.mailbox.MailboxApi.TolerableFailureException;
|
||||||
@@ -17,17 +16,17 @@ import static org.briarproject.bramble.util.LogUtils.logException;
|
|||||||
* Convenience class for making simple API calls that don't return values.
|
* Convenience class for making simple API calls that don't return values.
|
||||||
*/
|
*/
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public abstract class SimpleApiCall implements Supplier<Boolean> {
|
public abstract class SimpleApiCall implements ApiCall {
|
||||||
|
|
||||||
private static final Logger LOG = getLogger(SimpleApiCall.class.getName());
|
private static final Logger LOG = getLogger(SimpleApiCall.class.getName());
|
||||||
|
|
||||||
abstract void callApi()
|
abstract void tryToCallApi()
|
||||||
throws IOException, ApiException, TolerableFailureException;
|
throws IOException, ApiException, TolerableFailureException;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean get() {
|
public boolean callApi() {
|
||||||
try {
|
try {
|
||||||
callApi();
|
tryToCallApi();
|
||||||
return false; // Succeeded, don't retry
|
return false; // Succeeded, don't retry
|
||||||
} catch (IOException | ApiException e) {
|
} catch (IOException | ApiException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.bramble.mailbox;
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.Cancellable;
|
import org.briarproject.bramble.api.Cancellable;
|
||||||
import org.briarproject.bramble.api.Supplier;
|
|
||||||
import org.briarproject.bramble.api.system.TaskScheduler;
|
import org.briarproject.bramble.api.system.TaskScheduler;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.briarproject.bramble.test.CaptureArgumentAction;
|
import org.briarproject.bramble.test.CaptureArgumentAction;
|
||||||
@@ -23,8 +22,7 @@ public class MailboxApiCallerImplTest extends BrambleMockTestCase {
|
|||||||
private final TaskScheduler taskScheduler =
|
private final TaskScheduler taskScheduler =
|
||||||
context.mock(TaskScheduler.class);
|
context.mock(TaskScheduler.class);
|
||||||
private final Executor ioExecutor = context.mock(Executor.class);
|
private final Executor ioExecutor = context.mock(Executor.class);
|
||||||
private final BooleanSupplier supplier =
|
private final ApiCall apiCall = context.mock(ApiCall.class);
|
||||||
context.mock(BooleanSupplier.class);
|
|
||||||
private final Cancellable scheduledTask = context.mock(Cancellable.class);
|
private final Cancellable scheduledTask = context.mock(Cancellable.class);
|
||||||
|
|
||||||
private final MailboxApiCallerImpl caller =
|
private final MailboxApiCallerImpl caller =
|
||||||
@@ -39,12 +37,12 @@ public class MailboxApiCallerImplTest extends BrambleMockTestCase {
|
|||||||
will(new CaptureArgumentAction<>(runnable, Runnable.class, 0));
|
will(new CaptureArgumentAction<>(runnable, Runnable.class, 0));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
caller.retryWithBackoff(supplier);
|
caller.retryWithBackoff(apiCall);
|
||||||
|
|
||||||
// When the task runs, the supplier should be called. The supplier
|
// When the task runs, the API call should be called. The call
|
||||||
// returns false, so no retries should be scheduled
|
// returns false, so no retries should be scheduled
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(supplier).get();
|
oneOf(apiCall).callApi();
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
@@ -60,12 +58,12 @@ public class MailboxApiCallerImplTest extends BrambleMockTestCase {
|
|||||||
will(new CaptureArgumentAction<>(runnable, Runnable.class, 0));
|
will(new CaptureArgumentAction<>(runnable, Runnable.class, 0));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
Cancellable returned = caller.retryWithBackoff(supplier);
|
Cancellable returned = caller.retryWithBackoff(apiCall);
|
||||||
|
|
||||||
// When the task runs, the supplier should be called. The supplier
|
// When the task runs, the API call should be called. The call
|
||||||
// returns true, so a retry should be scheduled
|
// returns true, so a retry should be scheduled
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(supplier).get();
|
oneOf(apiCall).callApi();
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(taskScheduler).schedule(with(any(Runnable.class)),
|
oneOf(taskScheduler).schedule(with(any(Runnable.class)),
|
||||||
with(ioExecutor), with(MIN_RETRY_INTERVAL_MS),
|
with(ioExecutor), with(MIN_RETRY_INTERVAL_MS),
|
||||||
@@ -90,7 +88,7 @@ public class MailboxApiCallerImplTest extends BrambleMockTestCase {
|
|||||||
returned.cancel();
|
returned.cancel();
|
||||||
|
|
||||||
// If the scheduled task runs anyway (cancellation came too late),
|
// If the scheduled task runs anyway (cancellation came too late),
|
||||||
// the supplier should not be called and no further tries should be
|
// the API call should not be called and no further tries should be
|
||||||
// scheduled
|
// scheduled
|
||||||
runnable.get().run();
|
runnable.get().run();
|
||||||
}
|
}
|
||||||
@@ -114,13 +112,13 @@ public class MailboxApiCallerImplTest extends BrambleMockTestCase {
|
|||||||
will(new CaptureArgumentAction<>(runnable, Runnable.class, 0));
|
will(new CaptureArgumentAction<>(runnable, Runnable.class, 0));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
caller.retryWithBackoff(supplier);
|
caller.retryWithBackoff(apiCall);
|
||||||
|
|
||||||
// Each time the task runs, the supplier returns true, so a retry
|
// Each time the task runs, the API call returns true, so a retry
|
||||||
// should be scheduled with a longer interval
|
// should be scheduled with a longer interval
|
||||||
for (long interval : expectedIntervals) {
|
for (long interval : expectedIntervals) {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(supplier).get();
|
oneOf(apiCall).callApi();
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(taskScheduler).schedule(with(any(Runnable.class)),
|
oneOf(taskScheduler).schedule(with(any(Runnable.class)),
|
||||||
with(ioExecutor), with(interval), with(MILLISECONDS));
|
with(ioExecutor), with(interval), with(MILLISECONDS));
|
||||||
@@ -134,8 +132,4 @@ public class MailboxApiCallerImplTest extends BrambleMockTestCase {
|
|||||||
runnable.get().run();
|
runnable.get().run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reify the generic type to mollify jMock
|
|
||||||
private interface BooleanSupplier extends Supplier<Boolean> {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user