Skip to content

Commit

Permalink
Polishing.
Browse files Browse the repository at this point in the history
Tweak wording around thread-safety. Include notices in connection factories.

Reformat asciidoc.

See #2653
Original pull request: #2667
  • Loading branch information
mp911de committed Aug 10, 2023
1 parent 4bf1d06 commit 76da57e
Show file tree
Hide file tree
Showing 9 changed files with 41 additions and 24 deletions.
12 changes: 9 additions & 3 deletions src/main/asciidoc/reference/redis.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,15 @@ NOTE: For the corner cases where the native library API is required, `RedisConne

Active `RedisConnection` objects are created through `RedisConnectionFactory`. In addition, the factory acts as `PersistenceExceptionTranslator` objects, meaning that, once declared, they let you do transparent exception translation. For example, you can do exception translation through the use of the `@Repository` annotation and AOP. For more information, see the dedicated {spring-framework-reference}/data-access.html#orm-exception-translation[section] in the Spring Framework documentation.

WARNING: `RedisConnection` classes, such as `JedisConnection` and `LettuceConnection`, are **not** Thread-safe. While the underlying native connection, such as Lettuce's `StatefulRedisConnection`, may be Thread-safe, Spring Data Redis's `LettuceConnection` class itself is not Thread-safe. Therefore, you should **not** share instances of a `RedisConnection` across multiple Threads. This is especially true for transactional, or blocking Redis operations and commands, such as `BLPOP`. In transactional and pipelining operations, for instance, `RedisConnection` holds onto unguarded mutable state to complete the operation correctly, thereby making it unsafe to use with multiple Threads. This is by design.

TIP: If you need to share (stateful) Redis resources, like connections, across multiple Threads, for performance reasons or otherwise, then you should acquire the native connection and use the Redis client library (driver) API directly. Alternatively, you can use the `RedisTemplate`, which acquires and manages connections for operations (and Redis commands) in a Thread-safe manner. See <<redis:template,documentation>> on `RedisTemplate` for more details.
NOTE: `RedisConnection` classes are **not** Thread-safe.
While the underlying native connection, such as Lettuce's `StatefulRedisConnection`, may be Thread-safe, Spring Data Redis's `LettuceConnection` class itself is not.
Therefore, you should **not** share instances of a `RedisConnection` across multiple Threads.
This is especially true for transactional, or blocking Redis operations and commands, such as `BLPOP`.
In transactional and pipelining operations, for instance, `RedisConnection` holds onto unguarded mutable state to complete the operation correctly, thereby making it unsafe to use with multiple Threads.
This is by design.

TIP: If you need to share (stateful) Redis resources, like connections, across multiple Threads, for performance reasons or otherwise, then you should acquire the native connection and use the Redis client library (driver) API directly.
Alternatively, you can use the `RedisTemplate`, which acquires and manages connections for operations (and Redis commands) in a Thread-safe manner. See <<redis:template,documentation>> on `RedisTemplate` for more details.

NOTE: Depending on the underlying configuration, the factory can return a new connection or an existing connection (when a pool or shared native connection is used).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
* {@link RedisClusterNode} can be obtained from {@link #clusterGetNodes()} or it can be constructed using either
* {@link RedisClusterNode#getHost() host} and {@link RedisClusterNode#getPort()} or the {@link RedisClusterNode#getId()
* node Id}.
* <p>
* {@link RedisClusterConnection Redis connections}, unlike perhaps their underlying native connection are not
* Thread-safe and should not be shared across multiple threads.
*
* @author Christoph Strobl
* @author Mark Paluch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,14 @@
/**
* A connection to a Redis server.
* <p>
* The {@link RedisConnection} interface serves as a common abstraction across various Redis client libraries
* (or drivers).
* The {@link RedisConnection} interface serves as a common abstraction across various Redis client libraries (or
* drivers).
* <p>
* Additionally, performs exception translation between the underlying Redis client library and Spring DAO exceptions.
* The methods follow as much as possible the Redis names and conventions.
* <p>
* Spring Data Redis {@link RedisConnection connections}, unlike perhaps their underlying native connection (for example:
* the Lettuce {@literal StatefulRedisConnection}) are not Thread-safe. Please refer to the corresponding the Javadoc
* for Redis client library (driver) specific connections provided by Spring Data Redis for more details.
* {@link RedisConnection Redis connections}, unlike perhaps their underlying native connection are not Thread-safe and
* should not be shared across multiple threads.
*
* @author Costin Leau
* @author Christoph Strobl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.PropertyAccessor;
import org.springframework.dao.DataAccessException;
Expand All @@ -61,6 +60,8 @@
* {@link RedisClusterConnection} implementation on top of {@link JedisCluster}.<br/>
* Uses the native {@link JedisCluster} api where possible and falls back to direct node communication using
* {@link Jedis} where needed.
* <p>
* This class is not Thread-safe and instances should not be shared across threads.
*
* @author Christoph Strobl
* @author Mark Paluch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
Expand All @@ -60,10 +59,7 @@
/**
* {@code RedisConnection} implementation on top of <a href="https://github.com/redis/jedis">Jedis</a> library.
* <p>
* WARNING: The {@link JedisConnection} class is not Thread-safe. This class requires and uses a
* {@literal Jedis} instance from the Jedis client library (driver), which is very clearly
* <a href="https://github.com/redis/jedis/wiki/Getting-started#using-jedis-in-a-multithreaded-environment">documented</a>
* as not Thread-safe.
* This class is not Thread-safe and instances should not be shared across threads.
*
* @author Costin Leau
* @author Jennifer Hickey
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@
* connection. {@link #afterPropertiesSet() Initialization} {@link SmartLifecycle#start() starts} this bean
* {@link #isAutoStartup() by default}. You can {@link SmartLifecycle#stop()} and {@link SmartLifecycle#start() restart}
* this connection factory if needed.
* <p>
* Note that {@link JedisConnection} and its {@link JedisClusterConnection clustered variant} are not Thread-safe and
* instances should not be shared across threads. Refer to the
* <a href="https://github.com/redis/jedis/wiki/Getting-started#using-jedis-in-a-multithreaded-environment">Jedis
* documentation</a> for guidance on configuring Jedis in a multithreaded environment.
*
* @author Costin Leau
* @author Thomas Darimont
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
Expand All @@ -53,6 +52,13 @@
/**
* {@code RedisClusterConnection} implementation on top of <a href="https://github.com/mp911de/lettuce">Lettuce</a>
* Redis client.
* <p>
* While the underlying Lettuce {@literal RedisClient} and {@literal StatefulRedisConnection} instances used by
* {@link LettuceClusterConnection} are Thread-safe, this class itself is not Thread-safe. Therefore, instances of
* {@link LettuceClusterConnection} should not be shared across multiple Threads when executing Redis commands and other
* operations. If optimal performance is required by your application(s), then we recommend direct access to the
* low-level, API provided by the underlying Lettuce client library (driver), where such Thread-safety guarantees can be
* made. Simply call {@link #getNativeConnection()} and use the native resource as required.
*
* @author Christoph Strobl
* @author Mark Paluch
Expand Down Expand Up @@ -486,7 +492,6 @@ public void multi() {
throw new InvalidDataAccessApiUsageException("MULTI is currently not supported in cluster mode");
}


public ClusterCommandExecutor getClusterCommandExecutor() {
return clusterCommandExecutor;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@
* {@code RedisConnection} implementation on top of <a href="https://github.com/mp911de/lettuce">Lettuce</a> Redis
* client.
* <p>
* WARNING: While the underlying Lettuce {@literal RedisClient} and {@literal StatefulRedisConnection} instances used by
* {@link LettuceConnection} are Thread-safe, this class itself is not Thread-safe. Therefore, instances of {@link LettuceConnection}
* should not be shared across multiple Threads when executing Redis commands and other operations. If optimal performance
* is required by your application(s), then we recommend direct access to the low-level, API provided by the underlying
* Lettuce client library (driver), where such Thread-safety guarantees can be made. Simply call {@link #getNativeConnection()}
* and use the native resource as required.
* While the underlying Lettuce {@literal RedisClient} and {@literal StatefulRedisConnection} instances used by
* {@link LettuceConnection} are Thread-safe, this class itself is not Thread-safe. Therefore, instances of
* {@link LettuceConnection} should not be shared across multiple Threads when executing Redis commands and other
* operations. If optimal performance is required by your application(s), then we recommend direct access to the
* low-level, API provided by the underlying Lettuce client library (driver), where such Thread-safety guarantees can be
* made. Simply call {@link #getNativeConnection()} and use the native resource as required.
*
* @author Costin Leau
* @author Jennifer Hickey
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,10 @@
/**
* Connection factory creating <a href="https://github.com/mp911de/lettuce">Lettuce</a>-based connections.
* <p>
* This factory creates a new {@link LettuceConnection} on each call to {@link #getConnection()}. Multiple
* {@link LettuceConnection}s share a single thread-safe native connection by default.
* This factory creates a new {@link LettuceConnection} on each call to {@link #getConnection()}. While multiple
* {@link LettuceConnection}s share a single thread-safe native connection by default, {@link LettuceConnection} and its
* {@link LettuceClusterConnection clustered variant} are not Thread-safe and instances should not be shared across
* threads.
* <p>
* The shared native connection is never closed by {@link LettuceConnection}, therefore it is not validated by default
* on {@link #getConnection()}. Use {@link #setValidateConnection(boolean)} to change this behavior if necessary. If
Expand Down

0 comments on commit 76da57e

Please sign in to comment.