Skip to content

Commit

Permalink
Modified PNReconnectionPolicy
Browse files Browse the repository at this point in the history
Default and max value for maximumReconnectionRetries is 10
Added random value 0,001-2,999s to delay between retry both for Linear and Exponential policy.
  • Loading branch information
marcin-cebo committed Dec 15, 2023
1 parent 9ff499f commit 4e5f052
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 21 deletions.
7 changes: 5 additions & 2 deletions src/main/java/com/pubnub/api/PNConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public class PNConfiguration {
private static final int SUBSCRIBE_TIMEOUT = 310;
private static final int CONNECT_TIMEOUT = 5;
private static final int FILE_MESSAGE_PUBLISH_RETRY_LIMIT = 5;
private static final int MAXIMUM_RECONNECTION_RETRIES = 10;

@Getter
private SSLSocketFactory sslSocketFactory;
Expand Down Expand Up @@ -201,7 +202,9 @@ public void setUserId(@NotNull UserId userId) {
private PNReconnectionPolicy reconnectionPolicy;

/**
* Set how many times the reconneciton manager will try to connect before giving app
* Set how many times the reconnection manager will try to connect before giving up.
* Max allowed value is 10.
* Default is 10.
*/
@Setter
private int maximumReconnectionRetries;
Expand Down Expand Up @@ -284,7 +287,7 @@ public PNConfiguration(@NotNull UserId userId) throws PubNubException {

startSubscriberThread = true;

maximumReconnectionRetries = -1;
maximumReconnectionRetries = MAXIMUM_RECONNECTION_RETRIES;

dedupOnSubscribe = false;
suppressLeaveEvents = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,21 @@
import com.pubnub.api.enums.PNReconnectionPolicy;
import lombok.extern.slf4j.Slf4j;

import java.text.DecimalFormat;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

@Slf4j
public class DelayedReconnectionManager {
private static final int DELAY_SECONDS = 3;
private static final int MAX_RANDOM = 3;
private static final int MILLISECONDS = 1000;

private final PNReconnectionPolicy pnReconnectionPolicy;
private ReconnectionCallback callback;
private PubNub pubnub;
private Random random = new Random();

/**
* Timer for heartbeat operations.
Expand All @@ -34,12 +38,13 @@ public void scheduleDelayedReconnection() {
}

timer = new Timer("Delayed Reconnection Manager timer", true);
int effectiveDelayInMilliSeconds = (int) ((DELAY_SECONDS + getRandomDelay()) * MILLISECONDS);
timer.schedule(new TimerTask() {
@Override
public void run() {
callTime();
}
}, DELAY_SECONDS * MILLISECONDS);
}, effectiveDelayInMilliSeconds);
}

public void setReconnectionListener(ReconnectionCallback reconnectionCallback) {
Expand All @@ -61,8 +66,19 @@ private boolean isReconnectionPolicyUndefined() {
return false;
}

private double getRandomDelay() {
double randomDelay = MAX_RANDOM * random.nextDouble();
randomDelay = roundTo3DecimalPlaces(randomDelay);
return randomDelay;
}

private void callTime() {
stop();
callback.onReconnection();
}

private double roundTo3DecimalPlaces(double value) {
DecimalFormat decimalFormat = new DecimalFormat("#.###");
return Double.parseDouble(decimalFormat.format(value));
}
}
46 changes: 35 additions & 11 deletions src/main/java/com/pubnub/api/managers/ReconnectionManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;

import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

Expand All @@ -18,10 +20,12 @@
public class ReconnectionManager {

private static final int LINEAR_INTERVAL = 3;
private static final int MIN_EXPONENTIAL_BACKOFF = 1;
private static final int MAX_RANDOM = 3;
private static final int MIN_EXPONENTIAL_BACKOFF = 2;
private static final int MAX_EXPONENTIAL_BACKOFF = 32;

private static final int MILLISECONDS = 1000;
public static final int MAXIMUM_RECONNECTION_RETRIES_DEFAULT = 10;

private ReconnectionCallback callback;
private PubNub pubnub;
Expand All @@ -31,6 +35,7 @@ public class ReconnectionManager {

private PNReconnectionPolicy pnReconnectionPolicy;
private int maxConnectionRetries;
private Random random = new Random();

/**
* Timer for heartbeat operations.
Expand All @@ -40,7 +45,16 @@ public class ReconnectionManager {
public ReconnectionManager(PubNub pubnub) {
this.pubnub = pubnub;
this.pnReconnectionPolicy = pubnub.getConfiguration().getReconnectionPolicy();
this.maxConnectionRetries = pubnub.getConfiguration().getMaximumReconnectionRetries();
this.maxConnectionRetries = getMaximumReconnectionRetries();
}

private int getMaximumReconnectionRetries() {
int maximumReconnectionRetries = pubnub.getConfiguration().getMaximumReconnectionRetries();
if (maximumReconnectionRetries < 0 || maximumReconnectionRetries > MAXIMUM_RECONNECTION_RETRIES_DEFAULT) {
maximumReconnectionRetries = MAXIMUM_RECONNECTION_RETRIES_DEFAULT;
}
log.debug("maximumReconnectionRetries is: " + maximumReconnectionRetries);
return maximumReconnectionRetries;
}

public void setReconnectionListener(ReconnectionCallback reconnectionCallback) {
Expand All @@ -55,18 +69,18 @@ public void startPolling() {
exponentialMultiplier = 1;
failedCalls = 0;

registerHeartbeatTimer();
registerRetryTimer();
}

private void registerHeartbeatTimer() {
private void registerRetryTimer() {
// make sure only one timer is running at a time.
stopHeartbeatTimer();

if (isReconnectionPolicyUndefined()) {
return;
}

if (maxConnectionRetries != -1 && failedCalls >= maxConnectionRetries) { // _what's -1?
if (failedCalls >= maxConnectionRetries) {
callback.onMaxReconnectionExhaustion();
return;
}
Expand All @@ -78,10 +92,10 @@ private void registerHeartbeatTimer() {
public void run() {
callTime();
}
}, getNextInterval() * MILLISECONDS);
}, getNextIntervalInMilliSeconds());
}

int getNextInterval() {
int getNextIntervalInMilliSeconds() {
int timerInterval = LINEAR_INTERVAL;
failedCalls++;

Expand All @@ -95,16 +109,26 @@ int getNextInterval() {
} else if (timerInterval < 1) {
timerInterval = MIN_EXPONENTIAL_BACKOFF;
}
log.debug("timerInterval = " + timerInterval + " at: " + Calendar.getInstance().getTime().toString());
timerInterval = (int) ((timerInterval + getRandomDelay()) * MILLISECONDS);
log.debug("timerInterval = " + timerInterval + "ms at: " + Calendar.getInstance().getTime().toString());
}

if (pnReconnectionPolicy == PNReconnectionPolicy.LINEAR) {
timerInterval = LINEAR_INTERVAL;
timerInterval = (int) ((LINEAR_INTERVAL + getRandomDelay()) * MILLISECONDS);
}

return timerInterval;
}

private double getRandomDelay() {
double randomDelay = MAX_RANDOM * random.nextDouble();
return roundTo3DecimalPlaces(randomDelay);
}

private double roundTo3DecimalPlaces(double value) {
DecimalFormat decimalFormat = new DecimalFormat("#.###");
return Double.parseDouble(decimalFormat.format(value));
}

private void stopHeartbeatTimer() {
if (timer != null) {
timer.cancel();
Expand All @@ -121,7 +145,7 @@ public void onResponse(PNTimeResult result, @NotNull PNStatus status) {
callback.onReconnection();
} else {
log.debug("callTime() at: " + Calendar.getInstance().getTime().toString());
registerHeartbeatTimer();
registerRetryTimer();
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

import java.util.UUID;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class ReconnectionManagerTest {
Expand All @@ -20,10 +19,11 @@ public void reconnectionIntervalsEqualsForLinear() throws PubNubException {
pnConfiguration.setReconnectionPolicy(PNReconnectionPolicy.LINEAR);
final ReconnectionManager reconnectionManagerUnderTest = new ReconnectionManager(pubNub);

int firstInterval = reconnectionManagerUnderTest.getNextInterval();
int secondInterval = reconnectionManagerUnderTest.getNextInterval();
int firstInterval = reconnectionManagerUnderTest.getNextIntervalInMilliSeconds();
int secondInterval = reconnectionManagerUnderTest.getNextIntervalInMilliSeconds();

assertEquals(secondInterval, firstInterval);
assertTrue(firstInterval >= 3000 && firstInterval <= 6000);
assertTrue(secondInterval >= 3000 && secondInterval <= 6000);
}

@Test
Expand All @@ -33,9 +33,9 @@ public void reconnectionIntervalsIncreaseForExponential() throws PubNubException
PubNub pubNub = new PubNub(pnConfiguration);
final ReconnectionManager reconnectionManagerUnderTest = new ReconnectionManager(pubNub);

int firstInterval = reconnectionManagerUnderTest.getNextInterval();
int secondInterval = reconnectionManagerUnderTest.getNextInterval();
int thirdInterval = reconnectionManagerUnderTest.getNextInterval();
int firstInterval = reconnectionManagerUnderTest.getNextIntervalInMilliSeconds();
int secondInterval = reconnectionManagerUnderTest.getNextIntervalInMilliSeconds();
int thirdInterval = reconnectionManagerUnderTest.getNextIntervalInMilliSeconds();

assertTrue(firstInterval < secondInterval);
assertTrue(secondInterval < thirdInterval);
Expand Down

0 comments on commit 4e5f052

Please sign in to comment.