Skip to content

Commit fea4498

Browse files
DOC-5065 started Python production usage page
1 parent 28f392a commit fea4498

File tree

1 file changed

+214
-0
lines changed

1 file changed

+214
-0
lines changed
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
---
2+
categories:
3+
- docs
4+
- develop
5+
- stack
6+
- oss
7+
- rs
8+
- rc
9+
- oss
10+
- kubernetes
11+
- clients
12+
description: Get your `redis-py` app ready for production
13+
linkTitle: Production usage
14+
title: Production usage
15+
weight: 70
16+
---
17+
18+
This guide offers recommendations to get the best reliability and
19+
performance in your production environment.
20+
21+
## Checklist
22+
23+
Each item in the checklist below links to the section
24+
for a recommendation. Use the checklist icons to record your
25+
progress in implementing the recommendations.
26+
27+
{{< checklist "prodlist" >}}
28+
{{< checklist-item "#connection-pooling" >}}Connection pooling{{< /checklist-item >}}
29+
{{< checklist-item "#client-side-caching" >}}Client-side caching{{< /checklist-item >}}
30+
{{< checklist-item "#retries" >}}Retries{{< /checklist-item >}}
31+
{{< checklist-item "#timeouts" >}}Timeouts{{< /checklist-item >}}
32+
{{< checklist-item "#health-checks" >}}Health checks{{< /checklist-item >}}
33+
{{< checklist-item "#exception-handling" >}}Exception handling{{< /checklist-item >}}
34+
{{< /checklist >}}
35+
36+
## Recommendations
37+
38+
The sections below offer recommendations for your production environment. Some
39+
of them may not apply to your particular use case.
40+
41+
### Connection pooling
42+
43+
Example code often opens a connection at the start, demonstrates a feature,
44+
and then closes the connection at the end. However, production code
45+
typically uses connections many times intermittently. Repeatedly opening
46+
and closing connections has a performance overhead.
47+
48+
Use [connection pooling]({{< relref "/develop/clients/pools-and-muxing" >}})
49+
to avoid the overhead of opening and closing connections without having to
50+
write your own code to cache and reuse open connections. See
51+
[Connect with a connection pool]({{< relref "/develop/clients/redis-py/connect#connect-with-a-connection-pool" >}})
52+
to learn how to use this technique with `redis-py`.
53+
54+
### Client-side caching
55+
56+
[Client-side caching]({{< relref "/develop/clients/client-side-caching" >}})
57+
involves storing the results from read-only commands in a local cache. If the
58+
same command is executed again later, the results can be obtained from the cache,
59+
without contacting the server. This improves command execution time on the client,
60+
while also reducing network traffic and server load. See
61+
[Connect using client-side caching]({{< relref "/develop/clients/redis-py/connect#connect-using-client-side-caching" >}})
62+
for more information and example code.
63+
64+
### Retries
65+
66+
Redis connections and commands can often fail due to transient problems,
67+
such as temporary network outages or timeouts. When this happens,
68+
the operation will generally succeed after a few attempts, despite
69+
failing the first time.
70+
71+
You can configure `redis-py` to retry connections automatically after
72+
specified errors occur. Use an instance of the `Retry` class to
73+
specify the number of times to retry after a failure and a backoff
74+
strategy to determine the time between attempts. For example, the
75+
following code creates a `Retry` with
76+
[exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff)
77+
that will make three repeated attempts after a failure:
78+
79+
```py
80+
from redis.backoff import ExponentialBackoff
81+
from redis.retry import Retry
82+
83+
# Run 3 retries with exponential backoff strategy.
84+
retry = Retry(ExponentialBackoff(), 3)
85+
```
86+
87+
Pass the `Retry` instance in the `retry` parameter when you connect
88+
to Redis. When you are connecting to a standalone Redis server,
89+
you can also set the `retry_on_timeout` parameter to `True`
90+
to retry only after timeout errors, or pass a list of exception
91+
types in the `retry_on_error` parameter.
92+
93+
```py
94+
# Retry only on timeout
95+
r = Redis(
96+
retry=retry,
97+
retry_on_timeout=True
98+
.
99+
.
100+
)
101+
102+
# Retry on any of a specified list of command exceptions.
103+
from redis.exceptions import (
104+
BusyLoadingError,
105+
ConnectionError,
106+
TimeoutError
107+
)
108+
.
109+
.
110+
111+
r = Redis(
112+
retry=retry,
113+
retry_on_error=[BusyLoadingError, ConnectionError, TimeoutError],
114+
.
115+
.
116+
)
117+
```
118+
119+
If you specify either `retry_on_timeout` or `retry_on_error` without
120+
a `retry` parameter, the default is to retry once immediately with no
121+
backoff.
122+
123+
For a connection to a Redis cluster, you can specify a `retry` instance.
124+
However, the list of exceptions is not configurable and is always set
125+
to `TimeoutError`, `ConnectionError`, and `ClusterDownError`. You can use
126+
the `cluster_error_retry_attempts` parameter to specify the number of
127+
attempts to make after encountering one of these errors:
128+
129+
```py
130+
131+
```
132+
133+
### Timeouts
134+
135+
If a network or server error occurs while your code is opening a
136+
connection or issuing a command, it can end up hanging indefinitely.
137+
You can prevent this from happening by setting timeouts for socket
138+
reads and writes and for opening connections.
139+
140+
To set a timeout for a connection, use the `JedisPooled` or `JedisPool` constructor with the `timeout` parameter, or use `JedisClientConfig` with the `socketTimeout` and `connectionTimeout` parameters.
141+
(The socket timeout is the maximum time allowed for reading or writing data while executing a
142+
command. The connection timeout is the maximum time allowed for establishing a new connection.)
143+
144+
```java
145+
HostAndPort hostAndPort = new HostAndPort("localhost", 6379);
146+
147+
JedisPooled jedisWithTimeout = new JedisPooled(hostAndPort,
148+
DefaultJedisClientConfig.builder()
149+
.socketTimeoutMillis(5000) // set timeout to 5 seconds
150+
.connectionTimeoutMillis(5000) // set connection timeout to 5 seconds
151+
.build(),
152+
poolConfig
153+
);
154+
```
155+
156+
### Health checks
157+
158+
If your code doesn't access the Redis server continuously then it
159+
might be useful to make a "health check" periodically (perhaps once
160+
every few seconds) to verify that the connection is working.
161+
Set the `health_check_interval` parameter during
162+
a connection (with either `Redis` or `ConnectionPool`) to specify
163+
an integer number of seconds. If the connection remains idle for
164+
longer than this interval, it will automatically issue a
165+
[`PING`]({{< relref "/commands/ping" >}}) command and check the
166+
response before continuing with any client commands.
167+
168+
```py
169+
# Issue a health check if the connection is idle for longer
170+
# than three seconds.
171+
r = Redis(
172+
health_check_interval = 3,
173+
.
174+
.
175+
)
176+
```
177+
178+
Health checks help to detect problems as soon as possible without
179+
waiting for a user to report them. If a `ConnectionError` or `TimeoutError`
180+
occurs for the health check itself, a second attempt will be made before
181+
reporting failure.
182+
183+
### Exception handling
184+
185+
Redis handles many errors using return values from commands, but there
186+
are also situations where exceptions can be thrown. In production code,
187+
you should handle exceptions wherever they can occur. In particular,
188+
exceptions can occur when you
189+
[connect to the server]({{< relref "/develop/clients/redis-py/connect" >}}),
190+
create a [query index]({{< relref "/develop/interact/search-and-query/indexing" >}}),
191+
or execute a
192+
[watched transaction]({{< relref "/develop/clients/redis-py/transpipe#watch-keys-for-changes" >}}).
193+
194+
#### General exceptions
195+
196+
In general, Jedis can throw the following exceptions while executing commands:
197+
198+
- `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.
199+
- `JedisAccessControlException` - when the user does not have the permission to execute the command or the user ID and/or password are incorrect.
200+
- `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.
201+
- `JedisException` - this exception is a catch-all exception that can be thrown for any other unexpected errors.
202+
203+
Conditions when `JedisException` can be thrown:
204+
- Bad return from a health check with the [`PING`]({{< relref "/commands/ping" >}}) command
205+
- Failure during SHUTDOWN
206+
- Pub/Sub failure when issuing commands (disconnect)
207+
- Any unknown server messages
208+
- Sentinel: can connect to sentinel but master is not monitored or all Sentinels are down.
209+
- MULTI or DISCARD command failed
210+
- Shard commands key hash check failed or no Reachable Shards
211+
- Retry deadline exceeded/number of attempts (Retry Command Executor)
212+
- POOL - pool exhausted, error adding idle objects, returning broken resources to the pool
213+
214+
All the Jedis exceptions are runtime exceptions and in most cases irrecoverable, so in general bubble up to the API capturing the error message.

0 commit comments

Comments
 (0)