Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions content/develop/clients/jedis/transpipe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
categories:
- docs
- develop
- stack
- oss
- rs
- rc
- oss
- kubernetes
- clients
description: Learn how to use Redis pipelines and transactions
linkTitle: Pipelines/transactions
title: Pipelines and transactions
weight: 2
---

Redis lets you send a sequence of commands to the server together in a batch.
There are two types of batch that you can use:

- **Pipelines** avoid network and processing overhead by sending several commands
to the server together in a single communication. The server then sends back
a single communication with all the responses. See the
[Pipelining]({{< relref "/develop/use/pipelining" >}}) page for more
information.
- **Transactions** guarantee that all the included commands will execute
to completion without being interrupted by commands from other clients.
See the [Transactions]({{< relref "/develop/interact/transactions" >}})
page for more information.

## Execute a pipeline

To execute commands in a pipeline, you first create a pipeline object
and then add commands to it using methods that resemble the standard
command methods (for example, `set()` and `get()`). The commands are
buffered in the pipeline and only execute when you call the `sync()`
method on the pipeline object.

The main difference with the pipeline commands is that they return
`Response<Type>` objects, where `Type` is the return type of the
standard command method. A `Response` object contains a valid result
only after the pipeline has finished executing. You can access the
result using the `Response` object's `get()` method.

{{< clients-example pipe_trans_tutorial basic_pipe Java-Sync >}}
{{< /clients-example >}}

## Execute a transaction

A transaction works in a similar way to a pipeline. Create a
transaction object with the `multi()`, call command methods
on that object, and then call the transaction object's
`exec()` method to execute it. You can access the results
from commands in the transaction using `Response` objects, as
you would with a pipeline. However, the `exec()` method also
returns a `List<Object>` value that contains all the result
values in the order the commands were executed (see
[Watch keys for changes](#watch-keys-for-changes) below for
an example that uses the results list).

{{< clients-example pipe_trans_tutorial basic_trans Java-Sync >}}
{{< /clients-example >}}

## Watch keys for changes

Redis supports *optimistic locking* to avoid inconsistent updates
to different keys. The basic idea is to watch for changes to any
keys that you use in a transaction while you are are processing the
updates. If the watched keys do change, you must restart the updates
with the latest data from the keys. See
[Transactions]({{< relref "/develop/interact/transactions" >}})
for more information about optimistic locking.

The code below reads a string
that represents a `PATH` variable for a command shell, then appends a new
command path to the string before attempting to write it back. If the watched
key is modified by another client before writing, the transaction aborts.
Note that you should call read-only commands for the watched keys synchronously on
the usual client object (called `jedis` in our examples) but you still call commands
for the transaction on the transaction object.

For production usage, you would generally call code like the following in
a loop to retry it until it succeeds or else report or log the failure.

{{< clients-example pipe_trans_tutorial trans_watch Java-Sync >}}
{{< /clients-example >}}
91 changes: 6 additions & 85 deletions content/develop/clients/redis-py/transpipe.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,31 +41,8 @@ Note that the command methods for a pipeline always return the original
pipeline object, so you can "chain" several commands together, as the
example below shows:

<!-- Tested examples will replace the inline ones when they are approved.
Markup removed to stop warnings.

clients-example pipe_trans_tutorial basic_pipe Python
/clients-example
-->
```python
import redis

r = redis.Redis(decode_responses=True)

pipe = r.pipeline()

for i in range(5):
pipe.set(f"seat:{i}", f"#{i}")

set_5_result = pipe.execute()
print(set_5_result) # >>> [True, True, True, True, True]

pipe = r.pipeline()

# "Chain" pipeline commands together.
get_3_result = pipe.get("seat:0").get("seat:3").get("seat:4").execute()
print(get_3_result) # >>> ['#0', '#3', '#4']
```
{{< clients-example pipe_trans_tutorial basic_pipe Python >}}
{{< /clients-example >}}

## Execute a transaction

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

<!--
clients-example pipe_trans_tutorial trans_watch Python
/clients-example
-->
```python
r.set("shellpath", "/usr/syscmds/")

with r.pipeline() as pipe:
# Repeat until successful.
while True:
try:
# Watch the key we are about to change.
pipe.watch("shellpath")

# The pipeline executes commands directly (instead of
# buffering them) from immediately after the `watch()`
# call until we begin the transaction.
current_path = pipe.get("shellpath")
new_path = current_path + ":/usr/mycmds/"

# Start the transaction, which will enable buffering
# again for the remaining commands.
pipe.multi()

pipe.set("shellpath", new_path)

pipe.execute()

# The transaction succeeded, so break out of the loop.
break
except redis.WatchError:
# The transaction failed, so continue with the next attempt.
continue

get_path_result = r.get("shellpath")
print(get_path_result) # >>> '/usr/syscmds/:/usr/mycmds/'
```
{{< clients-example pipe_trans_tutorial trans_watch Python >}}
{{< /clients-example >}}

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

<!--
clients-example pipe_trans_tutorial watch_conv_method Python
/clients-example
*-->
```python
r.set("shellpath", "/usr/syscmds/")


def watched_sequence(pipe):
current_path = pipe.get("shellpath")
new_path = current_path + ":/usr/mycmds/"

pipe.multi()

pipe.set("shellpath", new_path)


trans_result = r.transaction(watched_sequence, "shellpath")
print(trans_result) # True

get_path_result = r.get("shellpath")
print(get_path_result) # >>> '/usr/syscmds/:/usr/mycmds/'
```
{{< clients-example pipe_trans_tutorial watch_conv_method Python >}}
{{< /clients-example >}}
Loading