Comments (12)
I have created a new issue to improve cancellation support, see #32 so I will continue there. AFAICS, this ticket can be closed as the crashes have been fixed.
from redis.
You can easily reproduce it with simple loop like:
for (;;)
{
auto timer = asio::steady_timer{ executor, std::chrono::milliseconds{ 10 } };
co_await (connection.async_run(endpoint, asio::use_awaitable) || timer.async_wait(asio::use_awaitable));
}
from redis.
Thanks for reporting. Aedis was designed to provide built-in timeouts. The call to
co_await (connection.async_run(endpoint, asio::use_awaitable) || timer.async_wait(asio::use_awaitable));
is probably messing around with the internal operations in a way I did not test before. I am considering disabling this type of cancellation unless there is a reason for not doing so. I want to avoid every user implementing timeouts on their side over and over again. For all possible timeouts see https://github.com/mzimbres/aedis/blob/fd82204ba9e6e85b1011c96ebff79539c4227ddf/include/aedis/connection.hpp#L46
from redis.
Timeout here is just for demonstration, I'm not using timers like that I just cancel the connection for other reasons.
Point is that async_run is not can cancellable properly.
from redis.
How are you cancelling, with connection::cancel(operation::run)
? Do you observe the same behaviour if you cancel like this
timer.async_wait([&](auto){conn.cancel(operation::run)})
I will investigate this issue on the weekend.
from redis.
Haven't tested that, but because I am using it in coroutines, it needs to be cancellable because even if I use current coroutines cancellation slot it will get overwritten by co_await conn.async_run(...)
from redis.
I can't reproduce the crash with this
#include <chrono>
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/experimental/awaitable_operators.hpp>
#include <aedis.hpp>
#include <aedis/src.hpp>
namespace net = boost::asio;
using namespace net::experimental::awaitable_operators;
using aedis::endpoint;
using connection = aedis::connection<>;
net::awaitable<void> reconnect(std::shared_ptr<connection> db)
{
net::steady_timer timer{co_await net::this_coro::executor};
for (;;) {
timer.expires_after(std::chrono::milliseconds{10});
endpoint ep{"127.0.0.1", "6379"};
co_await (
db->async_run(ep, net::use_awaitable) ||
timer.async_wait(net::use_awaitable)
);
std::cout << "Retrying" << std::endl;
}
}
int main()
{
net::io_context ioc;
auto db = std::make_shared<connection>(ioc);
net::co_spawn(ioc, reconnect(db), net::detached);
ioc.run();
}
from redis.
The crash on line : ~/third_party/aedis/include/aedis/detail/connection_ops.hpp:536
is not possible on a normal cancellation. I am afraid this is indicating a buffer overflow somewhere in your program. Can you please enable sanitizers? For example, I get a crash if I use
co_await (
db->async_run({"127.0.0.1", "6379"}, net::use_awaitable) ||
timer.async_wait(net::use_awaitable)
);
instead of
endpoint ep{"127.0.0.1", "6379"};
co_await (
db->async_run(ep, net::use_awaitable) ||
timer.async_wait(net::use_awaitable)
);
from redis.
I can't reproduce the crash with this
#include <chrono> #include <iostream> #include <boost/asio.hpp> #include <boost/asio/experimental/awaitable_operators.hpp> #include <aedis.hpp> #include <aedis/src.hpp> namespace net = boost::asio; using namespace net::experimental::awaitable_operators; using aedis::endpoint; using connection = aedis::connection<>; net::awaitable<void> reconnect(std::shared_ptr<connection> db) { net::steady_timer timer{co_await net::this_coro::executor}; for (;;) { timer.expires_after(std::chrono::milliseconds{10}); endpoint ep{"127.0.0.1", "6379"}; co_await ( db->async_run(ep, net::use_awaitable) || timer.async_wait(net::use_awaitable) ); std::cout << "Retrying" << std::endl; } } int main() { net::io_context ioc; auto db = std::make_shared<connection>(ioc); net::co_spawn(ioc, reconnect(db), net::detached); ioc.run(); }
I can reproduce it with your code here, it takes a little time to happen (most of the times under 60 secs). some times it leads to that assertion fail some times dead lock.
Try change the time form 10ms to 6ms it happens faster.
And of course make sure you are in debug build.
Changing timer to something low like 1ms leads to a new assertion fail:
test: ~/third_party/aedis/include/aedis/detail/net.hpp:101: void aedis::detail::resolve_op<boost::asio::ip::basic_resolver<boost::asio::ip::tcp>, boost::asio::basic_waitable_timer<std::chrono::steady_clock>>::operator()(Self &, std::array<std::size_t, 2>, boost::system::error_code, boost::asio::ip::tcp::resolver::results_type, boost::system::error_code) [Resolver = boost::asio::ip::basic_resolver<boost::asio::ip::tcp>, Timer = boost::asio::basic_waitable_timer<std::chrono::steady_clock>, Self = boost::asio::detail::composed_op<aedis::detail::resolve_op<boost::asio::ip::basic_resolver<boost::asio::ip::tcp>, boost::asio::basic_waitable_timer<std::chrono::steady_clock>>, boost::asio::detail::composed_work<void (boost::asio::any_io_executor, boost::asio::any_io_executor)>, boost::asio::detail::composed_op<aedis::detail::resolve_with_timeout_op<aedis::connection<>>, boost::asio::detail::composed_work<void (boost::asio::any_io_executor)>, boost::asio::detail::composed_op<aedis::detail::run_op<aedis::connection<>>, boost::asio::detail::composed_work<void (boost::asio::any_io_executor)>, boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code>, void (boost::system::error_code)>, void (boost::system::error_code)>, void (boost::system::error_code, boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>)>]: Assertion (!ec2)&&("resolve_op: Incompatible state.")' failed.
from redis.
The second assertion you found is something I thought was impossible to happen but does not represent a pre condition for my code to work. I will remove it since it can indeed happen. Thanks again for reporting.
from redis.
This commit 3a03a43 fixes the problems I could reproduce so far. There is still a problem though if use very short timeouts like 1ms, in this case it seems that the cancellation gets lost. I will have to investigate more.
from redis.
Are you using the same commit that I mentioned in first comment?
here is another assertion fail:
test: ~/third_party/aedis/include/aedis/resp3/detail/exec.hpp:133: void aedis::resp3::detail::exec_with_timeout_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp>, boost::asio::basic_waitable_timer<std::chrono::steady_clock>, aedis::adapter::detail::general_aggregate<std::vector<aedis::resp3::node<std::string>>>, boost::asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char>>>::operator()(Self &, std::array<std::size_t, 2>, boost::system::error_code, std::size_t, boost::system::error_code) [AsyncStream = boost::asio::basic_stream_socket<boost::asio::ip::tcp>, Timer = boost::asio::basic_waitable_timer<std::chrono::steady_clock>, Adapter = aedis::adapter::detail::general_aggregate<std::vector<aedis::resp3::node<std::string>>>, DynamicBuffer = boost::asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char>>, Self = boost::asio::detail::composed_op<aedis::resp3::detail::exec_with_timeout_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp>, boost::asio::basic_waitable_timer<std::chrono::steady_clock>, aedis::adapter::detail::general_aggregate<std::vector<aedis::resp3::node<std::string>>>, boost::asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char>>>, boost::asio::detail::composed_work<void (boost::asio::any_io_executor, boost::asio::any_io_executor)>, boost::asio::detail::composed_op<aedis::detail::run_op<aedis::connection<>>, boost::asio::detail::composed_work<void (boost::asio::any_io_executor)>, boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code>, void (boost::system::error_code)>, void (boost::system::error_code, unsigned long)>]: Assertion (!ec2)&&("exec_with_timeout_op: Unexpected completion order.")' failed.
Maybe using the following code helps to reproduce it faster:
#include <boost/asio.hpp>
#include <boost/asio/experimental/awaitable_operators.hpp>
#include <aedis.hpp>
#include <aedis/src.hpp>
#include <chrono>
#include <iostream>
namespace net = boost::asio;
using namespace net::experimental::awaitable_operators;
using aedis::endpoint;
using connection = aedis::connection<>;
net::awaitable< void >
reconnect()
{
auto executor = co_await net::this_coro::executor;
auto db1 = connection{ executor };
auto db2 = connection{ executor };
auto db3 = connection{ executor };
auto db4 = connection{ executor };
auto timer = net::steady_timer{ executor };
for (int i = 0;; i++)
{
timer.expires_after(std::chrono::milliseconds{ 10 });
endpoint ep{ "127.0.0.1", "6379" };
co_await (db1.async_run(ep, net::use_awaitable) || db2.async_run(ep, net::use_awaitable) ||
db3.async_run(ep, net::use_awaitable) || db4.async_run(ep, net::use_awaitable) ||
timer.async_wait(net::use_awaitable));
std::cout << i << std::endl;
}
}
int
main()
{
net::io_context ioc;
net::co_spawn(ioc, reconnect(), net::detached);
ioc.run();
}
from redis.
Related Issues (20)
- Pass socket close errors to the caller HOT 1
- Understand why we have to call connection.cancel in the TLS test
- MGET with invalid key unexpectedly reports error HOT 4
- Remove resp3::read and resp3::async_read
- Enable reading server pushes in batches
- geoadd error HOT 1
- Boost docs formatting problems
- Docs styles minor tweaks
- Add ability to check if initial connection to server succeeded HOT 2
- Support containers in CI HOT 1
- Using AWS cluster - Trouble writing values to it HOT 5
- No way to specify CA/client certificate for SSL connections. HOT 10
- Where to reinstate SSL verification spec? HOT 4
- Redis client fails to process all the requests. HOT 30
- How to use cmake or link an example? HOT 5
- Windows Visual Studio 2022 C++17/C++20 failed compilation of src.hpp. HOT 14
- Are distinct connection objects thread safe ? HOT 24
- How to treat well return nothing lua function ? HOT 2
- Question about boost::redis::request::config HOT 17
- second call to async_exec hangs and never returns HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from redis.