From e38c3b0ba9f77a8d9caee58f35ee06df9bdf8596 Mon Sep 17 00:00:00 2001 From: monkey <1283045105@qq.com> Date: Sat, 24 Apr 2021 20:20:54 +0800 Subject: [PATCH] issue #707 ExponentialBackOff refactored to interface for custom implementation --- pom.xml | 17 +++++++ .../telegrambots/meta/generics/BackOff.java | 19 ++++++++ .../telegrambots/bots/DefaultBotOptions.java | 16 +++---- .../updatesreceivers/DefaultBotSession.java | 19 ++++---- .../updatesreceivers/ExponentialBackOff.java | 38 +++++++++++++-- .../test/TestDefaultBotSession.java | 48 +++++++++++++++++++ 6 files changed, 133 insertions(+), 24 deletions(-) create mode 100644 telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/generics/BackOff.java diff --git a/pom.xml b/pom.xml index 4f48691c..ae080b72 100644 --- a/pom.xml +++ b/pom.xml @@ -178,6 +178,23 @@ + + diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/generics/BackOff.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/generics/BackOff.java new file mode 100644 index 00000000..9371ec3e --- /dev/null +++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/generics/BackOff.java @@ -0,0 +1,19 @@ +package org.telegram.telegrambots.meta.generics; + +/** + * @author Calvin + * @version 1.0 + * Interface for backoff retries + */ +public interface BackOff { + + /** + * Should be able to reset to the starting + */ + void reset(); + + /** + * specify the next backoff interval in milliseconds + */ + long nextBackOffMillis(); +} diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultBotOptions.java b/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultBotOptions.java index 6437d7c8..18300da1 100644 --- a/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultBotOptions.java +++ b/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultBotOptions.java @@ -5,7 +5,7 @@ import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.protocol.HttpContext; import org.telegram.telegrambots.meta.ApiConstants; import org.telegram.telegrambots.meta.generics.BotOptions; -import org.telegram.telegrambots.updatesreceivers.ExponentialBackOff; +import org.telegram.telegrambots.meta.generics.BackOff; import java.util.List; @@ -19,7 +19,7 @@ public class DefaultBotOptions implements BotOptions { private int maxThreads; ///< Max number of threads used for async methods executions (default 1) private RequestConfig requestConfig; private volatile HttpContext httpContext; - private ExponentialBackOff exponentialBackOff; + private BackOff backOff; private Integer maxWebhookConnections; private String baseUrl; private List allowedUpdates; @@ -91,23 +91,23 @@ public class DefaultBotOptions implements BotOptions { } /** - * @implSpec Default implementation assumes no proxy is needed and sets a 75secs timoute * @param requestConfig Request config to be used in all Http requests + * @implSpec Default implementation assumes no proxy is needed and sets a 75secs timoute */ public void setRequestConfig(RequestConfig requestConfig) { this.requestConfig = requestConfig; } - public ExponentialBackOff getExponentialBackOff() { - return exponentialBackOff; + public BackOff getBackOff() { + return backOff; } /** + * @param BackOff backOff to be used when long polling fails * @implSpec Default implementation assumes starting at 500ms and max time of 60 minutes - * @param exponentialBackOff ExponentialBackOff to be used when long polling fails */ - public void setExponentialBackOff(ExponentialBackOff exponentialBackOff) { - this.exponentialBackOff = exponentialBackOff; + public void setBackOff(BackOff BackOff) { + this.backOff = BackOff; } public ProxyType getProxyType() { diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java b/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java index ef777e51..fec34b3e 100644 --- a/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java +++ b/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java @@ -16,11 +16,7 @@ import org.telegram.telegrambots.facilities.TelegramHttpClientBuilder; import org.telegram.telegrambots.meta.api.methods.updates.GetUpdates; import org.telegram.telegrambots.meta.api.objects.Update; import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException; -import org.telegram.telegrambots.meta.generics.BotOptions; -import org.telegram.telegrambots.meta.generics.BotSession; -import org.telegram.telegrambots.meta.generics.LongPollingBot; -import org.telegram.telegrambots.meta.generics.UpdatesHandler; -import org.telegram.telegrambots.meta.generics.UpdatesReader; +import org.telegram.telegrambots.meta.generics.*; import java.io.IOException; import java.io.InvalidObjectException; @@ -142,7 +138,7 @@ public class DefaultBotSession implements BotSession { private final UpdatesSupplier updatesSupplier; private final Object lock; private CloseableHttpClient httpclient; - private ExponentialBackOff exponentialBackOff; + private BackOff backOff; private RequestConfig requestConfig; public ReaderThread(UpdatesSupplier updatesSupplier, Object lock) { @@ -154,10 +150,11 @@ public class DefaultBotSession implements BotSession { public synchronized void start() { httpclient = TelegramHttpClientBuilder.build(options); requestConfig = options.getRequestConfig(); - exponentialBackOff = options.getExponentialBackOff(); + backOff = options.getBackOff(); - if (exponentialBackOff == null) { - exponentialBackOff = new ExponentialBackOff(); + // fall back to default exponential backoff strategy if no backoff specified + if (backOff == null) { + backOff = new ExponentialBackOff(); } if (requestConfig == null) { @@ -215,7 +212,7 @@ public class DefaultBotSession implements BotSession { log.error(global.getLocalizedMessage(), global); try { synchronized (lock) { - lock.wait(exponentialBackOff.nextBackOffMillis()); + lock.wait(backOff.nextBackOffMillis()); } } catch (InterruptedException e) { if (!running.get()) { @@ -261,7 +258,7 @@ public class DefaultBotSession implements BotSession { } else { try { List updates = request.deserializeResponse(responseContent); - exponentialBackOff.reset(); + backOff.reset(); return updates; } catch (JSONException e) { log.error("Error deserializing update: " + responseContent, e); diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/ExponentialBackOff.java b/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/ExponentialBackOff.java index 80769b29..eeed99ae 100644 --- a/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/ExponentialBackOff.java +++ b/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/ExponentialBackOff.java @@ -14,6 +14,7 @@ package org.telegram.telegrambots.updatesreceivers; import com.google.common.base.Preconditions; +import org.telegram.telegrambots.meta.generics.BackOff; /** * Implementation of BackOff that increases the back off period for each retry attempt using @@ -68,7 +69,7 @@ import com.google.common.base.Preconditions; * @since 1.15 * @author Ravi Mistry */ -public class ExponentialBackOff { +public class ExponentialBackOff implements BackOff { /** The default initial interval value in milliseconds (0.5 seconds). */ private static final int DEFAULT_INITIAL_INTERVAL_MILLIS = 500; @@ -82,7 +83,7 @@ public class ExponentialBackOff { private static final double DEFAULT_MULTIPLIER = 1.5; /** The default maximum back off time in milliseconds (15 minutes). */ - private static final int DEFAULT_MAX_INTERVAL_MILLIS = 30000; + private static final int DEFAULT_MAX_INTERVAL_MILLIS = 900000; /** The default maximum elapsed time in milliseconds (60 minutes). */ private static final int DEFAULT_MAX_ELAPSED_TIME_MILLIS = 3600000; @@ -161,7 +162,8 @@ public class ExponentialBackOff { } /** Sets the interval back to the initial retry interval and restarts the timer. */ - final void reset() { + @Override + public void reset() { currentIntervalMillis = initialIntervalMillis; startTimeNanos = nanoTime(); } @@ -178,7 +180,8 @@ public class ExponentialBackOff { * Subclasses may override if a different algorithm is required. *

*/ - long nextBackOffMillis() { + @Override + public long nextBackOffMillis() { // Make sure we have not gone over the maximum elapsed time. if (getElapsedTimeMillis() > maxElapsedTimeMillis) { return maxElapsedTimeMillis; @@ -274,7 +277,32 @@ public class ExponentialBackOff { */ int maxElapsedTimeMillis = DEFAULT_MAX_ELAPSED_TIME_MILLIS; - Builder() { + public Builder() { + } + + public Builder setInitialIntervalMillis(int initialIntervalMillis) { + this.initialIntervalMillis = initialIntervalMillis; + return this; + } + + public Builder setRandomizationFactor(double randomizationFactor) { + this.randomizationFactor = randomizationFactor; + return this; + } + + public Builder setMultiplier(double multiplier) { + this.multiplier = multiplier; + return this; + } + + public Builder setMaxIntervalMillis(int maxIntervalMillis) { + this.maxIntervalMillis = maxIntervalMillis; + return this; + } + + public Builder setMaxElapsedTimeMillis(int maxElapsedTimeMillis) { + this.maxElapsedTimeMillis = maxElapsedTimeMillis; + return this; } /** Builds a new instance of {@link ExponentialBackOff}. */ diff --git a/telegrambots/src/test/java/org/telegram/telegrambots/test/TestDefaultBotSession.java b/telegrambots/src/test/java/org/telegram/telegrambots/test/TestDefaultBotSession.java index 7a5c77c9..36ec876a 100644 --- a/telegrambots/src/test/java/org/telegram/telegrambots/test/TestDefaultBotSession.java +++ b/telegrambots/src/test/java/org/telegram/telegrambots/test/TestDefaultBotSession.java @@ -15,9 +15,11 @@ import org.mockito.Mockito; import org.telegram.telegrambots.bots.DefaultBotOptions; import org.telegram.telegrambots.meta.TelegramBotsApi; import org.telegram.telegrambots.meta.api.objects.Update; +import org.telegram.telegrambots.meta.generics.BackOff; import org.telegram.telegrambots.meta.generics.LongPollingBot; import org.telegram.telegrambots.test.Fakes.FakeLongPollingBot; import org.telegram.telegrambots.updatesreceivers.DefaultBotSession; +import org.telegram.telegrambots.updatesreceivers.ExponentialBackOff; import java.io.IOException; import java.util.Arrays; @@ -139,6 +141,30 @@ public class TestDefaultBotSession { session.stop(); } + @Test + public void testDefaultBotSessionWithCustomExponentialBackOff() { + ExponentialBackOff ex = new ExponentialBackOff.Builder() + .setInitialIntervalMillis(500) + .setRandomizationFactor(0.5) + .setMultiplier(1.5) + .setMaxIntervalMillis(900000) + .setMaxElapsedTimeMillis(3600000) + .build(); + DefaultBotOptions options = new DefaultBotOptions(); + options.setBackOff(ex); + DefaultBotSession session = new DefaultBotSession(); + session.setOptions(options); + } + + @Test + public void testDefaultBotSessionWithCustomConstantBackOff() { + DefaultBotOptions options = new DefaultBotOptions(); + ConstantBackOff backOff = new ConstantBackOff(3000); + options.setBackOff(backOff); + DefaultBotSession session = new DefaultBotSession(); + session.setOptions(options); + } + private Update[] createFakeUpdates(int count) { return IntStream.range(0, count).mapToObj(x -> { Update mock = Mockito.mock(Update.class); @@ -178,4 +204,26 @@ public class TestDefaultBotSession { session.setOptions(new DefaultBotOptions()); return session; } + + private static class ConstantBackOff implements BackOff { + + private long backOffMillis; + + ConstantBackOff() { + new ConstantBackOff(3000); + } + + ConstantBackOff(long millis) { + this.backOffMillis = millis; + } + + @Override + public void reset() { + } + + @Override + public long nextBackOffMillis() { + return backOffMillis; + } + } }