Search in sources :

Example 1 with ReconnectFailedEvent

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));
    }
}
Also used : Channel(io.netty.channel.Channel) ReconnectAttemptEvent(io.lettuce.core.event.connection.ReconnectAttemptEvent) ReconnectFailedEvent(io.lettuce.core.event.connection.ReconnectFailedEvent) InternalLogLevel(io.netty.util.internal.logging.InternalLogLevel) ConnectionEvents(io.lettuce.core.ConnectionEvents) CompletableFuture(java.util.concurrent.CompletableFuture) SocketAddress(java.net.SocketAddress)

Example 2 with ReconnectFailedEvent

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);
    }
}
Also used : ClientResources(io.lettuce.core.resource.ClientResources) ReconnectFailedEvent(io.lettuce.core.event.connection.ReconnectFailedEvent) RandomResponseServer(io.lettuce.test.server.RandomResponseServer) Event(io.lettuce.core.event.Event) ReconnectFailedEvent(io.lettuce.core.event.connection.ReconnectFailedEvent) Test(org.junit.jupiter.api.Test)

Aggregations

ReconnectFailedEvent (io.lettuce.core.event.connection.ReconnectFailedEvent)2 ConnectionEvents (io.lettuce.core.ConnectionEvents)1 Event (io.lettuce.core.event.Event)1 ReconnectAttemptEvent (io.lettuce.core.event.connection.ReconnectAttemptEvent)1 ClientResources (io.lettuce.core.resource.ClientResources)1 RandomResponseServer (io.lettuce.test.server.RandomResponseServer)1 Channel (io.netty.channel.Channel)1 InternalLogLevel (io.netty.util.internal.logging.InternalLogLevel)1 SocketAddress (java.net.SocketAddress)1 CompletableFuture (java.util.concurrent.CompletableFuture)1 Test (org.junit.jupiter.api.Test)1