
rocks.xmpp.core.session.ReconnectionStrategy Maven / Gradle / Ivy
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2016 Christian Schudt
*
* 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 rocks.xmpp.core.session;
import rocks.xmpp.core.stream.StreamErrorException;
import rocks.xmpp.core.stream.model.errors.Condition;
import java.time.Duration;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
/**
* A strategy for reconnection logic, i.e. when and in which interval reconnection attempts will happen. You can provide your own strategy by implementing this interface.
*
* Alternatively you can use some of the predefined strategies which you can retrieve by one of the static methods.
*
* E.g. {@link #after(long, TimeUnit)} always tries to reconnect after a fix amount of time.
*
* @author Christian Schudt
* @see ReconnectionManager#setReconnectionStrategy(ReconnectionStrategy)
*/
@FunctionalInterface
public interface ReconnectionStrategy {
default boolean mayReconnect(int attempt, Throwable e) {
// By default allow reconnection only if it's not caused by a stream error.
return !(e instanceof StreamErrorException) || ((StreamErrorException) e).getCondition() != Condition.CONFLICT;
}
/**
* Gets the duration after which the next reconnection is attempted.
*
* @param attempt The current reconnection attempt. The first attempt is 0, the second attempt is 1, etc...
* @param cause The cause for the disconnection.
* @return The the duration after which the next reconnection is attempted.
*/
Duration getNextReconnectionAttempt(int attempt, Throwable cause);
/**
* This is the default reconnection strategy used by the {@link rocks.xmpp.core.session.ReconnectionManager}.
*
* It exponentially increases the time span from which a random value for the next reconnection attempt is chosen.
* The formula for doing this, is: (2n - 1) * s
, where n
is the number of reconnection attempt and s
is the slot time, which is 60 seconds by default.
*
*
* In practice this means, the first reconnection attempt occurs after a random period of time between 0 and 60 seconds.
* The second attempt chooses a random number >= 0 and < 180 seconds.
* The third attempt chooses a random number >= 0 and < 420 seconds.
* The fourth attempt chooses a random number >= 0 and < 900 seconds.
* The fifth attempt chooses a random number >= 0 and < 1860 seconds (= 31 minutes)
*
*
* The strategy is called "truncated", because it won't increase the time span after the nth iteration, which means in the example above, the sixth and any further attempt
* behaves equally to the fifth attempt.
*
* This "truncated binary exponential backoff" is the recommended reconnection strategy by the XMPP specification.
*
* @param slotTime The slot time (in seconds), usually 60.
* @param ceiling The ceiling, i.e. when the time is truncated. E.g. if the ceiling is 4, the back off is truncated at the 5th reconnection attempt (it starts at zero).
* @return The truncated binary exponential backoff strategy.
*/
static ReconnectionStrategy truncatedBinaryExponentialBackoffStrategy(int slotTime, int ceiling) {
return new TruncatedBinaryExponentialBackoffStrategy(slotTime, ceiling);
}
/**
* Reconnects always after a fix duration, e.g. after 10 seconds.
*
* @param duration The fix duration after which a reconnection is attempted.
* @param timeUnit The time unit.
* @return The reconnection strategy.
* @deprecated Use {@link #alwaysAfter(Duration)}
*/
@Deprecated
static ReconnectionStrategy after(long duration, TimeUnit timeUnit) {
return (attempt, cause) -> Duration.ofSeconds(timeUnit.toSeconds(duration));
}
/**
* Reconnects always after a fix duration, e.g. after 10 seconds. When a disconnection is detected the first reconnection attempt is started after the given duration.
* If the attempt fails, the second one is started again after the same duration and so on.
*
* @param duration The fix duration after which a reconnection is attempted.
* @return The reconnection strategy.
*/
static ReconnectionStrategy alwaysAfter(Duration duration) {
return (attempt, cause) -> duration;
}
/**
* Reconnects always after a random duration which lies between the given min and max duration, e.g. after 10-20 seconds.
*
* @param min The min duration after which a reconnection is attempted.
* @param max The max duration.
* @return The reconnection strategy.
*/
static ReconnectionStrategy alwaysRandomlyAfter(Duration min, Duration max) {
return (attempt, cause) -> Duration.ofSeconds(ThreadLocalRandom.current().nextLong(min.getSeconds(), max.getSeconds()));
}
/**
* Uses a hybrid reconnection strategy, which uses the first one on system shutdown and the second one on every other disconnection cause.
*
* @param first The first strategy.
* @param second The second strategy.
* @return The reconnection strategy.
*/
static ReconnectionStrategy onSystemShutdownFirstOrElseSecond(ReconnectionStrategy first, ReconnectionStrategy second) {
return new HybridReconnectionStrategy(first, second, new ReconnectionManager.SystemShutdownPredicate());
}
/**
* Reconnection won't happen automatically, i.e. it's disabled.
*
* @return The reconnection strategy.
*/
static ReconnectionStrategy none() {
return new ReconnectionStrategy() {
@Override
public boolean mayReconnect(int attempt, Throwable cause) {
return false;
}
@Override
public Duration getNextReconnectionAttempt(int attempt, Throwable cause) {
return Duration.ZERO;
}
};
}
}