Skip to content

async command callback invoking policy when disconnecting #57

@redboltz

Description

@redboltz

I have a question about the policy of invoking callback handler.

When I call RedisAsyncClient::command() during disconnected, callback function doesn't seems to be called. Is that intentional specification?

Here is the small example code that demonstrates the behavior.
I've tested it with f55ffdc.

#include <string>
#include <iostream>

#include <boost/asio/ip/address.hpp>

#include <redisclient/redisasyncclient.h>

int main() {
    boost::asio::ip::address address = boost::asio::ip::address::from_string("127.0.0.1");
    const unsigned short port = 6379;
    boost::asio::ip::tcp::endpoint endpoint(address, port);

    boost::asio::io_service ioService;
    redisclient::RedisAsyncClient redis(ioService);
    boost::system::error_code ec;

    redis.connect(
        endpoint,
        [&]
        (auto const& ec) {
            if(ec) {
                std::cerr << __LINE__ <<
                    ": Can't connect to redis: " << ec.message() << std::endl;
                return;
            }
            std::cout << __LINE__ <<
                ": Please restart redis service within 5 seconds for testing!" << std::endl;
            sleep(5);

            std::cout << __LINE__ <<
                ": do async command" << std::endl;
            redis.command(
                "SET",
                {"key", "value"},
                [&]
                (auto const& result) {
                    if( result.isError() )
                    {
                        std::cerr << __LINE__ <<
                            ": SET error: " << result.toString() << "\n";
                        return ;
                    }
                    std::cout << __LINE__ <<
                        ": result: " << result.toString() << std::endl;
                }
            );
            std::cout << __LINE__ <<
                ": finish async command" << std::endl;
        }
    );

    std::function<void(boost::system::error_code const&)> handler;

    handler =
        [&handler, &redis, &endpoint]
        (boost::system::error_code const& ec) {
        if (ec) {
            std::cout << __LINE__ <<
                ": ec: " << ec << std::endl;
            redis.disconnect();
            std::cout << __LINE__ <<
                ": trying reconnect inner..." << std::endl;
            sleep(1);
            redis.connect(
                endpoint,
                handler);
        }
        else {
            std::cout << __LINE__ <<
                ": reconnect success" << std::endl;
        }
    };

    redis.installErrorHandler(
        [&](std::string const& ec) {
            std::cout << __LINE__ <<
                ": ec: " << ec << std::endl;
            std::cout << __LINE__ <<
                ": trying reconnect..." << std::endl;
            redis.disconnect();
            redis.connect(
                endpoint,
                handler
            );
        }
    );

    ioService.run();
}

When I run the program, the following message is appeared:

26: Please restart redis service within 5 seconds for testing!

Then if I do nothing within 5 seconds, I got the following message:

30: do async command
47: finish async command
43: result: OK

The last line (43) indicates that RedisAsyncClient::command() callback is called.

If I restart redis service within 5 seconds, I got the following message:

26: Please restart redis service within 5 seconds for testing!

I do sudo systemctl restart redis.service.

30: do async command
47: finish async command
76: ec: End of file
78: trying reconnect...
69: reconnect success

That indicates that RedisAsyncClient::command() callback is NOT called. But the handler that is installed using Redis::installErrorHandler() is called.

Is that expected behavior?

I want to implement automatic re-execute RedisAsyncClient::command() mechanism if the redis connection is disconnected.

In order to do that, I think that the following mechanism is required:

  1. Prepare a queue.
  2. Before calling RedisAsyncClient::command(), I copy the contents of the command and push it to the queue.
  3. If the RedisAsyncClient::command() callback is called, erase the pushed command. If installed error handler is called, reconnect to redis, and when reconnected, call RedisAsyncClient::command() for each commands in the queue.

Before I implement it in my client program, I'd like to clarify the library spec.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions