diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2014-09-29 13:18:50 +0200 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2014-09-29 13:18:50 +0200 |
commit | 135f68e249e4b01df7d9b5387a045bfb91bc4455 (patch) | |
tree | 722f0641af8d0abcf40570e38f8d72c2981d3d8a /src/storage | |
parent | 46e06bf378e5edc38b5ce1c3ab1e4567eb756d24 (diff) | |
download | qtlocation-mapboxgl-135f68e249e4b01df7d9b5387a045bfb91bc4455.tar.gz |
add retries in case of connection failures
Diffstat (limited to 'src/storage')
-rw-r--r-- | src/storage/http_request.cpp | 76 |
1 files changed, 73 insertions, 3 deletions
diff --git a/src/storage/http_request.cpp b/src/storage/http_request.cpp index fb079d2588..a60f4b8913 100644 --- a/src/storage/http_request.cpp +++ b/src/storage/http_request.cpp @@ -93,35 +93,78 @@ void HTTPRequest::startHTTPRequest(std::unique_ptr<Response> &&res) { HTTPRequestBaton::start(http_baton); } + + void HTTPRequest::handleHTTPResponse(HTTPResponseType responseType, std::unique_ptr<Response> &&res) { assert(uv_thread_self() == thread_id); assert(!http_baton); assert(!response); switch (responseType) { - case HTTPResponseType::TemporaryError: + // This error was caused by a temporary error and it is likely that it will be resolved + // immediately. We are going to try again right away. This is like the TemporaryError, + // except that we will not perform exponential back-off. case HTTPResponseType::SingularError: + if (attempts >= 4) { + // Report as error after 4 attempts. + response = std::move(res); + notify(); + } else if (attempts >= 2) { + // Switch to the back-off algorithm after the second failure. + retryHTTPRequest(std::move(res), (1 << attempts) * 1000); + return; + } else { + startHTTPRequest(std::move(res)); + } + break; + + // This error might be resolved by waiting some time (e.g. server issues). + // We are going to do an exponential back-off and will try again in a few seconds. + case HTTPResponseType::TemporaryError: + if (attempts >= 4) { + // Report error back after it failed completely. + response = std::move(res); + notify(); + } else { + retryHTTPRequest(std::move(res), (1 << attempts) * 1000); + } + break; + + // This error might be resolved once the network reachability status changes. + // We are going to watch the network status for changes and will retry as soon as the + // operating system notifies us of a network status change. case HTTPResponseType::ConnectionError: - fprintf(stderr, "error: %s\n", res->message.c_str()); - // TODO: retry + + if (attempts >= 4) { + // Report error back after it failed completely. + response = std::move(res); + notify(); + } else { + // By default, we will retry every 60 seconds. + retryHTTPRequest(std::move(res), 60000); + } break; + // The request was canceled programatically. case HTTPResponseType::Canceled: response.reset(); notify(); break; + // This error probably won't be resolved by retrying anytime soon. We are giving up. case HTTPResponseType::PermanentError: response = std::move(res); notify(); break; + // The request returned data successfully. We retrieved and decoded the data successfully. case HTTPResponseType::Successful: store->put(path, type, *res); response = std::move(res); notify(); break; + // The request confirmed that the data wasn't changed. We already have the data. case HTTPResponseType::NotModified: store->updateExpiration(path, res->expires); response = std::move(res); @@ -134,6 +177,22 @@ void HTTPRequest::handleHTTPResponse(HTTPResponseType responseType, std::unique_ } } +void HTTPRequest::retryHTTPRequest(std::unique_ptr<Response> &&res, uint64_t timeout) { + assert(uv_thread_self() == thread_id); + assert(!backoff_timer); + backoff_timer = new uv_timer_t(); + uv_timer_init(loop, backoff_timer); + using Store = std::pair<HTTPRequest *, std::unique_ptr<Response>>; + backoff_timer->data = new Store(this, std::move(res)); + uv_timer_start(backoff_timer, [](uv_timer_t *timer) { + std::unique_ptr<Store> pair { static_cast<Store *>(timer->data) }; + pair->first->startHTTPRequest(std::move(pair->second)); + pair->first->backoff_timer = nullptr; + uv_timer_stop(timer); + uv_close((uv_handle_t *)timer, [](uv_handle_t *handle) { delete (uv_timer_t *)handle; }); + }, timeout, 0); +} + void HTTPRequest::removeHTTPBaton() { assert(uv_thread_self() == thread_id); if (http_baton) { @@ -156,10 +215,21 @@ void HTTPRequest::removeCacheBaton() { } } +void HTTPRequest::removeBackoffTimer() { + assert(uv_thread_self() == thread_id); + if (backoff_timer) { + delete static_cast<std::pair<HTTPRequest *, std::unique_ptr<Response>> *>(backoff_timer->data); + uv_timer_stop(backoff_timer); + uv_close((uv_handle_t *)backoff_timer, [](uv_handle_t *handle) { delete (uv_timer_t *)handle; }); + backoff_timer = nullptr; + } +} + void HTTPRequest::cancel() { assert(uv_thread_self() == thread_id); removeCacheBaton(); removeHTTPBaton(); + removeBackoffTimer(); notify(); } |