mirror of
https://github.com/XRPLF/clio.git
synced 2026-09-30 17:08:27 +00:00
fix: Fiber suspension during exception (#3187)
This commit is contained in:
@@ -103,16 +103,21 @@ retryOnTimeout(
|
||||
auto retry = util::makeRetryExponentialBackoff(delays, yield.get_executor());
|
||||
|
||||
while (true) {
|
||||
// Suspending a coroutine from inside a catch block is not safe so we copy out the failure.
|
||||
std::string failure;
|
||||
|
||||
try {
|
||||
return func();
|
||||
} catch (DatabaseError const& e) {
|
||||
auto const delayMs =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(retry.delayValue()).count();
|
||||
LOG(log.error()) << e.what() << " (attempt " << retry.attemptNumber() + 1
|
||||
<< "). Retrying in " << delayMs << "ms ...";
|
||||
|
||||
retry.wait(yield);
|
||||
failure = e.what();
|
||||
}
|
||||
|
||||
auto const delayMs =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(retry.delayValue()).count();
|
||||
LOG(log.error()) << failure << " (attempt " << retry.attemptNumber() + 1
|
||||
<< "). Retrying in " << delayMs << "ms ...";
|
||||
|
||||
retry.wait(yield);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "util/Retry.hpp"
|
||||
|
||||
#include "util/Assert.hpp"
|
||||
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
@@ -8,6 +10,7 @@
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
@@ -95,6 +98,14 @@ ExponentialBackoffStrategy::nextDelay() const
|
||||
void
|
||||
Retry::wait(boost::asio::yield_context yield)
|
||||
{
|
||||
// Suspending a coroutine while an exception is being handled corrupts the caught-exception
|
||||
// state, which is per-thread rather than per-coroutine. Copy whatever is needed out of the
|
||||
// handler and let it exit before waiting.
|
||||
ASSERT(
|
||||
std::current_exception() == nullptr,
|
||||
"Retry::wait must not be called while an exception is being handled"
|
||||
);
|
||||
|
||||
*canceled_ = false;
|
||||
timer_.expires_after(strategy_->getDelay());
|
||||
strategy_->increaseDelay();
|
||||
|
||||
Reference in New Issue
Block a user