
io.lettuce.core.pubsub.StatefulRedisPubSubConnectionImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lettuce-core Show documentation
Show all versions of lettuce-core Show documentation
Advanced and thread-safe Java Redis client for synchronous, asynchronous, and
reactive usage. Supports Cluster, Sentinel, Pipelining, Auto-Reconnect, Codecs
and much more.
The newest version!
/*
* Copyright 2011-Present, Redis Ltd. and Contributors
* All rights reserved.
*
* Licensed under the MIT License.
*
* This file contains contributions from third-party contributors
* licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.lettuce.core.pubsub;
import java.lang.reflect.Array;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import io.lettuce.core.RedisChannelWriter;
import io.lettuce.core.RedisCommandExecutionException;
import io.lettuce.core.RedisFuture;
import io.lettuce.core.StatefulRedisConnectionImpl;
import io.lettuce.core.codec.RedisCodec;
import io.lettuce.core.protocol.ConnectionWatchdog;
import io.lettuce.core.pubsub.api.async.RedisPubSubAsyncCommands;
import io.lettuce.core.pubsub.api.reactive.RedisPubSubReactiveCommands;
import io.lettuce.core.pubsub.api.sync.RedisPubSubCommands;
import io.netty.util.internal.logging.InternalLoggerFactory;
import static io.lettuce.core.ClientOptions.DEFAULT_JSON_PARSER;
/**
* An thread-safe pub/sub connection to a Redis server. Multiple threads may share one {@link StatefulRedisPubSubConnectionImpl}
*
* A {@link ConnectionWatchdog} monitors each connection and reconnects automatically until {@link #close} is called. All
* pending commands will be (re)sent after successful reconnection.
*
* @param Key type.
* @param Value type.
* @author Mark Paluch
*/
public class StatefulRedisPubSubConnectionImpl extends StatefulRedisConnectionImpl
implements StatefulRedisPubSubConnection {
private final PubSubEndpoint endpoint;
/**
* Initialize a new connection.
*
* @param endpoint the {@link PubSubEndpoint}
* @param writer the writer used to write commands
* @param codec Codec used to encode/decode keys and values.
* @param timeout Maximum time to wait for a response.
*/
public StatefulRedisPubSubConnectionImpl(PubSubEndpoint endpoint, RedisChannelWriter writer, RedisCodec codec,
Duration timeout) {
super(writer, endpoint, codec, timeout, DEFAULT_JSON_PARSER);
this.endpoint = endpoint;
endpoint.setConnectionState(getConnectionState());
}
/**
* Add a new listener.
*
* @param listener Listener.
*/
@Override
public void addListener(RedisPubSubListener listener) {
endpoint.addListener(listener);
}
/**
* Remove an existing listener.
*
* @param listener Listener.
*/
@Override
public void removeListener(RedisPubSubListener listener) {
endpoint.removeListener(listener);
}
@Override
public RedisPubSubAsyncCommands async() {
return (RedisPubSubAsyncCommands) async;
}
@Override
protected RedisPubSubAsyncCommandsImpl newRedisAsyncCommandsImpl() {
return new RedisPubSubAsyncCommandsImpl<>(this, codec);
}
@Override
public RedisPubSubCommands sync() {
return (RedisPubSubCommands) sync;
}
@Override
protected RedisPubSubCommands newRedisSyncCommandsImpl() {
return syncHandler(async(), RedisPubSubCommands.class);
}
@Override
public RedisPubSubReactiveCommands reactive() {
return (RedisPubSubReactiveCommands) reactive;
}
@Override
protected RedisPubSubReactiveCommandsImpl newRedisReactiveCommandsImpl() {
return new RedisPubSubReactiveCommandsImpl<>(this, codec);
}
/**
* Re-subscribe to all previously subscribed channels and patterns.
*
* @return list of the futures of the {@literal subscribe} and {@literal psubscribe} commands.
*/
protected List> resubscribe() {
List> result = new ArrayList<>();
if (endpoint.hasChannelSubscriptions()) {
result.add(async().subscribe(toArray(endpoint.getChannels())));
}
if (endpoint.hasShardChannelSubscriptions()) {
result.add(async().ssubscribe(toArray(endpoint.getShardChannels())));
}
if (endpoint.hasPatternSubscriptions()) {
result.add(async().psubscribe(toArray(endpoint.getPatterns())));
}
return result;
}
@SuppressWarnings("unchecked")
private T[] toArray(Collection c) {
Class cls = (Class) c.iterator().next().getClass();
T[] array = (T[]) Array.newInstance(cls, c.size());
return c.toArray(array);
}
@Override
public void activated() {
super.activated();
for (RedisFuture command : resubscribe()) {
command.exceptionally(throwable -> {
if (throwable instanceof RedisCommandExecutionException) {
InternalLoggerFactory.getInstance(getClass()).warn("Re-subscribe failed: " + command.getError());
}
return null;
});
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy