-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Question about boost::redis::request::config #181
Comments
I hadn't known how to setup Case2 situation.
Then, redis server start accepting DEBUG commands. For example:
10 seconds later I got
This means we can test redis server delayed response. I wrote the following test code using Boost.Redis 1.84.0. #include <string>
#include <iostream>
#include <optional>
#include <chrono>
#include <boost/asio.hpp>
#include <boost/redis/src.hpp>
namespace asio = boost::asio;
namespace redis = boost::redis;
int main() {
asio::io_context ioc;
redis::config cfg;
cfg.health_check_interval = std::chrono::seconds(0);
redis::request::config req_cfg;
req_cfg.cancel_on_connection_lost = false; // need to set false
req_cfg.cancel_if_not_connected = false;
req_cfg.cancel_if_unresponded = false; // need to set false
req_cfg.hello_with_priority = true;
redis::request req{req_cfg};
redis::response<std::optional<std::string>> resp;
auto conn = std::make_shared<redis::connection>(ioc.get_executor());
conn->async_run(cfg, {}, asio::consign(asio::detached, conn));
req.push("DEBUG", "SLEEP", 10);
std::cout << "please restart redis" << std::endl;
conn->async_exec(
req,
resp,
[&](boost::system::error_code const& ec, std::size_t size) {
std::cout << "ec:" << ec.message() << std::endl;
std::cout << "size:" << size << std::endl;
std::cout << "resp.has_value():" << std::get<0>(resp).has_value() << std::endl;
if (std::get<0>(resp).has_value()) {
if (std::get<0>(resp).value()) {
std::cout << "resp.value():" << *std::get<0>(resp).value() << std::endl;
}
else {
std::cout << "nullopt" << std::endl;
}
}
std::cout << "resp.has_error():" << std::get<0>(resp).has_error() << std::endl;
if (std::get<0>(resp).has_error()) {
std::cout << "resp.error().diagnostic:" << std::get<0>(resp).error().diagnostic << std::endl;
}
conn->cancel();
}
);
ioc.run();
}
When I see the output I tested the combination of
When only I set both I'm not sure why I need to set |
|
@criatura2 , thank you for the comment. I understand
I set request config as follows for testing: redis::request::config req_cfg;
req_cfg.cancel_on_connection_lost = true; // for testing set true
req_cfg.cancel_if_not_connected = false;
req_cfg.cancel_if_unresponded = false; // need to set false
req_cfg.hello_with_priority = true;
redis::request req{req_cfg}; After
Why does it happen? |
Hi, can't reproduce the problem. Your test program has the correct behavior in my tests
Can you please enable logging to better undestand what is happening, use debug level like this conn->async_run(cfg, {redis::logger::level::debug}, asio::consign(asio::detached, conn)); In my computer this results in
|
Here is my log with debug log enabled:
Just in case, I paste whole code: #include <string>
#include <iostream>
#include <optional>
#include <chrono>
#include <boost/asio.hpp>
#include <boost/redis/src.hpp>
namespace asio = boost::asio;
namespace redis = boost::redis;
int main() {
asio::io_context ioc;
redis::config cfg;
cfg.health_check_interval = std::chrono::seconds(0);
redis::request::config req_cfg;
req_cfg.cancel_on_connection_lost = true; // for testing set true
req_cfg.cancel_if_not_connected = false;
req_cfg.cancel_if_unresponded = false; // need to set false
req_cfg.hello_with_priority = true;
redis::request req{req_cfg};
redis::response<std::optional<std::string>> resp;
auto conn = std::make_shared<redis::connection>(ioc.get_executor());
conn->async_run(cfg, {redis::logger::level::debug}, asio::consign(asio::detached, conn));
req.push("DEBUG", "SLEEP", 10);
std::cout << "please restart redis" << std::endl;
conn->async_exec(
req,
resp,
[&](boost::system::error_code const& ec, std::size_t size) {
std::cout << "ec:" << ec.message() << std::endl;
std::cout << "size:" << size << std::endl;
std::cout << "resp.has_value():" << std::get<0>(resp).has_value() << std::endl;
if (std::get<0>(resp).has_value()) {
if (std::get<0>(resp).value()) {
std::cout << "resp.value():" << *std::get<0>(resp).value() << std::endl;
}
else {
std::cout << "nullopt" << std::endl;
}
}
std::cout << "resp.has_error():" << std::get<0>(resp).has_error() << std::endl;
if (std::get<0>(resp).has_error()) {
std::cout << "resp.error().diagnostic:" << std::get<0>(resp).error().diagnostic << std::endl;
}
conn->cancel();
}
);
ioc.run();
} |
It is behaving as if reconnection had been disabled but without being able to reproduce it it is hard to tell. Does conn->async_run(cfg, {redis::logger::level::debug}, asio::consign(asio::detached, conn)); with conn->async_run(cfg, {redis::logger::level::debug}, [conn](auto ec){
std::cout << "async_run: " << ec.message() << std::endl;
}); and let me know if you see the output |
I tested it. Here is the result:
The last line, async_run seems to be returned. Perhaps it is caused by Here is the result:
Program is not finished. async_run() callback is not invoked. |
Still can't understand where is the problem. I will create a branch with improved logging so we can narrow down the problem. By the way, are you using the develop or master branch? |
I tested both Boost.Redis 1.84.0 and develop (commit hash 0445e74), then got the same result. |
I have found the problem: When Redis is restarted the read operation fails and calls Later on the internal hello command failed because it was coalesced with the I am still unsure how to fix this: I can use brute force by setting a flag |
@mzimbres , thank you for the comment. It is good that you found the problem. By the way, Boost.Redis user's point of view, when I set both |
This should work well but I did not make this the default behaviour because there is a small window for double execution of a request
This is an unlikely theoretical possibility, so I decided to be conservative.
There are a couple of tests testing these flags, |
Thank you for the detail comment. It is very helpful to understand what is the difficult case.
If I understand correctly, if users only use idempotence request, it is not harmful. However, not all redis request is idempotence. For example By the way, in spite of Boost.Redis efforts, redis server could lost data by shutdown (e.g. power outage). Fortunately, my usecase requires idempotence operations only. So I think that I can set
I am not sure you already prepared the mechanisim but I guess that you need to prepare RESP3 mock server or timing controlable client side mock for testing. Then you can create any subtle timing in the test code. Or test-mode code could be required in the library side code (it is not an ideal). |
I have fixed the problem in this branch https://github.com/boostorg/redis/tree/181-question-about-boostredisrequestconfig. Can you have a look and let me know if it solves the problem on your side? Thanks. |
I tests your branch on my environment. It seems that the redis request finally sent and got expected result.
I added the comment NOTE: |
The default retry interval is 1s. AFAICS, the 10s you are observing comes from |
@criatura2 , sorry it was my mistake. The 10 seconcs wait is form
I wrote above comment. But I noticed that I used a wrong executable file. |
boost::redis::request::config has four member variables.
I want to know the behavior of cancel or not cancel.
I assume that redis server is running, and
async_run()
is called with reconnect_wait_interval 10 seconds.Case1: async_exec during disconnected
I tested it by my enviromnent, and works as above. It is expected behavior for me.
Case2: disconnect after async_exec called but not completion handler is invoked.
I am looking for the way that Boost.Redis resends step1 request to the server and receives the response and then, invoke the completion handler of the step1. So the user doesn't need to care about disconnection/resending.
I guess that
boost::redis::request::config
membercancel_if_unresponded
andcancel_on_connection_lost
are related.If I set
cancel_on_connection_lost = false
, Does Boost.Redis resend the request of step1 automatically ?Additional question: Is
cancel_if_unresponded
related to the situation?The text was updated successfully, but these errors were encountered: