-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refine JedisConnectionFactory
#2746
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did a first review pass. The majority of changes impose a different style, resulting in code that requires more effort to read (harder to read) and that isn't an improvement.
@@ -100,18 +102,17 @@ public class JedisConnectionFactory | |||
|
|||
private static final Log log = LogFactory.getLog(JedisConnectionFactory.class); | |||
|
|||
private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = new PassThroughExceptionTranslationStrategy( | |||
JedisExceptionConverter.INSTANCE); | |||
private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = jedisExceptionTranslationStrategy(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Introducing a indirection makes it difficult to understand at first sight the details.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoiding line breaks and undue noise. Plus, details aren't needed until they are needed. It is easy to navigate into the method.
@@ -125,8 +126,7 @@ public class JedisConnectionFactory | |||
|
|||
private @Nullable RedisConfiguration configuration; | |||
|
|||
private RedisStandaloneConfiguration standaloneConfig = new RedisStandaloneConfiguration("localhost", | |||
Protocol.DEFAULT_PORT); | |||
private RedisStandaloneConfiguration standaloneConfig = defaultStandaloneConfiguration(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Introducing a indirection makes it difficult to understand at first sight the details.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same reason as above.
@@ -249,8 +249,7 @@ public JedisConnectionFactory(RedisSentinelConfiguration sentinelConfiguration, | |||
@Nullable JedisPoolConfig poolConfig) { | |||
|
|||
this.configuration = sentinelConfiguration; | |||
this.clientConfiguration = MutableJedisClientConfiguration | |||
.create(poolConfig != null ? poolConfig : new JedisPoolConfig()); | |||
this.clientConfiguration = MutableJedisClientConfiguration.create(nullSafePoolConfig(poolConfig)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inflationary usage of nullSafe…
methods creates a lot of noise hiding the actual details. Introducing indirections makes it difficult to understand at first sight the details.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lines in question are too busy creating an 1) incomplete/break-in statement and 2) unnecessary line break. They are also redundant.
Plus, "named" methods are more intuitive and this method (nullSafePoolConfig(..)
) is reused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.pool = null; | ||
} catch (Exception ex) { | ||
log.warn("Cannot properly close Jedis pool", ex); | ||
} catch (Exception cause) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be precise: cause
isn't true as the cause refers to the exception cause and not the caught exception. Please stick to ex
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cause
is the reason the error occurred in the block above. You are confusing this with caused by.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In any case, I am not going to argue about this.
If you want it to be consistent, then we should call it e
everywhere Exceptions are caught (or ignore
when Exceptions are not handled), which is what the core Spring Framework uses (i.e. e
, not sure about ignore
).
Using ex
is not consistent, and o_O
is not professional.
static class MutableJedisClientConfiguration implements JedisClientConfiguration { | ||
|
||
private boolean useSsl; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reason to tear code with good locality apart? All SSL-related fields have been kept together. Now, these are spread across.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Organization by type. All the state variables were bunched together making it difficult to read.
If you want better organization around concern, then perhaps a private, internal SslConfiguration
class used by MutableJedisClientConfiguration
makes more sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reverted for the time being. This has room for improvement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now I see where we get our influence:
package redis.clients.jedis;
import ...;
public final class DefaultJedisClientConfig implements JedisClientConfig {
private final RedisProtocol redisProtocol;
private final int connectionTimeoutMillis;
private final int socketTimeoutMillis;
private final int blockingSocketTimeoutMillis;
private volatile Supplier<RedisCredentials> credentialsProvider;
private final int database;
private final String clientName;
private final boolean ssl;
private final SSLSocketFactory sslSocketFactory;
private final SSLParameters sslParameters;
private final HostnameVerifier hostnameVerifier;
//...
This is unfortunate. And, this is only marginally better.
} catch (Exception ex) { | ||
log.warn(String.format("Ping failed for sentinel host: %s", node.getHost()), ex); | ||
} catch (Exception cause) { | ||
log.warn("Ping failed for sentinel host: %s".formatted(node.getHost()), cause); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please let's remain on String.format(…)
to remain consitent. We can change all occurrences of String.format(…)
to formatted
if we feel that the value we get from that outweighs the effort.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"some string with placeholders".formatted(..)
is less noisy and it makes the "message" more apparent.
Why change try-finally
blocks with proper handling to try-with-resources blocks, or use for-each loops when for(index; condition; increment)
works perfectly fine?
Simple. Because it reads easier, or in the case of try-with-resources, is a more reliable alternative and welcome language feature.
NOTE: Even multi-line Strings would be a nice addition in certain places where we use really long Exception messages.
I don't believe in big bang, change everything at once and be done with it. All improvements happen incrementally or generally don't/won't happen at all. They are not all or nothing.
In addition, where String
formatting, or even concatenation, are concerned, String.format(..)
is not even consistently used everywhere, and not just Spring Data Redis.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems there was already a style in place that predates the existing style. So, either 1) we do not consistently follow any standard or 2) authors "come up with our own way" and then don't consistently apply it everywhere, which enforces my point about "big bang" changes don't work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another case in point: https://github.com/spring-projects/spring-data-redis/blob/3.2.0-RC1/src/main/java/org/springframework/data/redis/core/mapping/RedisMappingContext.java#L245-L250
In the RedisMappintContext
's case, inconsistent and incorrect message formatting was used.
I am certain there are others.
if (jedis.ping().equalsIgnoreCase("pong")) { | ||
success = true; | ||
return jedis; | ||
} | ||
} catch (Exception ex) { | ||
log.warn(String.format("Ping failed for sentinel host: %s", node.getHost()), ex); | ||
} catch (Exception cause) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cause
is technically wrong, please stick to ex
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. It is the cause for the Exception being thrown in the block above.
* @param cluster reference to the configured {@link JedisCluster} used by the {@link ClusterTopologyProvider} | ||
* to interact with the Redis cluster; must not be {@literal null}. | ||
* @return a new {@link ClusterTopologyProvider}. | ||
* @see org.springframework.data.redis.connection.jedis.JedisClusterConnection.JedisClusterTopologyProvider |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to create duplicate @see
references to types that are already present in the signature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed
* @see redis.clients.jedis.JedisCluster | ||
* @since 3.2 | ||
*/ | ||
protected ClusterCommandExecutor createClusterCommandExecutor(JedisCluster cluster, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to create duplicate @see
references to types that are already present in the signature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed
*/ | ||
@Deprecated(since = "3.2") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not understand what warrants a deprecation of the createTopologyProvider
. New deprecations are a signal for existing users to do something about their usage while we do not solve an actual problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
API and naming consistency with other cluster-oriented types, along with the type itself, ClusterTopologyProvider
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was quite surprised when I first learned about Redis that we don't have something equivalent to SentinelTopologyProvider
for Redis Sentinel.
Of course, Redis Sentinel is not a fully managed, "clustered" solution (only HA), but is a group of nodes in a distributed system none-the-less.
Technically, ClusterTopology
is Set
of RedisClusterNode
and similarly, RedisSentinelConfiguration
contains a Set
of RedisNode
where RedisClusterNode
extends from RedisNode
. So, although they are not quite the same, they are similar enough.
Introduces private [static] methods (and/or local variables as needed) to simplify and remove duplicate logic while simultaneously removing broken line breaks affecting readability and understanding. Simplifies assertions by making consistent use of Spring Frameworks Assert facility rather than unnecessary conditional blocks. Refers to state variables using getter (rather than direct variable reference) where applicable helping to improve extensibility. Deprecates createTopologyProvider(..) in favor of createClusterTopologyProvider(..) for consistent and clarified naming. Cleans up compiler warnings. Closes #2745
I reworked this PR. Please keep your comments objective and constructive. If you re-read the commit message, you will notice several areas where the code was "improved". Cleaning up compiler warnings is a worthwhile improvement all by itself. Finally, if you don't agree with the deprecation of the " |
See #2745