2
0
mirror of https://github.com/boostorg/redis.git synced 2026-01-19 04:42:09 +00:00

Fixes async_exec terminal cancellation.

This commit is contained in:
Marcelo Zimbres
2022-12-25 20:01:35 +01:00
parent ad5dd8c30b
commit 4f9dcc7dc5
3 changed files with 21 additions and 15 deletions

View File

@@ -47,17 +47,16 @@ that ensures that one operation is cancelled as soon as the other
completes, these functions play the following roles
* `connection::async_exec`: Execute commands by writing the request payload to the underlying stream and reading the response sent back by Redis. It can be called from multiple places in your code concurrently.
* `connection::async_run`: Coordinate the low-level IO (read and write) operations and remains suspended until the connection is lost.
* `connection::async_run`: Coordinate the low-level IO (read and write) operations. It remains suspended until the connection is lost.
When a connection is lost, the `async_exec` calls won't automatically
fail, instead, they will remain suspended until they are either all
canceled with a call to `connection::cancel(operation::exec)` or a new
connection is established and `async_run` is called again, in which
case they will be resent automatically. Users can customise this
behaviour by carefully choosing the values of
The `async_exec` calls won't automatically fail when the connection is
lost, instead, they will remain suspended until either
`connection::cancel(operation::exec)` is called to cancel them all or
a new connection is established and `async_run` is called again.
Users can customise the desired behaviour by carefully choosing
`aedis::resp3::request::config`. The role played by `async_run`
becomes clearer with long-lived connections, which we will cover
in the next section.
becomes clearer with long-lived connections, which we will cover in
the next section.
<a name="connection"></a>
## Connection

View File

@@ -139,9 +139,18 @@ EXEC_OP_WAIT:
if (is_cancelled(self)) {
if (info->is_written()) {
self.get_cancellation_state().clear();
goto EXEC_OP_WAIT; // Too late, can't cancel.
if (self.get_cancellation_state().cancelled() == boost::asio::cancellation_type_t::terminal) {
// Cancellation requires closing the connection
// otherwise it stays in inconsistent state.
conn->cancel(operation::run);
return self.complete(ec, 0);
} else {
// Can't implement other cancelation types, ignoring.
self.get_cancellation_state().clear();
goto EXEC_OP_WAIT;
}
} else {
// Cancelation can be honored.
conn->remove_request(info);
self.complete(ec, 0);
return;

View File

@@ -110,7 +110,7 @@ auto ignore_implicit_cancel_of_req_written() -> net::awaitable<void>
// Will be cancelled before it is written.
resp3::request req2;
req2.get_config().coalesce = false;
//req2.get_config().cancel_on_connection_lost = true;
req2.get_config().cancel_on_connection_lost = true;
req2.push("PING");
net::steady_timer st{ex};
@@ -123,11 +123,9 @@ auto ignore_implicit_cancel_of_req_written() -> net::awaitable<void>
st.async_wait(redir(ec3))
);
BOOST_TEST(!ec1);
BOOST_CHECK_EQUAL(ec1, net::error::basic_errors::operation_aborted);
BOOST_CHECK_EQUAL(ec2, net::error::basic_errors::operation_aborted);
BOOST_TEST(!ec3);
conn->cancel(operation::run);
}
auto cancel_of_req_written_on_run_canceled() -> net::awaitable<void>