Redis library for rust

Related tags

Database redis-rs
Overview

redis-rs

Build Status crates.io

Redis-rs is a high level redis library for Rust. It provides convenient access to all Redis functionality through a very flexible but low-level API. It uses a customizable type conversion trait so that any operation can return results in just the type you are expecting. This makes for a very pleasant development experience.

The crate is called redis and you can depend on it via cargo:

[dependencies]
redis = "0.20.0"

Documentation on the library can be found at docs.rs/redis.

Note: redis-rs requires at least Rust 1.39.

Basic Operation

To open a connection you need to create a client and then to fetch a connection from it. In the future there will be a connection pool for those, currently each connection is separate and not pooled.

Many commands are implemented through the Commands trait but manual command creation is also possible.

extern crate redis;
use redis::Commands;

fn fetch_an_integer() -> redis::RedisResult<isize> {
    // connect to redis
    let client = redis::Client::open("redis://127.0.0.1/")?;
    let mut con = client.get_connection()?;
    // throw away the result, just make sure it does not fail
    let _ : () = con.set("my_key", 42)?;
    // read back the key and return it.  Because the return value
    // from the function is a result for integer this will automatically
    // convert into one.
    con.get("my_key")
}

Async support

To enable asynchronous clients a feature for the underlying feature need to be activated.

# if you use tokio
redis = { version = "0.17.0", features = ["tokio-comp"] }

# if you use async-std
redis = { version = "0.17.0", features = ["async-std-comp"] }

TLS Support

To enable TLS support, you need to use the relevant feature entry in your Cargo.toml.

redis = { version = "0.19.0", features = ["tls"] }

# if you use tokio
redis = { version = "0.19.0", features = ["tokio-native-tls-comp"] }

# if you use async-std
redis = { version = "0.19.0", features = ["async-std-tls-comp"] }

then you should be able to connect to a redis instance using the rediss:// URL scheme:

let client = redis::Client::open("rediss://127.0.0.1/")?;

Cluster Support

Cluster mode can be used by specifying "cluster" as a features entry in your Cargo.toml.

redis = { version = "0.17.0", features = [ "cluster"] }

Then you can simply use the ClusterClient which accepts a list of available nodes.

use redis::cluster::ClusterClient;
use redis::Commands;

fn fetch_an_integer() -> String {
    // connect to redis
    let nodes = vec!["redis://127.0.0.1/"];
    let client = ClusterClient::open(nodes).unwrap();
    let mut connection = client.get_connection().unwrap();
    let _: () = connection.set("test", "test_data").unwrap();
    let rv: String = connection.get("test").unwrap();
    return rv;
}

Development

If you want to develop on the library there are a few commands provided by the makefile:

To build:

$ make

To test:

$ make test

To run benchmarks:

$ make bench

