sewenew / redis-plus-plus

Redis client written in C++
Apache License 2.0
1.6k stars 347 forks source link

Issue with Specific Redis Plus Plus Exceptions Not Being Caught #545

Closed Hamza091 closed 7 months ago

Hamza091 commented 8 months ago

Hi, I'm currently facing an issue while using async redis plus plus, specifically related to handling exceptions. I've implemented the usage of future objects to retrieve values in callbacks. However, I've encountered an unexpected behavior where specific Redis Plus Plus exceptions, such as ClosedError or IoError, are not being caught as expected. Instead, a generic Error exception is consistently thrown. Here's the code snippet:

void readMsgCallBack(Future<Streams>&&fut){
   Streams reply;
    try{

        reply = fut.get();

    }catch(const ClosedError &err){
        cout<<"ClosedError "<<endl;
        cout<<string(err.what())<<endl;
    }catch(const IoError &err){
        cout<<"IoError "<<endl;
        cout<<string(err.what())<<endl;
    }catch(const Error &err){
        cout<<"Error "<<endl;
        cout<<string(err.what())<<endl;
    } 
}

What could be the possible reason for this behaviour?

sewenew commented 7 months ago

Sorry, but I cannot reproduce your problem. You can try the following code:

AsyncRedis r("redis://127.0.0.1:6378");   // <---- set a wrong port number, and the client will get an IO error.
r.get("key", [](Future<OptionalString> &&fut) {
            try {
                cout << *fut.get() << endl;
            } catch (const ClosedError &e) {
                cout << "closed error: " << e.what() << endl;
            } catch (const IoError &e) {
                cout << "io error: " << e.what() << endl;
            } catch (const Error &e) {
                cout << "error: " << e.what() << endl;
            }
        });
string s;
cin >> s;

Since Redis does not listen on port 6378, the client receives a IO error, and it print io error: xxxxxx.

It seems that you might not get any IO error. You can check the error message to see if it's really an IO error.

Regards

Hamza091 commented 7 months ago

Thank you for the code snippet. I've tried it out, and indeed, setting the wrong port number results in an IO error as expected. I think the problem is specifically with the generic command interface for async redis. Could you please verify this? because I am still getting same issue with generic command interface.

sewenew commented 7 months ago

This has nothing to do with generic interface, and you can change the get command with a generic interface call to test it:

AsyncRedis r("redis://127.0.0.1:6378");   // <---- set a wrong port number, and the client will get an IO error.
r.command<OptionalString>("get", "key", [](Future<OptionalString> &&fut) {    // <---- call `get` with generic interface
            try {
                cout << *fut.get() << endl;
            } catch (const ClosedError &e) {
                cout << "closed error: " << e.what() << endl;
            } catch (const IoError &e) {
                cout << "io error: " << e.what() << endl;
            } catch (const Error &e) {
                cout << "error: " << e.what() << endl;
            }
        });
string s;
cin >> s;

And it shows the same result.

Maybe you can show me a minimum code snippet that reproducing your problem, so that I can do some research on it.

Regards

Hamza091 commented 7 months ago

Actually, I want to handle failover conditions and want to do retries based on specific exceptions, like if connection is lost during execution of some query or if there is some network issue then I intend to rerun that query. Specifically, if I execute a blocking query and encounter a connection closure while Redis is stopped, I anticipate a ClosedError exception. While this scenario functions correctly with synchronous Redis, I'm encountering difficulties in capturing these specific exceptions with asynchronous Redis.

Code snippet to reproduce the issue:


vector<string> command =  {"XREADGROUP","GROUP",groupName,consumerName,"BLOCK","0","COUNT","1","STREAMS",topic,">"};

asyncRedis->command<Streams>(command.begin(),command.end(),[callBack](Future<Streams> &&fut){

            std::exception* exp = nullptr;
            Streams res;

            try{
                res = fut.get();

            }catch(ClosedError &err){

                // connection is closed during execution of some query     
                cout<<string(err.what())<<endl;
                // do retries

            }catch(IoError &err){

                // connection refused
                cout<<string(err.what())<<endl;
                // do retries

            }catch(Error &err){

                cout<<string(err.what())<<endl;

            }      

        });
`
sewenew commented 7 months ago

Thanks for describing your scenario, and I can reproduce your problem with any blocking command, such as BLPOP.

I've fixed the problem, and you can try the latest code. If you still have problem, feel free to let me know.

Regards

sewenew commented 7 months ago

Close the issue, since there's no update.

Regards