Expand description
redis-rs is a Rust implementation of a Redis client library. It exposes a general purpose interface to Redis and also provides specific helpers for commonly used functionality.
The crate is called redis
and you can depend on it via cargo:
[dependencies.redis]
version = "*"
If you want to use the git version:
[dependencies.redis]
git = "https://github.com/redis-rs/redis-rs.git"
§Basic Operation
redis-rs exposes two API levels: a low- and a high-level part. The high-level part does not expose all the functionality of redis and might take some liberties in how it speaks the protocol. The low-level part of the API allows you to express any request on the redis level. You can fluently switch between both API levels at any point.
§Connection Handling
For connecting to redis you can use a client object which then can produce
actual connections. Connections and clients as well as results of
connections and clients are considered ConnectionLike
objects and
can be used anywhere a request is made.
The full canonical way to get a connection is to create a client and to ask for a connection from it:
extern crate redis;
fn do_something() -> redis::RedisResult<()> {
let client = redis::Client::open("redis://127.0.0.1/")?;
let mut con = client.get_connection()?;
/* do something here */
Ok(())
}
§Optional Features
There are a few features defined that can enable additional functionality if so desired. Some of them are turned on by default.
acl
: enables acl support (enabled by default)aio
: enables async IO support (optional)geospatial
: enables geospatial support (enabled by default)script
: enables script support (enabled by default)streams
: enables high-level interface for interaction with Redis streams (enabled by default)r2d2
: enables r2d2 connection pool support (optional)ahash
: enables ahash map/set support & uses ahash internally (+7-10% performance) (optional)cluster
: enables redis cluster support (optional)cluster-async
: enables async redis cluster support (optional)tokio-comp
: enables support for tokio (optional)connection-manager
: enables support for automatic reconnection (optional)keep-alive
: enables keep-alive option on socket by means ofsocket2
crate (enabled by default)tcp_nodelay
: enables the no-delay flag on communication sockets (optional)rust_decimal
,bigdecimal
,num-bigint
: enables type conversions to large number representation from different crates (optional)uuid
: enables type conversion to UUID (optional)sentinel
: enables high-level interfaces for communication with Redis sentinels (optional)
§Connection Parameters
redis-rs knows different ways to define where a connection should
go. The parameter to Client::open
needs to implement the
IntoConnectionInfo
trait of which there are three implementations:
- string slices in
redis://
URL format. - URL objects from the redis-url crate.
ConnectionInfo
objects.
The URL format is redis://[<username>][:<password>@]<hostname>[:port][/[<db>][?protocol=<protocol>]]
If Unix socket support is available you can use a unix URL in this format:
redis+unix:///<path>[?db=<db>[&pass=<password>][&user=<username>][&protocol=<protocol>]]
For compatibility with some other redis libraries, the “unix” scheme is also supported:
unix:///<path>[?db=<db>][&pass=<password>][&user=<username>][&protocol=<protocol>]]
§Executing Low-Level Commands
To execute low-level commands you can use the cmd
function which allows
you to build redis requests. Once you have configured a command object
to your liking you can send a query into any ConnectionLike
object:
fn do_something(con: &mut redis::Connection) -> redis::RedisResult<()> {
redis::cmd("SET").arg("my_key").arg(42).exec(con)?;
Ok(())
}
Upon querying the return value is a result object. If you do not care
about the actual return value (other than that it is not a failure)
you can always type annotate it to the unit type ()
.
Note that commands with a sub-command (like “MEMORY USAGE”, “ACL WHOAMI”,
“LATENCY HISTORY”, etc) must specify the sub-command as a separate arg
:
fn do_something(con: &mut redis::Connection) -> redis::RedisResult<usize> {
// This will result in a server error: "unknown command `MEMORY USAGE`"
// because "USAGE" is technically a sub-command of "MEMORY".
redis::cmd("MEMORY USAGE").arg("my_key").query::<usize>(con)?;
// However, this will work as you'd expect
redis::cmd("MEMORY").arg("USAGE").arg("my_key").query(con)
}
§Executing High-Level Commands
The high-level interface is similar. For it to become available you
need to use the Commands
trait in which case all ConnectionLike
objects the library provides will also have high-level methods which
make working with the protocol easier:
extern crate redis;
use redis::Commands;
fn do_something(con: &mut redis::Connection) -> redis::RedisResult<()> {
let _: () = con.set("my_key", 42)?;
Ok(())
}
Note that high-level commands are work in progress and many are still missing!
§Type Conversions
Because redis inherently is mostly type-less and the protocol is not
exactly friendly to developers, this library provides flexible support
for casting values to the intended results. This is driven through the FromRedisValue
and ToRedisArgs
traits.
The arg
method of the command will accept a wide range of types through
the ToRedisArgs
trait and the query
method of a command can convert the
value to what you expect the function to return through the FromRedisValue
trait. This is quite flexible and allows vectors, tuples, hashsets, hashmaps
as well as optional values:
let count : i32 = con.get("my_counter")?;
let count = con.get("my_counter").unwrap_or(0i32);
let k : Option<String> = con.get("missing_key")?;
let name : String = con.get("my_name")?;
let bin : Vec<u8> = con.get("my_binary")?;
let map : HashMap<String, i32> = con.hgetall("my_hash")?;
let keys : Vec<String> = con.hkeys("my_hash")?;
let mems : HashSet<i32> = con.smembers("my_set")?;
let (k1, k2) : (String, String) = con.get(&["k1", "k2"])?;
§RESP3 support
Since Redis / Valkey version 6, a newer communication protocol called RESP3 is supported.
Using this protocol allows the user both to receive a more varied Value
results, for users
who use the low-level Value
type, and to receive out of band messages on the same connection. This allows the user to receive PubSub
messages on the same connection, instead of creating a new PubSub connection (see “RESP3 async pubsub”).
§Iteration Protocol
In addition to sending a single query, iterators are also supported. When
used with regular bulk responses they don’t give you much over querying and
converting into a vector (both use a vector internally) but they can also
be used with SCAN
like commands in which case iteration will send more
queries until the cursor is exhausted:
let mut iter : redis::Iter<isize> = redis::cmd("SSCAN").arg("my_set")
.cursor_arg(0).clone().iter(&mut con)?;
for x in iter {
// do something with the item
}
As you can see the cursor argument needs to be defined with cursor_arg
instead of arg
so that the library knows which argument needs updating
as the query is run for more items.
§Pipelining
In addition to simple queries you can also send command pipelines. This
is provided through the pipe
function. It works very similar to sending
individual commands but you can send more than one in one go. This also
allows you to ignore individual results so that matching on the end result
is easier:
let (k1, k2) : (i32, i32) = redis::pipe()
.cmd("SET").arg("key_1").arg(42).ignore()
.cmd("SET").arg("key_2").arg(43).ignore()
.cmd("GET").arg("key_1")
.cmd("GET").arg("key_2").query(&mut con)?;
If you want the pipeline to be wrapped in a MULTI
/EXEC
block you can
easily do that by switching the pipeline into atomic
mode. From the
caller’s point of view nothing changes, the pipeline itself will take
care of the rest for you:
let (k1, k2) : (i32, i32) = redis::pipe()
.atomic()
.cmd("SET").arg("key_1").arg(42).ignore()
.cmd("SET").arg("key_2").arg(43).ignore()
.cmd("GET").arg("key_1")
.cmd("GET").arg("key_2").query(&mut con)?;
You can also use high-level commands on pipelines:
let (k1, k2) : (i32, i32) = redis::pipe()
.atomic()
.set("key_1", 42).ignore()
.set("key_2", 43).ignore()
.get("key_1")
.get("key_2").query(&mut con)?;
§Transactions
Transactions are available through atomic pipelines. In order to use
them in a more simple way you can use the transaction
function of a
connection:
use redis::Commands;
let key = "the_key";
let (new_val,) : (isize,) = redis::transaction(&mut con, &[key], |con, pipe| {
let old_val : isize = con.get(key)?;
pipe
.set(key, old_val + 1).ignore()
.get(key).query(con)
})?;
println!("The incremented number is: {}", new_val);
For more information see the transaction
function.
§PubSub
Pubsub is provided through the PubSub
connection object for sync usage, or the aio::PubSub
for async usage.
Example usage:
let client = redis::Client::open("redis://127.0.0.1/")?;
let mut con = client.get_connection()?;
let mut pubsub = con.as_pubsub();
pubsub.subscribe("channel_1")?;
pubsub.subscribe("channel_2")?;
loop {
let msg = pubsub.get_message()?;
let payload : String = msg.get_payload()?;
println!("channel '{}': {}", msg.get_channel_name(), payload);
}
In order to update subscriptions while concurrently waiting for messages, the async PubSub can be split into separate sink & stream components. The sink can be receive subscription requests while the stream is awaited for messages.
use futures_util::StreamExt;
let client = redis::Client::open("redis://127.0.0.1/")?;
let (mut sink, mut stream) = client.get_async_pubsub().await?.split();
sink.subscribe("channel_1").await?;
loop {
let msg = stream.next().await.unwrap();
let payload : String = msg.get_payload().unwrap();
println!("channel '{}': {}", msg.get_channel_name(), payload);
}
§RESP3 async pubsub
If you’re targeting a Redis/Valkey server of version 6 or above, you can receive pubsub messages from it without creating another connection, by setting a push sender on the connection.
let client = redis::Client::open("redis://127.0.0.1/?protocol=resp3").unwrap();
let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();
let config = redis::AsyncConnectionConfig::new().set_push_sender(tx);
let mut con = client.get_multiplexed_async_connection_with_config(&config).await?;
con.subscribe("channel_1").await?;
con.subscribe("channel_2").await?;
loop {
println!("Received {:?}", rx.recv().await.unwrap());
}
§Scripts
Lua scripts are supported through the Script
type in a convenient
way. It will automatically load the script if it does not exist and invoke it.
Example:
let script = redis::Script::new(r"
return tonumber(ARGV[1]) + tonumber(ARGV[2]);
");
let result: isize = script.arg(1).arg(2).invoke(&mut con)?;
assert_eq!(result, 3);
Scripts can also be pipelined:
let script = redis::Script::new(r"
return tonumber(ARGV[1]) + tonumber(ARGV[2]);
");
let (a, b): (isize, isize) = redis::pipe()
.invoke_script(script.arg(1).arg(2))
.invoke_script(script.arg(2).arg(3))
.query(&mut con)?;
assert_eq!(a, 3);
assert_eq!(b, 5);
Note: unlike a call to invoke
, if the script isn’t loaded during the pipeline operation,
it will not automatically be loaded and retried. The script can be loaded using the
load
operation.
§Async
In addition to the synchronous interface that’s been explained above there also exists an
asynchronous interface based on futures
and tokio
, or async-std
.
This interface exists under the aio
(async io) module (which requires that the aio
feature
is enabled) and largely mirrors the synchronous with a few concessions to make it fit the
constraints of futures
.
use futures::prelude::*;
use redis::AsyncCommands;
let client = redis::Client::open("redis://127.0.0.1/").unwrap();
let mut con = client.get_multiplexed_async_connection().await?;
let _: () = con.set("key1", b"foo").await?;
redis::cmd("SET").arg(&["key2", "bar"]).exec_async(&mut con).await?;
let result = redis::cmd("MGET")
.arg(&["key1", "key2"])
.query_async(&mut con)
.await;
assert_eq!(result, Ok(("foo".to_string(), b"bar".to_vec())));
§Sentinel
Sentinel types allow users to connect to Redis sentinels and find primaries and replicas.
use redis::{ Commands, RedisConnectionInfo };
use redis::sentinel::{ SentinelServerType, SentinelClient, SentinelNodeConnectionInfo };
let nodes = vec!["redis://127.0.0.1:6379/", "redis://127.0.0.1:6378/", "redis://127.0.0.1:6377/"];
let mut sentinel = SentinelClient::build(
nodes,
String::from("primary1"),
Some(SentinelNodeConnectionInfo {
tls_mode: Some(redis::TlsMode::Insecure),
redis_connection_info: None,
}),
redis::sentinel::SentinelServerType::Master,
)
.unwrap();
let primary = sentinel.get_connection().unwrap();
An async API also exists:
use futures::prelude::*;
use redis::{ Commands, RedisConnectionInfo };
use redis::sentinel::{ SentinelServerType, SentinelClient, SentinelNodeConnectionInfo };
let nodes = vec!["redis://127.0.0.1:6379/", "redis://127.0.0.1:6378/", "redis://127.0.0.1:6377/"];
let mut sentinel = SentinelClient::build(
nodes,
String::from("primary1"),
Some(SentinelNodeConnectionInfo {
tls_mode: Some(redis::TlsMode::Insecure),
redis_connection_info: None,
}),
redis::sentinel::SentinelServerType::Master,
)
.unwrap();
let primary = sentinel.get_async_connection().await.unwrap();
Modules§
- acl
acl
Defines types to use with the ACL commands. - aio
aio
Adds async IO support to redis. - cluster
cluster
This module extends the library to support Redis Cluster. - cluster_
async cluster
andaio
This module provides async functionality for connecting to Redis / Valkey Clusters. - cluster_
routing cluster
Routing information for cluster commands. - geo
geospatial
Defines types to use with the geospatial commands. - sentinel
sentinel
Defines a Sentinel type that connects to Redis sentinels and creates clients to master or replica nodes. - streams
streams
Defines types to use with the streams commands.
Structs§
- Options for creation of async connection
- Async
Iter aio
Represents a redis iterator that can be used with async connections. - The client type.
- Client
TlsConfig tls-rustls
Structure to hold mTLS client certificate and key binaries in PEM format - Represents redis commands.
- Represents a stateful redis TCP connection.
- Holds the connection information that redis should use for connecting.
- An info dictionary type.
- Represents a redis iterator.
- Options for the LPOS command
- Represents a pubsub message.
- The internal redis response parser.
- Represents a redis command pipeline.
- Represents a pubsub connection.
- A push message from the server.
- Redis specific/connection independent information used to establish a connection to redis.
- Represents a redis error. For the most part you should be using the Error trait to interact with this rather than the actual struct.
- Options for the SCAN command
- Script
script
Represents a lua script. - Script
Invocation script
Represents a prepared script call. - Options for the SET command
- TlsCertificates
tls-rustls
Structure to hold TLS certificates
Enums§
- An argument to a redis command
- Defines the connection address.
- Allows pubsub callbacks to stop receiving messages.
- Enum for the LEFT | RIGHT args used by some commands
- An enum of all error kinds.
- Helper enum that is used to define existence checks
- Helper enum that is used to define option for the hash expire commands
- Helper enum that is used to define expiry time
- Helper enum that is used in some situations to describe the behavior of arguments in a numeric context.
- Enum representing the communication protocol with the server. This enum represents the types of data that the server can send to the client, and the capabilities that the client can use.
Push
type’s currently known kinds.- Helper enum that is used to define expiry time for SET command
- TlsMode indicates use or do not use verification of certification. Check ConnectionAddr for more.
- Internal low-level redis value enum.
VerbatimString
’s format types defined by spec
Traits§
- Implements common redis commands over asynchronous connections. This allows you to send commands straight to a connection or client.
- Implements common redis commands for connection like objects. This allows you to send commands straight to a connection or client. It is also implemented for redis results of clients which makes for very convenient access in some basic cases.
- Implements the “stateless” part of the connection interface that is used by the different objects in redis-rs. Primarily it obviously applies to
Connection
object but also some other objects implement the interface (for instance whole clients or certain redis results). - This trait is used to convert a redis value into a more appropriate type. While a redis
Value
can represent any response that comes back from the redis server, usually you want to map this into something that works better in rust. For instance you might want to convert the return value into aString
or an integer. - Converts an object into a connection info struct. This allows the constructor of the client to accept connection information in a range of different formats.
- Json
Async Commands json
andaio
Implements RedisJSON commands over asynchronous connections. This allows you to send commands straight to a connection or client. - Json
Commands json
Implements RedisJSON commands for connection like objects. This allows you to send commands straight to a connection or client. It is also implemented for redis results of clients which makes for very convenient access in some basic cases. - The PubSub trait allows subscribing to one or more channels and receiving a callback whenever a message arrives.
- Abstraction trait for redis command abstractions.
- Used to convert a value into one or multiple redis argument strings. Most values will produce exactly one item but in some cases it might make sense to produce more than one.
Functions§
- Shortcut function to creating a command with a single argument.
- A shortcut function to invoke
FromRedisValue::from_owned_redis_value
to make the API slightly nicer. - A shortcut function to invoke
FromRedisValue::from_redis_value
to make the API slightly nicer. - Packs a bunch of commands into a request. This is generally a quite useless function as this functionality is nicely wrapped through the
Cmd
object, but in some cases it can be useful. The return value of this can then be send to the low levelConnectionLike
methods. - This function takes a redis URL string and parses it into a URL as used by rust-url. This is necessary as the default parser does not understand how redis URLs function.
- Parses bytes into a redis value.
- Parses a redis value asynchronously.
- Shortcut for creating a new pipeline.
- This function simplifies transaction management slightly. What it does is automatically watching keys and then going into a transaction loop util it succeeds. Once it goes through the results are returned.
Type Aliases§
- Redis
Future aio
Library generic future type. - Library generic result type.