To build the docs (require nightly compiler, see rust-lang/rust#43781):

$ make docs

We encourage you to run clippy prior to seeking a merge for your work. The lints can be quite strict. Running this on your own workstation can save you time, since Travis CI will fail any build that doesn't satisfy clippy:

$ cargo clippy --all-features --all --tests --examples -- -D clippy::all -D warnings

To run fuzz tests with afl, first install cargo-afl (cargo install -f afl), then run:

$ make fuzz

If the fuzzer finds a crash, in order to reproduce it, run:

$ cd afl/<target>/
$ cargo run --bin reproduce -- out/crashes/<crashfile>
Comments
  • performance regression with Redis protocol parser

    performance regression with Redis protocol parser

    I have encountered what I believe to be a performance bug in the Redis protocol parser, given thread dumps of my service using the redis crate show the service to be stuck in the Redis protocol parser. I would like advice on good ways to continue debugging this issue to narrow down a root cause.

    Versions

    • Rust v1.51.0
    • redis 0.20.0
    • tokio 1.4.0

    Background

    My company is running a service that uses the redis crate to access an AWS Elasticache Redis instance. The service serves requests from its own clients via a Tokio event loop. The service is a cache service and typically uses less than 0.1 vCPU.

    About 1-2 times per week, the service suddenly starts consuming all of its CPU limit and then gets throttled by the Linux kernel. This has occurred both with the limit to set to 1 vCPU and set to 0.5 vCPU. When this occurs, the service stops responding to requests entirely.

    Diagnosis

    I took two thread dumps of the same process about 10 minutes apart using gdb, and it appears that execution is stuck in the Redis parser.

    Backtrace #1:

    #0  0x00007f4f25afb141 in ?? () from target:/lib/x86_64-linux-gnu/libc.so.6
    #1  0x000055e27139c8d6 in combine::stream::decode ()
    #2  0x000055e2713a145f in <redis::parser::aio_support::ValueCodec as tokio_util::codec::decoder::Decoder>::decode ()
    #3  0x000055e27139e7eb in tokio_util::codec::decoder::Decoder::decode_eof ()
    #4  0x000055e2713afdd0 in <tokio_util::codec::framed_impl::FramedImpl<T,U,R> as futures_core::stream::Stream>::poll_next ()
    #5  0x000055e2713ade59 in <redis::aio::PipelineSink<T,I,E> as futures_sink::Sink<redis::aio::PipelineMessage<SinkItem,I,E>>>::poll_flush ()
    #6  0x000055e2713c3b62 in <futures_util::stream::stream::forward::Forward<St,Si,Item> as core::future::future::Future>::poll ()
    #7  0x000055e2713a1ef9 in <futures_util::future::future::map::Map<Fut,F> as core::future::future::Future>::poll ()
    #8  0x000055e27139d3e9 in <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once ()
    #9  0x000055e2713c1f4e in tokio::runtime::task::harness::poll_future ()
    #10 0x000055e2713c29c2 in tokio::runtime::task::harness::Harness<T,S>::poll ()
    #11 0x000055e27183d644 in std::thread::local::LocalKey<T>::with ()
    #12 0x000055e271864ef2 in tokio::runtime::thread_pool::worker::Context::run_task ()
    #13 0x000055e27186416e in tokio::runtime::thread_pool::worker::Context::run ()
    #14 0x000055e27183f5b5 in tokio::macros::scoped_tls::ScopedKey<T>::set ()
    #15 0x000055e271863fc6 in tokio::runtime::thread_pool::worker::run ()
    #16 0x000055e27184a5b0 in tokio::loom::std::unsafe_cell::UnsafeCell<T>::with_mut ()
    #17 0x000055e27186866f in <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once ()
    #18 0x000055e27185ebae in tokio::runtime::task::harness::Harness<T,S>::poll ()
    #19 0x000055e271842f2c in tokio::runtime::blocking::pool::Inner::run ()
    #20 0x000055e27185478e in std::sys_common::backtrace::__rust_begin_short_backtrace ()
    #21 0x000055e271848e9a in core::ops::function::FnOnce::call_once{{vtable-shim}} ()
    #22 0x000055e2718fdf0a in <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once ()
        at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/alloc/src/boxed.rs:1521
    #23 <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once ()
        at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/alloc/src/boxed.rs:1521
    #24 std::sys::unix::thread::Thread::new::thread_start ()
        at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0//library/std/src/sys/unix/thread.rs:71
    #25 0x00007f4f25dcafa3 in start_thread () from target:/lib/x86_64-linux-gnu/libpthread.so.0
    #26 0x00007f4f25b734cf in clone () from target:/lib/x86_64-linux-gnu/libc.so.6
    

    Note: The first trace was taken before I installed glibc debug symbols into the node for the node. However, the service runs in a container using a different Linux distribution, so I'm not sure the malloc decoding in the second trace is correct.

    Backtrace #2:

    #0  0x00007f4f25afe3a9 in malloc () from target:/lib/x86_64-linux-gnu/libc.so.6
    #1  0x000055e2713b8c16 in <combine::parser::PartialMode as combine::parser::ParseMode>::parse ()
    #2  0x000055e2713c6e18 in <redis::parser::value::{{closure}}::{{closure}}::Dispatch<A,B,C,D,E,F> as combine::
    parser::Parser<Input>>::parse_mode ()
    #3  0x000055e2713b8145 in <combine::parser::PartialMode as combine::parser::ParseMode>::parse ()
    #4  0x000055e2713a3fa0 in <combine::parser::combinator::AnySendSyncPartialStateParser<P> as combine::parser::
    Parser<Input>>::parse_mode ()
    #5  0x000055e2713a4ce6 in combine::parser::Parser::parse_with_state ()
    #6  0x000055e27139c760 in combine::stream::decode ()
    #7  0x000055e2713a145f in <redis::parser::aio_support::ValueCodec as tokio_util::codec::decoder::Decoder>::de
    code ()
    #8  0x000055e27139e7eb in tokio_util::codec::decoder::Decoder::decode_eof ()
    #9  0x000055e2713afdd0 in <tokio_util::codec::framed_impl::FramedImpl<T,U,R> as futures_core::stream::Stream>::poll_next ()
    #10 0x000055e2713ade59 in <redis::aio::PipelineSink<T,I,E> as futures_sink::Sink<redis::aio::PipelineMessage<SinkItem,I,E>>>::poll_flush ()
    #11 0x000055e2713c3b62 in <futures_util::stream::stream::forward::Forward<St,Si,Item> as core::future::future::Future>::poll ()
    #12 0x000055e2713a1ef9 in <futures_util::future::future::map::Map<Fut,F> as core::future::future::Future>::poll ()
    #13 0x000055e27139d3e9 in <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once ()
    #14 0x000055e2713c1f4e in tokio::runtime::task::harness::poll_future ()
    #15 0x000055e2713c29c2 in tokio::runtime::task::harness::Harness<T,S>::poll ()
    #16 0x000055e27183d644 in std::thread::local::LocalKey<T>::with ()
    #17 0x000055e271864ef2 in tokio::runtime::thread_pool::worker::Context::run_task ()
    #18 0x000055e27186416e in tokio::runtime::thread_pool::worker::Context::run ()
    #19 0x000055e27183f5b5 in tokio::macros::scoped_tls::ScopedKey<T>::set ()
    #20 0x000055e271863fc6 in tokio::runtime::thread_pool::worker::run ()
    #21 0x000055e27184a5b0 in tokio::loom::std::unsafe_cell::UnsafeCell<T>::with_mut ()
    #22 0x000055e27186866f in <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once ()
    #23 0x000055e27185ebae in tokio::runtime::task::harness::Harness<T,S>::poll ()
    #24 0x000055e271842f2c in tokio::runtime::blocking::pool::Inner::run ()
    #25 0x000055e27185478e in std::sys_common::backtrace::__rust_begin_short_backtrace ()
    #26 0x000055e271848e9a in core::ops::function::FnOnce::call_once{{vtable-shim}} ()
    #27 0x000055e2718fdf0a in <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once ()
        at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/alloc/src/boxed.rs:1521
    #28 <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once ()
        at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0/library/alloc/src/boxed.rs:1521
    #29 std::sys::unix::thread::Thread::new::thread_start ()
        at /rustc/2fd73fabe469357a12c2c974c140f67e7cdd76d0//library/std/src/sys/unix/thread.rs:71
    #30 0x00007f4f25dcafa3 in start_thread () from target:/lib/x86_64-linux-gnu/libpthread.so.0
    #31 0x00007f4f25b734cf in clone () from target:/lib/x86_64-linux-gnu/libc.so.6
    

    I would like advice on what data would be useful to proceed to narrow this down.

    bug 
    opened by tdyas 41
  • Add an async interface using futures-rs

    Add an async interface using futures-rs

    This adds support for communicating with redis instances asynchronously using futures and tokio. Putting this up now to show the changes and additions I have done so far.

    Since the current response parser is tied to reading synchronously from a Read instance I rewrote it using https://github.com/Marwes/combine. I choose combine since I know it (obviously) and I wanted to try the state machine support I have been working on in tandem with this PR (this PR is what made me come up with the idea). Though I am a bit biased I do think it should be a good fit after I have worked out the bugs so I hope the change is acceptable. (I did see the Nom parser in https://github.com/mitsuhiko/redis-rs/pull/129 but didn't use it as I'd still need to code the state machine manually whereas combine creates it automatically).

    query(_async) is currently the only added API and there is also a bunch of cleanup to be done.

    Closes #103

    opened by Marwes 36
  • Add TLS support, gated by a feature flag

    Add TLS support, gated by a feature flag

    Following up on my earlier attempt in MR #244.

    TODO:

    Resolves issue #241

    opened by gferon 29
  • Add async_std support

    Add async_std support

    Based in the conversation here: https://github.com/mitsuhiko/redis-rs/issues/280

    This branch comes from https://github.com/Marwes/redis-rs/tree/combine-4 If you merge this branch you will be merging this pull request too: https://github.com/mitsuhiko/redis-rs/pull/272

    When I needed to duplicate the method and it was public, I tried to create two variants (one with _tokio suffix and the other with _async_std) and leave the original method calling the _tokio variant. Still, very provably this mean breaking changes.

    All test pass in my pc (Pop_os 19.10)

    Let me know if I need to change anything!

    opened by DavidBM 24
  • Add support for streams

    Add support for streams

    Redis 5.0 will ship with streams. It's in beta now and will be stable in few months. It might be a good addition to the library and I hope it will work well with async libraries in Rust. I couldn't see any related issues or PR. Feel free to close this if it's a duplicate.

    Streams reference : https://redis.io/topics/streams-intro

    Thanks much for the library!

    opened by tirkarthi 24
  • Making the library executor agnostic (making Tokio optional)

    Making the library executor agnostic (making Tokio optional)

    Hi!

    I was developing a library using this one and I found out that the futures returned by redis-rs required tokio to be executed.

    As example, this test in my own library https://github.com/Couragium/rsmq_async :

    use rsmq_async::{Rsmq, RsmqError};
    use async_std::task;
    
    #[test]
    fn it_works() -> Result<(), RsmqError> {
        task::block_on(async {
            let mut rsmq = Rsmq::new(Default::default()).await?;
            
            let message = rsmq.receive_message_async("myqueue", None).await?;
            
            rsmq.delete_message_async("myqueue", &message.id).await?;
    
            Ok(())
        })
    }
    

    I get this on cargo test:

    ---- it_works stdout ----
    thread 'it_works' panicked at 'there is no reactor running, must be called from the context of Tokio runtime', src/libcore/option.rs:1188:5
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
    

    I'm not very into how futures work internally, but, is there any way for this library to return a future that doesn't require an specific executor?

    Edit: Btw, great work with this library!

    opened by DavidBM 23
  • Maintainers needed

    Maintainers needed

    I picked up maintenance of this crate a couple of years ago as it was heavily used at my work at the time. Since then I have switched jobs so I no longer have a direct motivator to continue maintenance.

    If anyone is feeling that they can and want to take over, please let me know.

    cc https://github.com/mitsuhiko/redis-rs/issues/376

    opened by Marwes 21
  • implemented BTreeMap/Set conversions ...

    implemented BTreeMap/Set conversions ...

    added the lacking BTreeMap/Set conversions ...

    I don't know where to plug in the to_redis_args based on the HashSet/Map implementation. Somehow BTreeMap has more traits and the implementation doesn't catch ...

    opened by przygienda 19
  • Connection manager

    Connection manager

    Early draft of a ConnectionManager that would address the reconnect behavior discussed in #218.

    Would be great to get some feedback on it. @Marwes you've written something like this in the past, right?

    To test, run cargo run --example async-connection-loss --features="tokio-rt-core" reconnect and then restart and/or stop redis. Output for a 2s server downtime:

    PING
    Query result: Ok("PONG")
    PING
    Query result: Ok("PONG")
    PING
    Connection lost, reconnecting
    Reconnecting failed: Connection refused (os error 111)
    Query result: Err(broken pipe)
    PING
    Connection lost, reconnecting
    Reconnecting failed: Connection refused (os error 111)
    Query result: Err(broken pipe)
    PING
    Connection lost, reconnecting
    Query result: Err(broken pipe)
    PING
    Query result: Ok("PONG")
    

    I'll add some comments inline.

    Based on #276.

    opened by dbrgn 17
  • Allow a more efficient pattern of Pipeline memory allocation

    Allow a more efficient pattern of Pipeline memory allocation

    This change allows a performance sensitive tight loop to reuse a Pipeline object instead of allocating a new one each time.

    • with_capacity allows to preallocate the internal commands vector to the specified capacity.
    • Pipeline.query_clear() clears the internal commands vector from values after the query (but keeps the allocated capacity).
    • The unitests show the expected behaviour of query vs query_clear.
    opened by tsnoam 17
  • Add Redis Streams commands

    Add Redis Streams commands

    Description

    This change set adds high-level wrappers for the Redis Streams commands (XREAD, XADD, etc). This is effectively a merge of https://github.com/grippy/redis-streams-rs into redis-rs.

    Adds a feature streams which is turned on by default (following the example of geo). Adds tests for the new commands. Adds an example of usage.

    Resolves #162.

    These changes deliver a significant feature set which was requested in August 2018.

    Task List

    • [x] address some outstanding lints
    • [x] add examples of how to manipulate the reply types
    • [x] fix doc links https://github.com/mitsuhiko/redis-rs/pull/319#discussion_r427010711 etc

    Attribution

    This body of work was produced by @grippy and the contributors in https://github.com/grippy/redis-streams-rs. Thanks for making this available to the community!

    opened by Terkwood 16
  • RESP3 support

    RESP3 support

    Hi, the Value enum supports ATM only RESP2 types. I would like to also add RESP3 support - would you prefer to add that as more enum types to Value (which would be a breaking change), or using some other way?

    Additional questions -

    • Since floats do not implement Eq, we'll need to import ordered-float, or a similar solution. Same for Hash derivation for recursive Maps. Is this acceptable?
    • In order to implement BigInt, we'll need to import BigInt or a similar solution. Is this acceptable?
    opened by nihohit 5
  • There should be an option to process the results of pipeline batch on a caller side.

    There should be an option to process the results of pipeline batch on a caller side.

    This is already somewhat known but opening a separate issue to track it specifically. Consider the following scenario: an application is populating the cache during an initial sync in big batches and one of the following happens:

    1. A batch contains 5000 hsets and a couple of the keys already exist in Redis but belong to a different data type(s).
    • Good luck with finding an offender among those 5000 items because all you get is WRONGTYPE: Operation against a key holding the wrong kind of value without any reference to a specific command in the pipelined batch (see the issue above).
    1. A batch was accepted by Redis and req_packed_commands received 4783 out of 5000 responses and then something happens (like dropped connection ). There is really no reason to re-send these 4783 entries again.

    And in general - it's much more flexible if a batch result processing is deferred to a caller.

    Would it be possible to add to ConnectionLike something like

        fn req_packed_commands_with_responses(
            &mut self,
            cmd: &[u8],
            batch_results: &mut Vec<RedisResult<Value>>,
            offset: usize,
            count: usize,
        ) -> RedisResult<Value>;
    

    which returns an error only if it wasn't able to pass the batch to Redis and the batch_results contains individual command responses? Though there might be a better implementation.

    Returning just a first error without any context is not very intuitive and doesn't match to the other redis client's behavior (hiredis/redis-py).

    opened by prokazov 3
  • Async Cluster Support

    Async Cluster Support

    The goal is to merge the currently forked redis-cluster-async lib into this repository. This will allow us to deprecate the fork and better maintain/improve async clustered Redis support going forward. Outstanding items need to accomplish this:

    • [ ] Merge #696 -- address comments here prior to or in subsequent PR post-merge
    • [ ] Finalize public API -- goal is to avoid future breaking changes while allowing for significant changes to current implementation
    • [ ] Ensure insecure TLS is supported (without this, current TLS-enabled test suite does not pass)
    • [ ] Ensure support for both tokio and async-std
    • [ ] Shared command routing logic w/ synchronous cluster impl
    • [ ] Use shared slot-parsing logic w/ synchronous cluster impl
    • [ ] Use ClusterParams
    • [ ] Rename cluster-async Pipeline to be less ambiguous / clashing with other names in the crate
    • [ ] Merge cluster-async Client with existing ClusterClient

    The preceding should be completed after the next 22.x release and all should be completed before another release is created.

    opened by jaymell 0
  • Feature request: Automatic serialization and deserialization of objects to JSON

    Feature request: Automatic serialization and deserialization of objects to JSON

    Redis.rs already supports some JSON-specific commands (with serde and serde-json), but there is no built-in way to get and set non-primitive structures. For example, even saving and reading a simple struct is impossible without serializing and deserializing manually:

    #[derive(Serialize, Deserialize)]
    struct Address {
        street: String,
        city: String,
    }
    
    fn main() -> Result<()> {
        let addr = Address { street: "street".to_string(), city: "city".to_string() };
        let client = redis::Client::open("redis://127.0.0.1/")?;
        let mut con = client.get_connection()?;
        // Set in Redis
        let serialized_addr = serde_json::to_string(&addr)?;
        con.set("address", serialized_addr)?;
        // Get from Redis
        let get_addr: String = con.get("address")?;
        let deserialized_addr: Address = serde_json::from_str(&get_addr)?;
    }
    

    If we want to allow to get and set this as a parameter, another way is to implement the two traits FromRedisValue and ToRedisArgs respectively. However, this is non-trivial, to say the least. It would make for a better developer experience if Redis.rs could make the implementation for these automatic.

    There are two ways to do this, the easiest would be to implement FromRedisValue and ToRedisArgs for every type that implement Deserialize and Serialize (impl <T>FromRedisValue for T where T: Deserialize). From a library user perspective, this would be the simplest, as one would only have to derive the serde traits. However this would create some collateral damage, because Rust doesn't (yet) have trait specialization, so it would collide with all types that Serialize is implemented for (including all numerics, strings and Vec<u8>).

    Probably a more standard way would be to provide a derive macro (#[derive(FromRedisValue, ToRedisArgs)]). This would generate a default implementation, that would use serde_json to serialize the struct to JSON (probably a safe default for most applications).

    A naive implementation of this could be this (mind the panic in the deserialization):

    impl FromRedisValue for Address {
        fn from_redis_value(v: &Value) -> RedisResult<Self> {
            match *v {
                Value::Data(ref bytes) => match serde_json::from_slice(&bytes) {
                    Ok(t) => Ok(t),
                    Err(_) => invalid_type_error!(v, "Response type not JSON serializable."),
                },
                _ => invalid_type_error!(v, "Response type not JSON serializable."),
            }
        }
    }
    
    impl ToRedisArgs for Address {
        fn write_redis_args<W>(&self, out: &mut W)
        where
            W: ?Sized + RedisWrite,
        {
            let mut buf = serde_json::to_vec(&self).unwrap(); // Maybe it shouldn't panic?
            out.write_arg(&buf)
        }
    }
    

    What do you think about this feature? I would love to contribute to this, as much as I can.

    opened by daniel7grant 1
  • [Feature Request] Add

    [Feature Request] Add "one node per shard" routing mode to support distributed query processing

    Current request routing supports AllNodes/AllMasters routing. What's missing is "one node per shard" routing. The use case is distributed transaction processing. e.g., I have a module command called M.QUERY, which performs per-shard query. I'd do Map/Reduce like distributed query:

    1. Route the command M.QUERY to "one node per shard" (ie., either master or replica node of each shard).
    2. Aggregate results from each shard and send the consolidated result back to the client.

    Using the current AllNodes/AllMasters routing, the command is only executed on all master. Replicas are not utilized for query, which makes it not scale well. (BTW, it seems to me that AllNodes is same as AllMasters. Can someone confirm? I thought AllNodes is supposed to include all replicas?)

    So, I'm proposing to add a "one node per shard" routing. Does the current code base have the infrastructure to support routing a ReadOnly command to a replica? How much work will be involved to implement the feature?

    opened by joehu888 2
Releases(redis-0.22.2)
  • redis-0.22.2(Jan 7, 2023)

    0.22.2 (2023-01-07)

    This release adds various incremental improvements and fixes a few long-standing bugs. Thanks to all our contributors for making this release happen.

    Features

    • Implement ToRedisArgs for HashMap (#722 @gibranamparan)
    • Add explicit MGET command (#729 @vamshiaruru-virgodesigns)

    Bug fixes

    • Enable single-item-vector get responses (#507 @hank121314)
    • Fix empty result from xread_options with deleted entries (#712 @Quiwin)
    • Limit Parser Recursion (#724)
    • Improve MultiplexedConnection Error Handling (#699)

    Changes

    • Add test case for atomic pipeline (#702 @CNLHC)
    • Capture subscribe result error in PubSub doc example (#739 @baoyachi)
    • Use async-std name resolution when necessary (#701 @UgnilJoZ)
    • Add Script::invoke_async method (#711 @r-bk)
    • Cluster Refactorings (#717, #716, #709, #707, #706 @0xWOF, @utkarshgupta137)
    • Fix intermitent test failure (#714 @0xWOF, @utkarshgupta137)
    • Doc changes (#705 @0xWOF, @utkarshgupta137)
    • Lint fixes (#704 @0xWOF)
    Source code(tar.gz)
    Source code(zip)
  • redis-0.21.7(Dec 12, 2022)

    0.21.7 (2022-12-10)

    This release addresses bugs related to server response parsing and MultiPlexedConnection error handling.

    Bug fixes

    • Limit parser recursion depth (#724) -- thank you to the OSS-Fuzz project for identifying the issue.
    • Improve MultiplexedConnection Error Handling (#699) -- thank you to @kvcache for identifying the issue (#698) and providing a reproducible example.
    Source code(tar.gz)
    Source code(zip)
  • redis-0.22.1(Oct 18, 2022)

  • redis-0.22.0(Oct 15, 2022)

    Redis-rs is a high level redis library for Rust and aims to provide convenient access to all Redis functionality through a very flexible but low-level API. The crate has recently come under maintainership by @djc and @jaymell. Much appreciation and many thanks to @mitsuhiko, @badboy, @Marwes for their work in building this library over the years! The new maintainers hope to improve the velocity of bug fixes, new features, and PR reviews in the coming months.

    This release adds various incremental improvements, including additional convenience commands, improved Cluster APIs, and various other bug fixes/library improvements.

    Although the changes here are incremental, this is a major release due to the breaking changes listed below.

    This release would not be possible without our many wonderful contributors -- thank you!

    Breaking changes

    • Box all large enum variants; changes enum signature (#667 @nihohit)
    • Support ACL commands by adding Rule::Other to cover newly defined flags; adds new enum variant (#685 @garyhai)
    • Switch from sha1 to sha1_smol; renames sha1 feature (#576)

    Features

    • Add support for RedisJSON (#657 @d3rpp)
    • Add support for weights in zunionstore and zinterstore (#641 @ndd7xv)
    • Cluster: Create read_from_replicas option (#635 @utkarshgupta137)
    • Make Direction a public enum to use with Commands like BLMOVE (#646 @thorbadour)
    • Add ahash feature for using ahash internally & for redis values (#636 @utkarshgupta137)
    • Add Script::load function (#603 @zhiburt)
    • Add support for OBJECT ([#610] @roger)
    • Add GETEX and GETDEL support (#582 @arpandaze)
    • Add support for ZMPOP (#605 @gkorland)

    Changes

    • Rust 2021 Edition / MSRV 1.59.0
    • Fix: Support IPV6 link-local address parsing (#679 @buaazp)
    • Derive Clone and add Deref trait to InfoDict (#661 @danni-m)
    • ClusterClient: add handling for empty initial_nodes, use ClusterParams to store cluster parameters, improve builder pattern (#669 @utkarshgupta137)
    • Implement Debug for MultiplexedConnection & Pipeline (#664 @elpiel)
    • Add support for casting RedisResult to CString (#660 @nihohit)
    • Move redis crate to subdirectory to support multiple crates in project (#465 @tdyas)
    • Stop versioning Cargo.lock (#620)
    • Auto-implement ConnectionLike for DerefMut (#567 @holmesmr)
    • Return errors from parsing inner items (#608)
    • Make dns resolution async, in async runtime (#606 @roger)
    • Make async_trait dependency optional (#572 @kamulos)
    • Add username to ClusterClient and ClusterConnection (#596 @gildaf)
    Source code(tar.gz)
    Source code(zip)
  • 0.13.0(Oct 14, 2019)

    Fixes and improvements

    • Breaking change: rename parse_async to parse_redis_value_async for consistency (ce59cecb).
    • Run clippy over the entire codebase (#238)
    • Breaking change: Make Script#invoke_async generic over aio::ConnectionLike (#242)

    BREAKING CHANGES

    Rename parse_async to parse_redis_value_async for consistency (ce59cecb).

    If you used redis::parse_async before, you now need to change this to redis::parse_redis_value_async or import the method under the new name: use redis::parse_redis_value_async.

    Make Script#invoke_async generic over aio::ConnectionLike (#242)

    Script#invoke_async was changed to be generic over aio::ConnectionLike in order to support wrapping a SharedConnection in user code. This required adding a new generic parameter to the method, causing an error when the return type is defined using the turbofish syntax.

    Old:

    redis::Script::new("return ...")
      .key("key1")
      .arg("an argument")
      .invoke_async::<String>()
    

    New:

    redis::Script::new("return ...")
      .key("key1")
      .arg("an argument")
      .invoke_async::<_, String>()
    
    Source code(tar.gz)
    Source code(zip)
  • 0.12.0(Oct 14, 2019)

    Fixes and improvements

    • Breaking change: Use dyn keyword to avoid deprecation warning (#223)
    • Breaking change: Update url dependency to v2 (#234)
    • Breaking change: (async) Fix Script::invoke_async return type error (#233)
    • Add GETRANGE and SETRANGE commands (#202)
    • Fix SINTERSTORE wrapper name, it's now correctly sinterstore (#225)
    • Allow running SharedConnection with any other runtime (#229)
    • Reformatted as Edition 2018 code (#235)

    BREAKING CHANGES

    Use dyn keyword to avoid deprecation warning (#223)

    Rust nightly deprecated bare trait objects. This PR adds the dyn keyword to all trait objects in order to get rid of the warning. This bumps the minimal supported Rust version to Rust 1.27.

    Update url dependency to v2 (#234)

    We updated the url dependency to v2. We do expose this on our public API on the redis::parse_redis_url function. If you depend on that, make sure to also upgrade your direct dependency.

    (async) Fix Script::invoke_async return type error (#233)

    Previously, invoking a script with a complex return type would cause the following error:

    Response was of incompatible type: "Not a bulk response" (response was string data('"4b98bef92b171357ddc437b395c7c1a5145ca2bd"'))
    

    This was because the Future returned when loading the script into the database returns the hash of the script, and thus the return type of String would not match the intended return type.

    This commit adds an enum to account for the different Future return types.

    Source code(tar.gz)
    Source code(zip)
  • 0.11.0(Oct 14, 2019)

    This release includes all fixes & improvements from the two beta releases listed below. This release contains breaking changes.

    Fixes and improvements

    • (async) Fix performance problem for SharedConnection (#222)
    • (async) Don't block the executor from shutting down (#217)
    • (async) Simplify implicit pipeline handling (#182)
    • (async) Use tokio_sync's channels instead of futures (#195)
    • (async) Only allocate one oneshot per request (#194)
    • Remove redundant BufReader when parsing (#197)
    • Hide actual type returned from async parser (#193)
    • Use more performant operations for line parsing (#198)
    • Optimize the command encoding, see below for breaking changes (#165)
    • Add support for geospatial commands (#130)
    • (async) Add support for async Script invocation (#206)

    BREAKING CHANGES

    Renamed the async module to aio (#189)

    async is a reserved keyword in Rust 2018, so this avoids the need to write r#async in it.

    Old code:

    use redis::async::SharedConnection;
    

    New code:

    use redis::aio::SharedConnection;
    

    The trait ToRedisArgs was changed (#165)

    ToRedisArgs has been changed to take take an instance of RedisWrite instead of Vec<Vec<u8>>. Use the write_arg method instead of Vec::push.

    Minimum Rust version is now 1.26 (#165)

    Upgrade your compiler. impl Iterator is used, requiring a more recent version of the Rust compiler.

    iter now takes self by value (#165)

    iter now takes self by value instead of cloning self inside the method.

    Old code:

    let mut iter : redis::Iter<isize> = cmd.arg("my_set").cursor_arg(0).iter(&con).unwrap();
    

    New code:

    let mut iter : redis::Iter<isize> = cmd.arg("my_set").cursor_arg(0).clone().iter(&con).unwrap();
    

    (The above line calls clone().)

    A mutable connection object is now required (#148)

    We removed the internal usage of RefCell and Cell and instead require a mutable reference, &mut ConnectionLike, on all command calls.

    Old code:

    let client = redis::Client::open("redis://127.0.0.1/")?;
    let con = client.get_connection()?;
    redis::cmd("SET").arg("my_key").arg(42).execute(&con);
    

    New code:

    let client = redis::Client::open("redis://127.0.0.1/")?;
    let mut con = client.get_connection()?;
    redis::cmd("SET").arg("my_key").arg(42).execute(&mut con);
    

    Due to this, transaction has changed. The callback now also receives a mutable reference to the used connection.

    Old code:

    let client = redis::Client::open("redis://127.0.0.1/").unwrap();
    let con = client.get_connection().unwrap();
    let key = "the_key";
    let (new_val,) : (isize,) = redis::transaction(&con, &[key], |pipe| {
        let old_val : isize = con.get(key)?;
        pipe
            .set(key, old_val + 1).ignore()
            .get(key).query(&con)
    })?;
    

    New code:

    let client = redis::Client::open("redis://127.0.0.1/").unwrap();
    let mut con = client.get_connection().unwrap();
    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)
    })?;
    

    Remove rustc-serialize feature (#200)

    We removed serialization to/from JSON. The underlying library is deprecated for a long time.

    Old code in Cargo.toml:

    [dependencies.redis]
    version = "0.9.1"
    features = ["with-rustc-json"]
    

    There's no replacement for the feature. Use serde and handle the serialization/deserialization in your own code.

    Remove with-unix-sockets feature (#201)

    We removed the Unix socket feature. It is now always enabled. We also removed auto-detection.

    Old code in Cargo.toml:

    [dependencies.redis]
    version = "0.9.1"
    features = ["with-unix-sockets"]
    

    There's no replacement for the feature. Unix sockets will continue to work by default.

    Source code(tar.gz)
    Source code(zip)
  • 0.10.0(Oct 14, 2019)

    • Fix handling of passwords with special characters (#163)
    • Better performance for async code due to less boxing (#167)
      • CAUTION: redis-rs will now require Rust 1.26
    • Add clear method to the pipeline (#176)
    • Better benchmarking (#179)
    • Fully formatted source code (#181)
    Source code(tar.gz)
    Source code(zip)
  • 0.9.1(Sep 10, 2018)

  • 0.9.0(Aug 8, 2018)

    Some time has passed since the last release. This new release will bring less bugs, more commands, experimental async support and better performance.

    Highlights:

    • Implement flexible PubSub API (#136)
    • Avoid allocating some redundant Vec's during encoding (#140)
    • Add an async interface using futures-rs (#141)
    • Allow the async connection to have multiple in flight requests (#143)

    The async support is currently experimental.

    Source code(tar.gz)
    Source code(zip)
Owner
Armin Ronacher
Software developer and Open Source nut. Creator of the Flask framework. Engineering at @getsentry. Other things of interest: @pallets and @rust-lang
Armin Ronacher
RedisLess is a fast, lightweight, embedded and scalable in-memory Key/Value store library compatible with the Redis API.

RedisLess is a fast, lightweight, embedded and scalable in-memory Key/Value store library compatible with the Redis API.

Qovery 145 Nov 23, 2022
Redis re-implemented in Rust.

rsedis Redis re-implemented in Rust. Why? To learn Rust. Use Cases rsedis does not rely on UNIX-specific features. Windows users can run it as a repla

Sebastian Waisbrot 1.6k Jan 6, 2023
A rust Key-Value store based on Redis.

Key-Value Store A Key-Value store that uses Redis to store data. Built using an async web framework in Rust with a full Command-Line interface and log

Miguel David Salcedo 0 Jan 14, 2022
Basic Redis Protocol specification in Rust

Basic Redis Protocol specification in Rust

Bruno 1 Jan 20, 2022
Rewrite Redis in Rust for evaluation and learning.

Drill-Redis This library has been created for the purpose of evaluating Rust functionality and performance. As such, it has not been fully tested. The

Akira Kawahara 3 Oct 18, 2022
Redis compatible server framework for Rust

Redis compatible server framework for Rust Features Create a fast custom Redis compatible server in Rust Simple API. Support for pipelining and telnet

Josh Baker 61 Nov 12, 2022
An intentionally-limited Rust implementation of the Redis server with no external dependencies.

lil-redis An intentionally-limited Rust implementation of the Redis server. lil redis is an accessible implementation of a very basic Redis server (wi

Miguel Piedrafita 37 Jan 1, 2023
📺 Netflix in Rust/ React-TS/ NextJS, Actix-Web, Async Apollo-GraphQl, Cassandra/ ScyllaDB, Async SQLx, Kafka, Redis, Tokio, Actix, Elasticsearch, Influxdb Iox, Tensorflow, AWS

Fullstack Movie Streaming Platform ?? Netflix in RUST/ NextJS, Actix-Web, Async Apollo-GraphQl, Cassandra/ ScyllaDB, Async SQLx, Spark, Kafka, Redis,

null 34 Apr 17, 2023
Lightweight async Redis client with connection pooling written in pure Rust and 100% memory safe

redi-rs (or redirs) redi-rs is a Lightweight Redis client with connection pooling written in Rust and 100% memory safe redi-rs is a Redis client writt

Oğuz Türkay 4 May 20, 2023
Simple and flexible queue implementation for Rust with support for multiple backends (Redis, RabbitMQ, SQS, etc.)

Omniqueue Omniqueue is an abstraction layer over queue backends for Rust. It includes support for RabbitMQ, Redis streams, and SQS out of the box. The

Svix 8 May 26, 2023
Sharded, concurrent mini redis that support http interface implemented in rust

Rudis A mini version of redis server that provides http interface implemented in Rust. The in-memorry kv-storage is sharded and concurrent safe. Inspi

Lorenzo Cao 43 May 30, 2023
Learning Rust by implementing parts of redis.

Redis This is a simple CLI Redis inspired project that supports the GET, SET, and INCR commands. Run it Have rust installed (if you don't, visit rustu

Shahzeb K. 3 Mar 28, 2024
RedisJSON - a JSON data type for Redis

RedisJSON RedisJSON is a Redis module that implements ECMA-404 The JSON Data Interchange Standard as a native data type. It allows storing, updating a

null 3.4k Jan 1, 2023
[POC] Redis Module for TiKV

RedisTikvPoc [POC] Redis Module for TiKV This is a POC repository. This Redis Module will add branch new Redis commands to operate TiKV data. After bu

Rain Li 6 Jun 25, 2022
Incomplete Redis client and server implementation using Tokio - for learning purposes only

mini-redis mini-redis is an incomplete, idiomatic implementation of a Redis client and server built with Tokio. The intent of this project is to provi

Tokio 2.3k Jan 4, 2023
A port of `java.util.*SummaryStatistics` as a Redis Module

RedisNumbersStats RedisNumbersStats is a Redis module that implements a Redis version of the Java Util *SummaryStatistics classes, such as DoubleSumma

Brian Sam-Bodden 4 Oct 4, 2022
A simplified version of a Redis server supporting SET/GET commands

This is a starting point for Rust solutions to the "Build Your Own Redis" Challenge. In this challenge, you'll build a toy Redis clone that's capable

Patrick Neilson 2 Nov 15, 2022
Macros for redis-rs to serialize and deserialize structs automatically

redis-macros Simple macros and wrappers to redis-rs to automatically serialize and deserialize structs with serde. Installation To install it, simply

Daniel Grant 4 Feb 18, 2023
A cross-platform redis gui client

Redis-Manager A cross-platform redis gui client started developing with Tauri, React and Typescript in Vite. Get Started Prerequisites Install Node.js

Kurisu 11 Mar 31, 2023