Giter VIP home page Giter VIP logo

Comments (16)

jaymell avatar jaymell commented on June 12, 2024

Can you post a reproducible example?

from redis-rs.

x1qqq avatar x1qqq commented on June 12, 2024

I have tried reproducing on a test function, everything seems to be working fine there somehow.

The only difference from my code and the test function, is that I'm passing the ConnectionManager to a TypeMap, everything else functionality wise is the same.

To give a little bit more context on what I am doing, I am building a discord bot with serenity-rs and using this library (redis-rs) to fetch json objects.

Here is my test function

#[cfg(test)]
mod tests {
    use std::time::Duration;

    use redis::aio::ConnectionLike;
    use redis::{aio::ConnectionManager, JsonAsyncCommands};
    use serenity::all::InteractionType;

    use crate::database::{InteractionStepKind, InteractionStep};
    use crate::slash_command::SlashCommandFunctionality;
    use crate::payload::captcha::UpdateSettings;
        

    #[tokio::test]
    async fn redis_json_get() {
        // Init redis
        let host = "127.0.0.1";
        let port = 6379;
        let user = "default";
        let password = "development";
        let database = 0;

        let client = redis::Client::open(format!("redis://{}:{}@{}:{}/{}", user, password, host, port, database)).unwrap();
        let mut conn_manager = ConnectionManager::new_with_backoff(client, 2, 2, 5).await.unwrap();

        let object = InteractionStep::new(
            &ulid::Ulid::new().to_string(),
            InteractionStepKind::ConfirmAction { confirm_button_id: "aaa".to_string(), cancel_button_id: "bbb".to_string() },
            SlashCommandFunctionality::UpdateCaptchaSettings(UpdateSettings { enabled: false, verified_role_id: Some(0000000), unverified_role_id: Some(111111) }),
            InteractionType::Component,
            00000000000000,
        );

        // JSON.SET
        let mut pipeline = redis::pipe();
        pipeline.json_set(&object.id, "$", &object).unwrap()
            .cmd("EXPIRE").arg(&object.id).arg(60).ignore();
        conn_manager.req_packed_commands(&pipeline, 0, 2).await.unwrap();
       

        tokio::time::sleep(Duration::from_secs(30)).await;

        // JSON.GET
        let object_fetched : InteractionStep = conn_manager.json_get(&object.id, "$").await.unwrap();

        assert_eq!(object, object_fetched)
    }
}

image

from redis-rs.

x1qqq avatar x1qqq commented on June 12, 2024

I seem to have found the origin of the issue, I am not aware of what it is specifically but.

There might be something wrong with the implementation of ConnectionLike and subsequently JsonAsyncCommands for ConnectionManager.

This was my previous function wrapper over json_get, which was giving me the unexpected behavior above
image

As soon as I removed the generic parameter and defined the type as ConnectionManager, things started working as expected again.

image

EDIT

I have managed to reproduce the unexpected behavior, it seems that its my issue due to defining the count argument on the req_packed_commands in an incorrect way.

I did think by calling ignore() on a command of the pipeline would make it so that specific command's response would not be read by the connection. It seems like it is, and if I set the count less to the amount of responses available, they will be eventually read by the json_get functionality, making it so it responds with an unexpected value.

Here is the test code

#[cfg(test)]
mod tests {
    use std::time::Duration;

    use redis::aio::ConnectionLike;
    use redis::{aio::ConnectionManager, JsonAsyncCommands};
    use serenity::all::InteractionType;

    use crate::database::{InteractionStepKind, InteractionStep};
    use crate::slash_command::SlashCommandFunctionality;
    use crate::payload::captcha::UpdateSettings;
     

    async fn json_get_wrapper<C: JsonAsyncCommands>(id: &str, c: &mut C) -> InteractionStep {
        c.json_get(id, "$").await.unwrap()
    }

    async fn json_set_wrapper<C: ConnectionLike>(object: &InteractionStep, conn: &mut C) {
        let mut pipeline = redis::pipe();
        pipeline.json_set(&object.id, "$", &object).unwrap()
            .cmd("EXPIRE").arg(&object.id).arg(60).ignore();

        conn.req_packed_commands(&pipeline, 0, 1).await.unwrap();
    }

