Expand description
rustis is a Redis client for Rust.
§Philosophy
- Low allocations
- Full async library
- Lock free implementation
- Rust idiomatic API
§Features
- Support all documented Redis Commands up to and including Redis 8.8
- Async support (tokio)
- Different client types:
- Single client
- Multiplexed client
- Pooled client manager (based on bb8)
- Automatic command batching
- Advanced reconnection & retry strategy
- Pipelining support
- Configuration with Redis URL or dedicated builder
- TLS support
- Transaction support
- Pub/sub support
- Sentinel support
- LUA Scripts/Functions support
- Cluster support
- Client-side caching support
§Optional Features
| Feature | Description |
|---|---|
tokio-runtime | Tokio runtime (default) |
tokio-rustls | Tokio Rustls TLS support |
tokio-native-tls | Tokio native_tls TLS support |
json | Enables JSON (de)serialization support via serde_json |
client-cache | Enables client-side caching support |
pool | Pooled client manager |
tokio-rustls and tokio-native-tls are mutually exclusive: enabling both is a
compile error. Each implies the corresponding backend-only feature (rustls,
native-tls), which gates the TLS configuration types. Enabling a backend-only
feature on its own is also a compile error: it brings the configuration types
without the connection code that honours them.
The remaining features are for developing rustis itself and carry no stability
guarantee: bench (exposes internal RESP entry points to the benchmarks and pulls in
criterion, fred, redis and pprof), fuzzing (same, for the cargo-fuzz targets
in fuzz/) and web-examples (axum / actix-web, for the examples).
§Protocol Compatibility
Rustis uses the RESP3 protocol exclusively.
The HELLO 3 command is automatically sent when establishing a connection.
Therefore, your Redis server must support RESP3 (Redis ≥6.0+ with RESP3 enabled).
If you use Redis 5 or older, or your Redis 6+ server still defaults to RESP2, Rustis will not work.
To verify your server supports RESP3:
redis-cli --raw HELLO 3If you see server info (role, version, etc.), you’re good to go. If you get an error, upgrade Redis.
§Basic Usage
use rustis::{
client::Client,
commands::{FlushingMode, ServerCommands, StringCommands},
Result,
};
#[tokio::main]
async fn main() -> Result<()> {
// Connect the client to a Redis server from its IP and port
let client = Client::connect("127.0.0.1:6379").await?;
// Flush all existing data in Redis
client.flushdb(FlushingMode::Sync).await?;
// sends the command SET to Redis. This command is defined in the StringCommands trait
client.set("key", "value").await?;
// sends the command GET to Redis. This command is defined in the StringCommands trait
let value: String = client.get("key").await?;
println!("value: {value:?}");
Ok(())
}§Client
See the module client to discover which are the 3
usages of the Client struct and how to configure it.
You will also learn how to use pipeline, pub/sub and transactions.
§RESP
RESP is the Redis Serialization Protocol.
See the module resp to discover how rustis
allows programmers to communicate with Redis in a Rust idiomatic way.
You will learn how to:
- Manipulate the rustis object model, the enum
Value, which is a generic Rust data structure over RESP. - Convert Rust types into Rust Commands with the
Commandstruct, whose arguments are any type implementing serde’sSerialize. - Convert Rust command responses into Rust type with serde and helpful marker traits.
§Commands
In order to send Commands to the Redis server, rustis offers two API levels:
- High-level Built-in commands that implement all documented Redis commands up to and including Redis 8.8, plus the Redis Stack commands.
- Low-level Generic command API to express any request that may not exist in rustis:
- new official commands not yet implemented by rustis.
- commands exposed by additional Redis modules not included in Redis Stack.
§Built-in commands
See the module commands to discover how Redis built-in commands are organized in different traits.
§Generic command API
To use the generic command API, you can use the cmd function to specify the name of the command,
followed by one or multiple calls to CommandBuilder::arg to add arguments to the command,
and to CommandBuilder::key to add arguments that are Redis keys.
This command can then be passed as a parameter to one of the following associated functions, depending on the client, transaction or pipeline struct used:
sendsend_and_forgetPipeline::queue, to batch several of them
use rustis::{client::Client, resp::cmd, Result};
#[tokio::main]
async fn main() -> Result<()> {
let client = Client::connect("127.0.0.1:6379").await?;
client
.send::<()>(
cmd("MSET")
.key("{my}key1")
.arg("value1")
.key("{my}key2")
.arg("value2")
.key("{my}key3")
.arg("value3")
.key("{my}key4")
.arg("value4"),
None,
)
.await?;
let values: Vec<String> = client
.send(
cmd("MGET")
.key("{my}key1")
.key("{my}key2")
.key("{my}key3")
.key("{my}key4"),
None,
)
.await?;
assert_eq!(vec!["value1", "value2", "value3", "value4"], values);
Ok(())
}§Warning: keys must be added with key, not arg
Only arguments added with key take part in Cluster slot
computation. A command built with arg alone carries no slot and is sent to a random node
of the cluster, with no error to tell you: a single-key command gets a MOVED reply, and the
retry that follows the topology refresh picks a random node again. A multi-key command such as
MSET fails with CROSSSLOT.
A multi-key command additionally requires all its keys to hash to the same slot, which is what
the {my} hash tag guarantees in the example above.
This does not apply to the strongly typed command API (commands): those functions already
mark their keys.
§Errors
Every fallible call returns Result<T>, whose error is Error.
An Error is what went wrong, kind(), plus the command it belongs
to, command():
use rustis::{Error, ErrorKind, Result};
fn report(result: Result<String>) {
if let Err(e) = result {
match e.kind() {
ErrorKind::Timeout => eprintln!("{:?} timed out", e.command()),
ErrorKind::Redis(redis_error) => eprintln!("the server refused it: {redis_error}"),
_ => eprintln!("{e}"),
}
}
}The command matters because a client multiplexes: a single connection carries
hundreds of commands at once, so a bare “the operation timed out” names nothing
the application can act on. It is set for every error the client raises on behalf
of a command, and absent for the ones raised outside any — a connection timeout,
for instance. Display appends it, so a logged error reads
The I/O operation's timeout expired (while executing BLMPOP).
§Client-side caching
See the module cache to discover how you can implement client-side caching.
Re-exports§
pub use bb8;pool
Modules§
- cache
client-cache - Client-side caching support
- client
- Defines types related to the clients structs and their dependencies:
Client,ExclusiveClient,PooledClientManager,Pipeline,Transactionand how to configure them - commands
- Define Redis built-in commands in a set of traits
- resp
- Defines types related to the
RESPprotocol and their encoding/decoding
Structs§
- Error
- Any error raised by the client, and the command it belongs to.
- Error
Context - Identifies the command an
Errorbelongs to. - Redis
Error - Error issued by the Redis server
Enums§
- Client
Error - Errors issued by the client
- Error
Kind - What an
Erroris, independently of the command it belongs to. - Redis
Error Kind - Redis server error kind