Skip to content

Commit c3b3a48

Browse files
Merge pull request #968 from redis/DOC-4560-jedis-py-pipe
DOC-4560 added testable Python and Jedis pipe/transaction examples
2 parents e5d48a6 + ceacfff commit c3b3a48

File tree

2 files changed

+92
-85
lines changed

2 files changed

+92
-85
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
---
2+
categories:
3+
- docs
4+
- develop
5+
- stack
6+
- oss
7+
- rs
8+
- rc
9+
- oss
10+
- kubernetes
11+
- clients
12+
description: Learn how to use Redis pipelines and transactions
13+
linkTitle: Pipelines/transactions
14+
title: Pipelines and transactions
15+
weight: 2
16+
---
17+
18+
Redis lets you send a sequence of commands to the server together in a batch.
19+
There are two types of batch that you can use:
20+
21+
- **Pipelines** avoid network and processing overhead by sending several commands
22+
to the server together in a single communication. The server then sends back
23+
a single communication with all the responses. See the
24+
[Pipelining]({{< relref "/develop/use/pipelining" >}}) page for more
25+
information.
26+
- **Transactions** guarantee that all the included commands will execute
27+
to completion without being interrupted by commands from other clients.
28+
See the [Transactions]({{< relref "/develop/interact/transactions" >}})
29+
page for more information.
30+
31+
## Execute a pipeline
32+
33+
To execute commands in a pipeline, you first create a pipeline object
34+
and then add commands to it using methods that resemble the standard
35+
command methods (for example, `set()` and `get()`). The commands are
36+
buffered in the pipeline and only execute when you call the `sync()`
37+
method on the pipeline object.
38+
39+
The main difference with the pipeline commands is that they return
40+
`Response<Type>` objects, where `Type` is the return type of the
41+
standard command method. A `Response` object contains a valid result
42+
only after the pipeline has finished executing. You can access the
43+
result using the `Response` object's `get()` method.
44+
45+
{{< clients-example pipe_trans_tutorial basic_pipe Java-Sync >}}
46+
{{< /clients-example >}}
47+
48+
## Execute a transaction
49+
50+
A transaction works in a similar way to a pipeline. Create a
51+
transaction object with the `multi()`, call command methods
52+
on that object, and then call the transaction object's
53+
`exec()` method to execute it. You can access the results
54+
from commands in the transaction using `Response` objects, as
55+
you would with a pipeline. However, the `exec()` method also
56+
returns a `List<Object>` value that contains all the result
57+
values in the order the commands were executed (see
58+
[Watch keys for changes](#watch-keys-for-changes) below for
59+
an example that uses the results list).
60+
61+
{{< clients-example pipe_trans_tutorial basic_trans Java-Sync >}}
62+
{{< /clients-example >}}
63+
64+
## Watch keys for changes
65+
66+
Redis supports *optimistic locking* to avoid inconsistent updates
67+
to different keys. The basic idea is to watch for changes to any
68+
keys that you use in a transaction while you are are processing the
69+
updates. If the watched keys do change, you must restart the updates
70+
with the latest data from the keys. See
71+
[Transactions]({{< relref "/develop/interact/transactions" >}})
72+
for more information about optimistic locking.
73+
74+
The code below reads a string
75+
that represents a `PATH` variable for a command shell, then appends a new
76+
command path to the string before attempting to write it back. If the watched
77+
key is modified by another client before writing, the transaction aborts.
78+
Note that you should call read-only commands for the watched keys synchronously on
79+
the usual client object (called `jedis` in our examples) but you still call commands
80+
for the transaction on the transaction object.
81+
82+
For production usage, you would generally call code like the following in
83+
a loop to retry it until it succeeds or else report or log the failure.
84+
85+
{{< clients-example pipe_trans_tutorial trans_watch Java-Sync >}}
86+
{{< /clients-example >}}

content/develop/clients/redis-py/transpipe.md

Lines changed: 6 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -41,31 +41,8 @@ Note that the command methods for a pipeline always return the original
4141
pipeline object, so you can "chain" several commands together, as the
4242
example below shows:
4343

44-
<!-- Tested examples will replace the inline ones when they are approved.
45-
Markup removed to stop warnings.
46-
47-
clients-example pipe_trans_tutorial basic_pipe Python
48-
/clients-example
49-
-->
50-
```python
51-
import redis
52-
53-
r = redis.Redis(decode_responses=True)
54-
55-
pipe = r.pipeline()
56-
57-
for i in range(5):
58-
pipe.set(f"seat:{i}", f"#{i}")
59-
60-
set_5_result = pipe.execute()
61-
print(set_5_result) # >>> [True, True, True, True, True]
62-
63-
pipe = r.pipeline()
64-
65-
# "Chain" pipeline commands together.
66-
get_3_result = pipe.get("seat:0").get("seat:3").get("seat:4").execute()
67-
print(get_3_result) # >>> ['#0', '#3', '#4']
68-
```
44+
{{< clients-example pipe_trans_tutorial basic_pipe Python >}}
45+
{{< /clients-example >}}
6946

7047
## Execute a transaction
7148

@@ -96,43 +73,8 @@ key is modified by another client before writing, the transaction aborts
9673
with a `WatchError` exception, and the loop executes again for another attempt.
9774
Otherwise, the loop terminates successfully.
9875

99-
<!--
100-
clients-example pipe_trans_tutorial trans_watch Python
101-
/clients-example
102-
-->
103-
```python
104-
r.set("shellpath", "/usr/syscmds/")
105-
106-
with r.pipeline() as pipe:
107-
# Repeat until successful.
108-
while True:
109-
try:
110-
# Watch the key we are about to change.
111-
pipe.watch("shellpath")
112-
113-
# The pipeline executes commands directly (instead of
114-
# buffering them) from immediately after the `watch()`
115-
# call until we begin the transaction.
116-
current_path = pipe.get("shellpath")
117-
new_path = current_path + ":/usr/mycmds/"
118-
119-
# Start the transaction, which will enable buffering
120-
# again for the remaining commands.
121-
pipe.multi()
122-
123-
pipe.set("shellpath", new_path)
124-
125-
pipe.execute()
126-
127-
# The transaction succeeded, so break out of the loop.
128-
break
129-
except redis.WatchError:
130-
# The transaction failed, so continue with the next attempt.
131-
continue
132-
133-
get_path_result = r.get("shellpath")
134-
print(get_path_result) # >>> '/usr/syscmds/:/usr/mycmds/'
135-
```
76+
{{< clients-example pipe_trans_tutorial trans_watch Python >}}
77+
{{< /clients-example >}}
13678

13779
Because this is a common pattern, the library includes a convenience
13880
method called `transaction()` that handles the code to watch keys,
@@ -144,26 +86,5 @@ using `transaction()`. Note that `transaction()` can't add the `multi()`
14486
call automatically, so you must still place this correctly in your
14587
transaction function.
14688

147-
<!--
148-
clients-example pipe_trans_tutorial watch_conv_method Python
149-
/clients-example
150-
*-->
151-
```python
152-
r.set("shellpath", "/usr/syscmds/")
153-
154-
155-
def watched_sequence(pipe):
156-
current_path = pipe.get("shellpath")
157-
new_path = current_path + ":/usr/mycmds/"
158-
159-
pipe.multi()
160-
161-
pipe.set("shellpath", new_path)
162-
163-
164-
trans_result = r.transaction(watched_sequence, "shellpath")
165-
print(trans_result) # True
166-
167-
get_path_result = r.get("shellpath")
168-
print(get_path_result) # >>> '/usr/syscmds/:/usr/mycmds/'
169-
```
89+
{{< clients-example pipe_trans_tutorial watch_conv_method Python >}}
90+
{{< /clients-example >}}

0 commit comments

Comments
 (0)