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

Adds support for asio::cancel_after (#324)

* Adds support for asio::cancel_after in connection::{async_exec, async_run}
* Adds cancel_after tests
* Adds an example on using asio::cancel_after
* Adds a discussion page on timeouts and the `cancel_if_unresponded` flag

close #226
This commit is contained in:
Anarthal (Rubén Pérez)
2025-10-06 18:11:25 +02:00
committed by GitHub
parent 0c159280ba
commit d3e335942f
9 changed files with 309 additions and 35 deletions

View File

@@ -1,5 +1,6 @@
* xref:index.adoc[Introduction]
* xref:requests_responses.adoc[]
* xref:cancellation.adoc[]
* xref:serialization.adoc[]
* xref:logging.adoc[]
* xref:benchmarks.adoc[]

View File

@@ -0,0 +1,57 @@
//
// Copyright (c) 2025 Marcelo Zimbres Silva (mzimbres@gmail.com),
// Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
= Cancellation
Requests may take a very long time. If the server is down, they may suspend forever,
waiting for the server to be up. Fortunately, requests can be cancelled after
a certain time using asio::cancel_after:
```
request req;
// ...
co_await conn.async_exec(req, resp, asio::cancel_after(10s));
```
If the request hasn't been responded after 10 seconds, it will
fail with `asio::error::operation_aborted`. With the coroutine
usage above, this means a `boost::system::system_error` exception
with the error code mentioned above.
== Retrying idempotent requests
By default, the library waits until the server is up,
and then sends the request. But what happens if there is a communication
error after sending the request, but before receiving a response?
In this situation, we don't know if the request was processed by the server or not.
And we have no way to know it. By default, the library mark these requests as
failed with `asio::error::operation_aborted`. (TODO: do we want another error code here?).
Some requests can be executed several times and result in the same outcome
as executing them only once. We say that these requests are idempotent.
The `SET` command is idempotent, while `INCR` is not.
If you know that a request contains only idempotent commands,
you can instruct Redis to retry the request on failure, even
if the library is unsure about whether the server received the request or not.
You can do so by setting request::config::cancel_if_unresponded to false:
```
request req;
req.push("SET", "my_key", 42); // idempotent
req.get_config().cancel_on_connection_lost = false; // TODO: we shouldn't need this
req.get_config().cancel_if_unresponded = false; // retry
// Makes sure that the key is set, even in the presence of network errors.
// Note that if the server is down, the current coroutine will remain suspended
// until the server is capable of serving requests again (e.g. until a process manager restarts the server).
// Use cancel_after as seen above if you need to limit this time.
co_await conn.async_exec(req, ignore);
```

View File

@@ -139,6 +139,7 @@ receiver(std::shared_ptr<connection> conn) -> net::awaitable<void>
Here is a list of topics that you might be interested in:
* xref:cancellation.adoc[Setting timeouts to requests and managing cancellation].
* xref:requests_responses.adoc[More on requests and responses].
* xref:serialization.adoc[Serializing and parsing into custom types].
* xref:logging.adoc[Configuring logging].