Defense against non-responsive aria RPC on startup

Downloader constructor may get stuck if the check for the aria2c RPC
being up gets stuck due to curl_easy_perform() never returning (or, at
least, taking longer than I was willing to wait). Currently it may
happen, for example, after an application crashes with active downloads
being saved to slow media. Then the next creation of a Downloader object
will deal with aria2c immediately resuming those downloads and becoming
unresponsive as it struggles flushing incoming data to slow storage (or
because of some other unfortunate timing of the RPC request being
received while it cannot yet be served).
This commit is contained in:
Veloman Yunkan 2024-06-28 12:52:53 +04:00
parent e8afcbe6ae
commit 42295c9010
1 changed files with 16 additions and 6 deletions

View File

@ -97,20 +97,30 @@ Aria2::Aria2():
curl_easy_setopt(p_curl, CURLOPT_PORT, m_port); curl_easy_setopt(p_curl, CURLOPT_PORT, m_port);
curl_easy_setopt(p_curl, CURLOPT_POST, 1L); curl_easy_setopt(p_curl, CURLOPT_POST, 1L);
curl_easy_setopt(p_curl, CURLOPT_ERRORBUFFER, curlErrorBuffer); curl_easy_setopt(p_curl, CURLOPT_ERRORBUFFER, curlErrorBuffer);
curl_easy_setopt(p_curl, CURLOPT_TIMEOUT_MS, 100);
int watchdog = 50; typedef std::chrono::duration<double> Seconds;
while(--watchdog) {
const double MAX_WAITING_TIME_SECONDS = 0.5;
const auto t0 = std::chrono::steady_clock::now();
bool maxWaitingTimeWasExceeded = false;
CURLcode res = CURLE_OK;
while ( !maxWaitingTimeWasExceeded ) {
sleep(10); sleep(10);
curlErrorBuffer[0] = 0; curlErrorBuffer[0] = 0;
auto res = curl_easy_perform(p_curl); res = curl_easy_perform(p_curl);
if (res == CURLE_OK) { if (res == CURLE_OK) {
break; break;
} else if (watchdog == 1) {
LOG_ARIA_ERROR();
} }
const auto dt = std::chrono::steady_clock::now() - t0;
const double elapsedTime = std::chrono::duration_cast<Seconds>(dt).count();
maxWaitingTimeWasExceeded = elapsedTime > MAX_WAITING_TIME_SECONDS;
} }
curl_easy_cleanup(p_curl); curl_easy_cleanup(p_curl);
if (!watchdog) { if ( maxWaitingTimeWasExceeded ) {
LOG_ARIA_ERROR();
throw std::runtime_error("Cannot connect to aria2c rpc. Aria2c launch cmd : " + launchCmd); throw std::runtime_error("Cannot connect to aria2c rpc. Aria2c launch cmd : " + launchCmd);
} }
} }