use of io.lettuce.core.event.connection.ReconnectFailedEvent in project lettuce-core by lettuce-io.
the class ConnectionWatchdog method run.
/**
* Reconnect to the remote address that the closed channel was connected to. This creates a new {@link ChannelPipeline} with
* the same handler instances contained in the old channel's pipeline.
*
* @param attempt attempt counter.
* @param delay retry delay.
*
* @throws Exception when reconnection fails.
*/
private void run(int attempt, Duration delay) throws Exception {
reconnectSchedulerSync.set(false);
reconnectScheduleTimeout = null;
if (!isEventLoopGroupActive()) {
logger.debug("isEventLoopGroupActive() == false");
return;
}
if (!isListenOnChannelInactive()) {
logger.debug("Skip reconnect scheduling, listener disabled");
return;
}
if (isReconnectSuspended()) {
logger.debug("Skip reconnect scheduling, reconnect is suspended");
return;
}
boolean shouldLog = shouldLog();
InternalLogLevel infoLevel = InternalLogLevel.INFO;
InternalLogLevel warnLevel = InternalLogLevel.WARN;
if (shouldLog) {
lastReconnectionLogging = System.currentTimeMillis();
} else {
warnLevel = InternalLogLevel.DEBUG;
infoLevel = InternalLogLevel.DEBUG;
}
InternalLogLevel warnLevelToUse = warnLevel;
try {
reconnectionListener.onReconnectAttempt(new ConnectionEvents.Reconnect(attempt));
eventBus.publish(new ReconnectAttemptEvent(redisUri, epid, LocalAddress.ANY, remoteAddress, attempt, delay));
logger.log(infoLevel, "Reconnecting, last destination was {}", remoteAddress);
Tuple2<CompletableFuture<Channel>, CompletableFuture<SocketAddress>> tuple = reconnectionHandler.reconnect();
CompletableFuture<Channel> future = tuple.getT1();
future.whenComplete((c, t) -> {
if (c != null && t == null) {
return;
}
CompletableFuture<SocketAddress> remoteAddressFuture = tuple.getT2();
SocketAddress remote = remoteAddress;
if (remoteAddressFuture.isDone() && !remoteAddressFuture.isCompletedExceptionally() && !remoteAddressFuture.isCancelled()) {
remote = remoteAddressFuture.join();
}
String message = String.format("Cannot reconnect to [%s]: %s", remote, t.getMessage() != null ? t.getMessage() : t.toString());
if (ReconnectionHandler.isExecutionException(t)) {
if (logger.isDebugEnabled()) {
logger.debug(message, t);
} else {
logger.log(warnLevelToUse, message);
}
} else {
logger.log(warnLevelToUse, message, t);
}
eventBus.publish(new ReconnectFailedEvent(redisUri, epid, LocalAddress.ANY, remote, t, attempt));
if (!isReconnectSuspended()) {
scheduleReconnect();
}
});
} catch (Exception e) {
logger.log(warnLevel, "Cannot reconnect: {}", e.toString());
eventBus.publish(new ReconnectFailedEvent(redisUri, epid, LocalAddress.ANY, remoteAddress, e, attempt));
}
}
use of io.lettuce.core.event.connection.ReconnectFailedEvent in project lettuce-core by lettuce-io.
the class ConnectionFailureIntegrationTests method emitEventOnReconnectFailure.
@Test
void emitEventOnReconnectFailure() throws Exception {
RandomResponseServer ts = getRandomResponseServer();
Queue<Event> queue = new ConcurrentLinkedQueue<>();
ClientResources clientResources = ClientResources.create();
RedisURI redisUri = RedisURI.create(defaultRedisUri.toURI());
RedisClient client = RedisClient.create(clientResources);
client.setOptions(ClientOptions.builder().build());
try {
RedisAsyncCommandsImpl<String, String> connection = (RedisAsyncCommandsImpl<String, String>) client.connect(redisUri).async();
ConnectionWatchdog connectionWatchdog = ConnectionTestUtil.getConnectionWatchdog(connection.getStatefulConnection());
redisUri.setPort(TestSettings.nonexistentPort());
client.getResources().eventBus().get().subscribe(queue::add);
connection.quit();
Wait.untilTrue(() -> !connection.getStatefulConnection().isOpen()).waitOrTimeout();
connectionWatchdog.run(0);
Delay.delay(Duration.ofMillis(500));
connection.getStatefulConnection().close();
assertThat(queue).isNotEmpty();
List<ReconnectFailedEvent> failures = queue.stream().filter(ReconnectFailedEvent.class::isInstance).map(ReconnectFailedEvent.class::cast).sorted(Comparator.comparingInt(ReconnectFailedEvent::getAttempt)).collect(Collectors.toList());
assertThat(failures.size()).isGreaterThanOrEqualTo(2);
ReconnectFailedEvent failure1 = failures.get(0);
assertThat(failure1.localAddress()).isEqualTo(LocalAddress.ANY);
assertThat(failure1.remoteAddress()).isInstanceOf(InetSocketAddress.class);
assertThat(failure1.getCause()).hasMessageContaining("Invalid first byte");
assertThat(failure1.getAttempt()).isZero();
ReconnectFailedEvent failure2 = failures.get(1);
assertThat(failure2.localAddress()).isEqualTo(LocalAddress.ANY);
assertThat(failure2.remoteAddress()).isInstanceOf(InetSocketAddress.class);
assertThat(failure2.getCause()).hasMessageContaining("Invalid first byte");
assertThat(failure2.getAttempt()).isOne();
} finally {
ts.shutdown();
FastShutdown.shutdown(client);
FastShutdown.shutdown(clientResources);
}
}
Aggregations