sewenew / redis-plus-plus

Redis client written in C++
Apache License 2.0
1.64k stars 351 forks source link

[QUESTION]Exceptions block the program except the first time it runs #382

Closed shihao-thx closed 2 years ago

shihao-thx commented 2 years ago

Describe the problem Hi @sewenew, I had a blocked program when I tried to use try catch for async redis++ exception. The Code is:

#include "redis++/async_redis++.h"
#include <iostream>
#include <string>

using namespace sw::redis;
using namespace std;

int main() {
    ConnectionOptions opts;
    opts.host = "192.168.127.139";
    opts.socket_timeout = std::chrono::milliseconds(2);
    opts.port = 6379;

    ConnectionPoolOptions pool_opts;
    pool_opts.size = 3;
    pool_opts.wait_timeout = std::chrono::milliseconds(100);

    std::unique_ptr<AsyncRedis> redis_client;
    redis_client.reset(new AsyncRedis(opts, pool_opts));

    try {
        Future<std::string> ping_res = redis_client->ping();
        if(ping_res.get() == "PONG") {
            cout << "hello redis" << endl;
        }   
    } catch (const ReplyError &err) {
        // WRONGTYPE Operation against a key holding the wrong kind of value
        cout << err.what() << endl;
    } catch (const TimeoutError &err) {
        // reading or writing timeout
        cout << err.what() << endl;
    } catch (const ClosedError &err) {
        // the connection has been closed.
        cout << err.what() << endl;
    } catch (const IoError &err) {
        // there's an IO error on the connection.
        cout << err.what() << endl;
    } catch (const Error &err) {
        // other errors
        cout << err.what() << endl;
    }

    return 0;
}

It worked well when I first ran it. And it gave me the exception: failed to connect to server: No route to host. But when I ran it again, I got nothing. It was blocked. It does work again when I change the opts.host. Failed again when I ran it the second time. BTW, I used the std::future. Environment:

sewenew commented 2 years ago

First of all, the error message shows that your client cannot connect to Redis server, and you should check the network setting.

Secondly, it seems that when you run the program the second time, the client hangs when trying to connecting to Redis. The current implement of async interface does not support setting connection timeout and socket timeout. I'll try to add this support ASAP, and then you can try to set connection_timeout to see if it still hangs.

B.T.W your socket_timeout is too small (although the async interface does not support setting socket timeout so far).

Regards

shihao-thx commented 2 years ago

Secondly, it seems that when you run the program the second time, the client hangs when trying to connecting to Redis. The current implement of async interface does not support setting connection timeout and socket timeout. I'll try to add this support ASAP, and then you can try to set connection_timeout to see if it still hangs.

I tried pool_opts.connection_lifetime = std::chrono::milliseconds(1000); and the block disappeared. But I guess it's really not good to use this in projects. Right? Are there other ways to handle a exception when request or response errors are happening? And I have another question that why the client hangs when trying to connecting to Redis could still exist, after all the process is killed(ctrl + c) before I run it the second time.

B.T.W your socket_timeout is too small (although the async interface does not support setting socket timeout so far).

Thanks for the reminder.

Regards.

sewenew commented 2 years ago

But I guess it's really not good to use this in projects. Right?

NO. You can use it in production. connection_lifetime is used to renew a connection. It won't hurt performance, unless you set a very small connection_lifetime. In your case, it means reconnecting every 1000ms, i.e. 1s, that's too small.

However, I'm not sure why the block behavior disappears when you set this option....

Are there other ways to handle a exception when request or response errors are happening?

So far, there's no other ways.

why the client hangs when trying to connecting to Redis could still exist, after all the process is killed(ctrl + c) before I run it the second time.

If the process has been killed, the client should not hang. Instead, it should exit.

Regards

shihao-thx commented 2 years ago

Thanks for the detailed response.

If the process has been killed, the client should not hang. Instead, it should exit.

I am sorry for not understanding this. Does this mean the program actually exit when I use ctrl + c rather than be killed. Are there any differences?

Regards.

sewenew commented 2 years ago

There's no difference. Unless you set a signal handle to catch the SIGINT, ctrl-c will kill the process, and the process will exit.

Regards

shihao-thx commented 2 years ago

Secondly, it seems that when you run the program the second time, the client hangs when trying to connecting to Redis.

Sorry. I have got into a deep doubt. In this case, ctrl-c to kill the process, what recorded the first connect request. How does the program know first connect request has already happened so that it choose to hang up? Is there a temporary file being created when the first request starts and it can exist although the process is killed?

Regards.

sewenew commented 2 years ago

@shihao-thx What you described should not be true. The second run should have nothing to do with the first run.

However, I'm not a network or operation system expert, and not sure why you see different results running the program twice... Maybe you need to seek help from a network or operation system expert.

Regards

shihao-thx commented 2 years ago

Fine. Thank you very much again.

Regards.

sewenew commented 2 years ago

Since there's no update, I'll close this issue.

Regards