    #[tokio::test]
    async fn redis_json_get() {
        // Init redis
        let host = "127.0.0.1";
        let port = 6379;
        let user = "default";
        let password = "development";
        let database = 0;

        let client = redis::Client::open(format!("redis://{}:{}@{}:{}/{}", user, password, host, port, database)).unwrap();
        let mut conn_manager = ConnectionManager::new_with_backoff(client, 2, 2, 5).await.unwrap();

        let object = InteractionStep::new(
            &ulid::Ulid::new().to_string(),
            InteractionStepKind::ConfirmAction { confirm_button_id: "aaa".to_string(), cancel_button_id: "bbb".to_string() },
            SlashCommandFunctionality::UpdateCaptchaSettings(UpdateSettings { enabled: false, verified_role_id: Some(0000000), unverified_role_id: Some(111111) }),
            InteractionType::Component,
            00000000000000,
        );

        // JSON.SET
        json_set_wrapper(&object, &mut conn_manager).await;
        tokio::time::sleep(Duration::from_secs(20)).await;
        // JSON.GET
        let object_fetched : InteractionStep = json_get_wrapper(&object.id, &mut conn_manager).await; 

        assert_eq!(object, object_fetched)
    }
}

from redis-rs.

nihohit avatar nihohit commented on June 12, 2024

Yes, the req_packed_commands arguments are a bit confusing - essentially, mostly the offset & count arguments have only 2 correct options - either (0, \<num of commands\>) for non-atomic pipelines, or (\<num of commands\> + 1, 1) for atomic pipelines. Ignored commands don't matter here.
It seems to me like the function was intended to be internal to the crate, and is supposed to be used in the pipeline's query/query_async function.

@jaymell We can definitely improve the command's documentation to reflect this, but if we're ok with breaking backwards compatibility about this, IMO we should hide this function from the users. It's a bit of a footgun.

from redis-rs.

x1qqq avatar x1qqq commented on June 12, 2024

@nihohit Thanks for the information, yeah it's definitely a bit confusing.
I wasn't aware that ignoring commands on the pipeline wouldn't count when using that same pipeline in the req_packed_commands.
So from what I understood, calling the ignore() function on a command, only works as intended when query/query_async pipeline's functions are called, is that right?

from redis-rs.

nihohit avatar nihohit commented on June 12, 2024

@x1qqq query/query_async/execute are the correct interfaces.

from redis-rs.

nihohit avatar nihohit commented on June 12, 2024

@x1qqq, can this issue be closed?

from redis-rs.

mrjackwills avatar mrjackwills commented on June 12, 2024

I am also experiencing a similar error, I am trying to create a simple example at the moment.

from redis-rs.

nihohit avatar nihohit commented on June 12, 2024

@mrjackwills are you also using req_packed_commands?

from redis-rs.

mrjackwills avatar mrjackwills commented on June 12, 2024

@mrjackwills are you also using req_packed_commands?

No, I'm using the simple AsyncCommands. I am trying to debug at the moment, I think my issue might be related to the TTL command, but there are many layers to try to delve through.

from redis-rs.

mrjackwills avatar mrjackwills commented on June 12, 2024

Ok, so I have finally worked out the issue, I was using the wrong connection type.

I should have been using a ConnectionManager rather then Connection. As this connection is being shared in a multi-threaded API backend. So far, this seems to have solved the issues I was having.

from redis-rs.

Cheban1996 avatar Cheban1996 commented on June 12, 2024
 redis: Response was of incompatible type - TypeError: "Response type not string compatible." (response was int(1)
 redis: Response was of incompatible type - TypeError: "Response type not bool compatible." (response was string-data('"{\"id\":16,\"devices\":300,\"is_active\":true,\"online\":0}"'))

And i don't know how reproduced it
What intersting is errors from prod
but local and staging is good working

from redis-rs.

nihohit avatar nihohit commented on June 12, 2024

@Cheban1996 what's the issue? Int isn't string compatible, and strings aren't bool compatible.

from redis-rs.

Cheban1996 avatar Cheban1996 commented on June 12, 2024

@nihohit It was noticed that there are no problems at low loads. But when the load is heavy, instead of the expected data for a certain type, we get something completely different - as if from a different pool.
For greater understanding, I also use bb8-redis = "0.14.0" to pull threads. It looks like the problem is related to out of sync responses between threads. When we expect one thing and get another from another stream

from redis-rs.

nihohit avatar nihohit commented on June 12, 2024

what connection type do you use?
if it's aio::Connection, it's deprecated - use aio::MultiplexedConnection.

from redis-rs.

Cheban1996 avatar Cheban1996 commented on June 12, 2024

@nihohit Thank you so much
It's resolve my trouble

from redis-rs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.