use associated executors for intermediate handlers

Summary: * per-operation cancellation changed: total/partial signals only prevent further resending, terminal signal cancels the whole client

Reviewers: ivica

Reviewed By: ivica

Subscribers: korina

Differential Revision: https://repo.mireo.local/D27246
This commit is contained in:
Bruno Iljazovic committed 2024-01-09 16:35:16 +01:00
1 parent 1996251253
commit d78fdd3208
21 files changed
+311 -414

No files matched your search

@@ -39,8 +39,7 @@ public:
CompletionToken&& token
) {
auto initiation = [this](auto handler) {
auto ex = asio::get_associated_executor(handler, _ex);
asio::post(ex,
asio::post(_ex,
asio::prepend(std::move(handler), error_code {})
);
};
+69 -74
View File
@@ -15,7 +15,8 @@ namespace async_mqtt5::test {
enum cancel_type {
ioc_stop = 1,
client_cancel
client_cancel,
signal_emit
};
} // end namespace async_mqtt5::test
@@ -34,27 +35,42 @@ void cancel_async_receive() {
using client_type = mqtt_client<stream_type>;
client_type c(ioc, "");
c.brokers("mqtt.mireo.local", 1883)
c.brokers("127.0.0.1", 1883)
.credentials("test-cli", "", "")
.run();
auto handler = [&handlers_called](
error_code ec, std::string, std::string, publish_props
) {
BOOST_CHECK_EQUAL(ec, asio::error::operation_aborted);
handlers_called++;
};
std::vector<asio::cancellation_signal> signals(3);
for (auto i = 0; i < num_handlers; ++i)
c.async_receive([&handlers_called](
error_code ec, std::string, std::string, publish_props
) {
BOOST_CHECK_EQUAL(ec, asio::error::operation_aborted);
handlers_called++;
});
c.async_receive(asio::bind_cancellation_slot(
signals[i].slot(),
std::move(handler)
));
asio::steady_timer timer(c.get_executor());
timer.expires_after(std::chrono::seconds(1));
timer.expires_after(std::chrono::milliseconds(10));
timer.async_wait([&](auto) {
if constexpr (type == ioc_stop)
ioc.stop();
else
else if constexpr (type == client_cancel)
c.cancel();
else if constexpr (type == signal_emit)
std::for_each(
signals.begin(), signals.end(),
[](auto& signal) {
signal.emit(asio::cancellation_type_t::terminal);
}
);
});
ioc.run();
ioc.run_for(std::chrono::milliseconds(20));
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
}
@@ -71,87 +87,68 @@ void cancel_async_publish() {
using client_type = mqtt_client<stream_type>;
client_type c(ioc, "");
c.brokers("mqtt.mireo.local", 1883)
c.brokers("127.0.0.1", 1883)
.credentials("test-cli", "", "")
.run();
std::vector<asio::cancellation_signal> signals(3);
c.async_publish<qos_e::at_most_once>(
"topic", "payload", retain_e::yes, {},
[&handlers_called](error_code ec) {
BOOST_CHECK_EQUAL(ec, asio::error::operation_aborted);
handlers_called++;
}
asio::bind_cancellation_slot(
signals[0].slot(),
[&handlers_called](error_code ec) {
BOOST_CHECK_EQUAL(ec, asio::error::operation_aborted);
handlers_called++;
}
)
);
c.async_publish<qos_e::at_least_once>(
"topic", "payload", retain_e::yes, {},
[&handlers_called](error_code ec, reason_code rc, puback_props) {
BOOST_CHECK_EQUAL(ec, asio::error::operation_aborted);
BOOST_CHECK_EQUAL(rc, reason_codes::empty);
handlers_called++;
}
asio::bind_cancellation_slot(
signals[1].slot(),
[&handlers_called](error_code ec, reason_code rc, puback_props) {
BOOST_CHECK_EQUAL(ec, asio::error::operation_aborted);
BOOST_CHECK_EQUAL(rc, reason_codes::empty);
handlers_called++;
}
)
);
c.async_publish<qos_e::exactly_once>(
"topic", "payload", retain_e::yes, {},
[&handlers_called](error_code ec, reason_code rc, pubcomp_props) {
BOOST_CHECK_EQUAL(ec, asio::error::operation_aborted);
BOOST_CHECK_EQUAL(rc, reason_codes::empty);
handlers_called++;
}
asio::bind_cancellation_slot(
signals[2].slot(),
[&handlers_called](error_code ec, reason_code rc, pubcomp_props) {
BOOST_CHECK_EQUAL(ec, asio::error::operation_aborted);
BOOST_CHECK_EQUAL(rc, reason_codes::empty);
handlers_called++;
}
)
);
asio::steady_timer timer(c.get_executor());
timer.expires_after(std::chrono::seconds(1));
timer.expires_after(std::chrono::milliseconds(10));
timer.async_wait([&](auto) {
if constexpr (type == ioc_stop)
ioc.stop();
else
else if constexpr (type == client_cancel)
c.cancel();
else if constexpr (type == signal_emit)
std::for_each(
signals.begin(), signals.end(),
[](auto& signal) {
signal.emit(asio::cancellation_type_t::terminal);
}
);
});
ioc.run();
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
}
template <test::cancel_type type>
void cancel_during_connecting() {
using namespace test;
constexpr int expected_handlers_called = type == ioc_stop ? 0 : 1;
int handlers_called = 0;
asio::io_context ioc;
using stream_type = asio::ip::tcp::socket;
using client_type = mqtt_client<stream_type>;
client_type c(ioc, "");
c.brokers("127.0.0.1", 1883)
.run();
c.async_publish<qos_e::at_most_once>(
"topic", "payload", retain_e::yes, {},
[&handlers_called](error_code ec) {
BOOST_CHECK_EQUAL(ec, asio::error::operation_aborted);
handlers_called++;
}
);
asio::steady_timer timer(c.get_executor());
timer.expires_after(std::chrono::seconds(2));
timer.async_wait([&](auto) {
if constexpr (type == ioc_stop)
ioc.stop();
else
c.cancel();
});
ioc.run();
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
}
BOOST_AUTO_TEST_SUITE(cancellation/*, *boost::unit_test::disabled()*/)
@@ -159,11 +156,14 @@ BOOST_AUTO_TEST_CASE(ioc_stop_async_receive) {
cancel_async_receive<test::cancel_type::ioc_stop>();
}
BOOST_AUTO_TEST_CASE(client_cancel_async_receive) {
cancel_async_receive<test::cancel_type::client_cancel>();
}
BOOST_AUTO_TEST_CASE(signal_emit_async_receive) {
cancel_async_receive<test::cancel_type::signal_emit>();
}
// passes on debian, hangs on windows in io_context destructor
BOOST_AUTO_TEST_CASE(ioc_stop_async_publish, *boost::unit_test::disabled() ) {
cancel_async_publish<test::cancel_type::ioc_stop>();
@@ -173,13 +173,8 @@ BOOST_AUTO_TEST_CASE(client_cancel_async_publish) {
cancel_async_publish<test::cancel_type::client_cancel>();
}
// passes on debian, hangs on windows
BOOST_AUTO_TEST_CASE(ioc_stop_cancel_during_connecting, *boost::unit_test::disabled() ) {
cancel_during_connecting<test::cancel_type::ioc_stop>();
}
BOOST_AUTO_TEST_CASE(client_cancel_during_connecting) {
cancel_during_connecting<test::cancel_type::client_cancel>();
BOOST_AUTO_TEST_CASE(signal_emit_async_publish) {
cancel_async_publish<test::cancel_type::signal_emit>();
}
#ifdef BOOST_ASIO_HAS_CO_AWAIT
-29
View File
@@ -260,35 +260,6 @@ BOOST_AUTO_TEST_CASE(test_topic_alias_maximum) {
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
}
BOOST_AUTO_TEST_CASE(test_publish_immediate_cancellation) {
constexpr int expected_handlers_called = 1;
int handlers_called = 0;
asio::io_context ioc;
using client_service_type = test::test_service<asio::ip::tcp::socket>;
auto svc_ptr = std::make_shared<client_service_type>(ioc.get_executor());
asio::cancellation_signal cancel_signal;
auto h = [&handlers_called](error_code ec, reason_code rc, puback_props) {
++handlers_called;
BOOST_CHECK(ec == asio::error::operation_aborted);
BOOST_CHECK_EQUAL(rc, reason_codes::empty);
};
auto handler = asio::bind_cancellation_slot(cancel_signal.slot(), std::move(h));
detail::publish_send_op<
client_service_type, decltype(handler), qos_e::at_least_once
> { svc_ptr, std::move(handler) }
.perform(
"test", "payload", retain_e::no, {}
);
cancel_signal.emit(asio::cancellation_type::terminal);
ioc.run();
BOOST_CHECK_EQUAL(handlers_called, expected_handlers_called);
}
BOOST_AUTO_TEST_CASE(test_publish_cancellation) {
constexpr int expected_handlers_called = 1;
int handlers_called = 0;
+1
View File
@@ -27,6 +27,7 @@ BOOST_AUTO_TEST_CASE(clear_waiting_on_pubrel) {
asio::io_context ioc;
using client_service_type = test::test_service<asio::ip::tcp::socket>;
auto svc_ptr = std::make_shared<client_service_type>(ioc.get_executor());
svc_ptr->open_stream();
decoders::publish_message pub_msg = std::make_tuple(
"topic", int16_t(1), uint8_t(0b0100), publish_props {}, "payload"