Skip to content

Commit 75b72bd

Browse files
Merge pull request #1400 from redis/DOC-5064-jedis-prod-usage
DOC-5064 improvements to Jedis production usage advice
2 parents 040b915 + 3636c56 commit 75b72bd

File tree

3 files changed

+176
-4
lines changed

3 files changed

+176
-4
lines changed

content/develop/clients/jedis/produsage.md

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,62 @@ title: Production usage
1515
weight: 6
1616
---
1717

18-
The following sections explain how to handle situations that may occur
19-
in your production environment.
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 "#timeouts" >}}Timeouts{{< /checklist-item >}}
31+
{{< checklist-item "#health-checks" >}}Health checks{{< /checklist-item >}}
32+
{{< checklist-item "#exception-handling" >}}Exception handling{{< /checklist-item >}}
33+
{{< checklist-item "#dns-cache-and-redis" >}}DNS cache and Redis{{< /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/jedis/connect#connect-with-a-connection-pool" >}})
52+
to learn how to use this technique with Jedis.
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/jedis/connect#connect-using-client-side-caching" >}})
62+
for more information and example code.
2063

2164
### Timeouts
2265

23-
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:
66+
If a network or server error occurs while your code is opening a
67+
connection or issuing a command, it can end up hanging indefinitely.
68+
You can prevent this from happening by setting timeouts for socket
69+
reads and writes and for opening connections.
70+
71+
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.
72+
(The socket timeout is the maximum time allowed for reading or writing data while executing a
73+
command. The connection timeout is the maximum time allowed for establishing a new connection.)
2474

2575
```java
2676
HostAndPort hostAndPort = new HostAndPort("localhost", 6379);
@@ -34,9 +84,33 @@ JedisPooled jedisWithTimeout = new JedisPooled(hostAndPort,
3484
);
3585
```
3686

87+
### Health checks
88+
89+
If your code doesn't access the Redis server continuously then it
90+
might be useful to make a "health check" periodically (perhaps once
91+
every few seconds). You can do this using a simple
92+
[`PING`]({{< relref "/commands/ping" >}}) command:
93+
94+
```java
95+
try (Jedis jedis = jedisPool.getResource()) {
96+
if (! "PONG".equals(jedis.ping())) {
97+
// Report problem.
98+
}
99+
}
100+
```
101+
102+
Health checks help to detect problems as soon as possible without
103+
waiting for a user to report them.
104+
37105
### Exception handling
38106

39-
The Jedis Exception Hierarchy is rooted on `JedisException`, which implements `RuntimeException`, and are therefore all unchecked exceptions.
107+
Redis handles many errors using return values from commands, but there
108+
are also situations where exceptions can be thrown. In production code,
109+
you should handle exceptions as they occur.
110+
111+
The Jedis exception hierarchy is rooted on `JedisException`, which implements
112+
`RuntimeException`. All exceptions in the hierarchy are therefore unchecked
113+
exceptions.
40114

41115
```
42116
JedisException
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<li>
2+
<select onchange="clChange('prodlist')">
3+
<option value="R">&#x274C;</option>
4+
<option value="G">&#9989;</option>
5+
<option value="A">&#x1F50D;</option>
6+
<option value="X">&#x2205;</option>
7+
</select>
8+
{{- if index .Params 0 -}}
9+
<a href="{{ index .Params 0 }}">{{ .Inner }}</a>
10+
{{- else -}}
11+
{{ .Inner }}
12+
{{- end -}}
13+
</li>

layouts/shortcodes/checklist.html

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
{{ $formId := index .Params 0 }}
2+
<form id="{{ $formId }}">
3+
<ul style="list-style-type: none;padding-left: 0px;">
4+
{{ .Inner }}
5+
</ul>
6+
<label for="gcount">&#9989; = </label>
7+
<output name="gcount" id="gcount">0</output>/<output name="gtotal"></output>,
8+
<label for="rcount">&#x274C; = </label>
9+
<output name="rcount" id="rcount">0</output>/<output name="rtotal"></output>,
10+
<label for="acount">&#x1F50D; = </label>
11+
<output name="acount" id="acount">0</output>/<output name="atotal"></output>
12+
<br/>
13+
(<label for="xcount">&#x2205; = </label>
14+
<output name="xcount" id="xcount">0</output>/<output name="xtotal"></output>)
15+
</form>
16+
<script>
17+
document.addEventListener('DOMContentLoaded', () => {
18+
let itemString = localStorage.getItem("{{ $formId }}");
19+
20+
if (itemString !== "") {
21+
setCLItemsFromString("{{ $formId }}", itemString);
22+
} else {
23+
clChange("{{ $formId }}");
24+
}
25+
});
26+
27+
28+
function getStringFromCLItems(formId) {
29+
let result = "";
30+
31+
let form = document.getElementById(formId);
32+
33+
let listItems = form.getElementsByTagName("li");
34+
35+
for (let elem of listItems) {
36+
let menu = elem.getElementsByTagName("select")[0];
37+
result += menu.value;
38+
}
39+
40+
return result;
41+
}
42+
43+
44+
function setCLItemsFromString(formId, clString) {
45+
let counts = {R: 0, G: 0, A: 0, X:0};
46+
47+
let form = document.getElementById(formId);
48+
let listItems = form.getElementsByTagName("li");
49+
50+
if (clString.length < listItems.length) {
51+
clString = clString.padEnd(listItems.length, "R");
52+
} else if (clString.length > listItems.length) {
53+
clString = clString.substring(0, listItems.length);
54+
}
55+
56+
for (let i = 0; i < clString.length; i++) {
57+
let char = clString.charAt(i);
58+
counts[char]++;
59+
let menu = listItems[i].getElementsByTagName("select")[0];
60+
menu.value = char;
61+
}
62+
63+
form.elements["rcount"].value = counts["R"];
64+
form.elements["gcount"].value = counts["G"];
65+
form.elements["acount"].value = counts["A"];
66+
form.elements["xcount"].value = counts["X"];
67+
68+
69+
let numClItems = listItems.length - counts["X"];
70+
71+
form.elements["rtotal"].value = numClItems;
72+
form.elements["gtotal"].value = numClItems;
73+
form.elements["atotal"].value = numClItems;
74+
form.elements["xtotal"].value = counts["X"];
75+
76+
let itemChoices = getStringFromCLItems("{{ $formId }}");
77+
localStorage.setItem("{{ $formId }}", itemChoices);
78+
}
79+
80+
81+
function clChange(formId) {
82+
let itemChoices = getStringFromCLItems(formId);
83+
setCLItemsFromString(formId, itemChoices);
84+
}
85+
</script>

0 commit comments

Comments
 (0)