content/develop/clients/jedis/produsage.md
This guide offers recommendations to get the best reliability and performance in your production environment.
Each item in the checklist below links to the section for a recommendation. Use the checklist icons to record your progress in implementing the recommendations.
- [ ] [Connection pooling](#connection-pooling)
- [ ] [Connection retries](#connection-retries)
- [ ] [Client-side caching](#client-side-caching)
- [ ] [Timeouts](#timeouts)
- [ ] [Health checks](#health-checks)
- [ ] [Exception handling](#exception-handling)
- [ ] [DNS cache and Redis](#dns-cache-and-redis)
The sections below offer recommendations for your production environment. Some of them may not apply to your particular use case.
Example code often opens a connection at the start, demonstrates a feature, and then closes the connection at the end. However, production code typically uses connections many times intermittently. Repeatedly opening and closing connections has a performance overhead.
Use [connection pooling]({{< relref "/develop/clients/pools-and-muxing" >}}) to avoid the overhead of opening and closing connections without having to write your own code to cache and reuse open connections. See [Configure a connection pool]({{< relref "/develop/clients/jedis/connect#configure-a-connection-pool" >}}) to learn how to use this technique with Jedis.
If a connection is lost before a command is completed, the command will fail with a JedisConnectionException. However, a connection error is often transient, in which case the
command will succeed after one or more reconnection attempts. See
[Retrying a command after a connection failure]({{< relref "/develop/clients/jedis/connect#retrying-a-command-after-a-connection-failure" >}})
for an example of a simple retry loop that can recover from a transient connection error.
[Client-side caching]({{< relref "/develop/clients/client-side-caching" >}}) involves storing the results from read-only commands in a local cache. If the same command is executed again later, the results can be obtained from the cache, without contacting the server. This improves command execution time on the client, while also reducing network traffic and server load. See [Connect using client-side caching]({{< relref "/develop/clients/jedis/connect#connect-using-client-side-caching" >}}) for more information and example code.
If a network or server error occurs while your code is opening a connection or issuing a command, it can end up hanging indefinitely. You can prevent this from happening by setting timeouts for socket reads and writes and for opening connections.
To set a timeout for a connection, use JedisClientConfig with the socketTimeout and connectionTimeout parameters.
(The socket timeout is the maximum time allowed for reading or writing data while executing a
command. The connection timeout is the maximum time allowed for establishing a new connection.)
RedisClient jedisWithTimeout = RedisClient.builder()
.hostAndPort("localhost", 6379)
.clientConfig(
DefaultJedisClientConfig.builder()
.socketTimeoutMillis(5000) // set timeout to 5 seconds
.connectionTimeoutMillis(5000) // set connection timeout to 5 seconds
.build())
.build();
If your code doesn't access the Redis server continuously then it
might be useful to make a "health check" periodically (perhaps once
every few seconds). You can do this using a simple
[PING]({{< relref "/commands/ping" >}}) command:
ConnectionPoolConfig poolConfig = new ConnectionPoolConfig();
poolConfig.setMaxTotal(8);
poolConfig.setMaxIdle(8);
poolConfig.setMinIdle(0);
poolConfig.setBlockWhenExhausted(true);
poolConfig.setMaxWait(Duration.ofSeconds(1));
// Enables sending a PING command once every second while the connection is idle.
poolConfig.setTestWhileIdle(true);
poolConfig.setTimeBetweenEvictionRuns(Duration.ofSeconds(1));
RedisClient jedis = RedisClient.builder()
.hostAndPort("localhost", 6379)
.poolConfig(poolConfig)
.build();
Health checks help to detect problems as soon as possible without waiting for a user to report them.
Redis handles many errors using return values from commands, but there are also situations where exceptions can be thrown. In production code, you should handle exceptions as they occur.
The Jedis exception hierarchy is rooted on JedisException, which implements
RuntimeException. All exceptions in the hierarchy are therefore unchecked
exceptions.
"JedisException":
_meta:
description: "Base class for all Jedis exceptions"
"JedisDataException":
"JedisRedirectionException":
"JedisMovedDataException":
"JedisAskDataException":
"AbortedTransactionException":
"JedisAccessControlException":
"JedisNoScriptException":
"JedisClusterException":
"JedisClusterOperationException":
"JedisConnectionException":
"JedisValidationException":
"InvalidURIException":
In general, Jedis can throw the following exceptions while executing commands:
JedisConnectionException - when the connection to Redis is lost or closed unexpectedly. Configure failover to handle this exception automatically with Resilience4J and the built-in Jedis failover mechanism.JedisAccessControlException - when the user does not have the permission to execute the command or the user ID and/or password are incorrect.JedisDataException - when there is a problem with the data being sent to or received from the Redis server. Usually, the error message will contain more information about the failed command.JedisException - this exception is a catch-all exception that can be thrown for any other unexpected errors.Conditions when JedisException can be thrown:
PING]({{< relref "/commands/ping" >}}) commandAll the Jedis exceptions are runtime exceptions and in most cases irrecoverable, so in general bubble up to the API capturing the error message.
When you connect to a Redis server with multiple endpoints, such as Redis Software Active-Active, you must disable the JVM's DNS cache. If a server node or proxy fails, the IP address for any database affected by the failure will change. When this happens, your app will keep trying to use the stale IP address if DNS caching is enabled.
Use the following code to disable the DNS cache:
java.security.Security.setProperty("networkaddress.cache.ttl","0");
java.security.Security.setProperty("networkaddress.cache.negative.ttl", "0");