diff options
author | Eelco Dolstra <edolstra@gmail.com> | 2019-06-24T19·48+0200 |
---|---|---|
committer | Eelco Dolstra <edolstra@gmail.com> | 2019-06-24T19·59+0200 |
commit | 78fa47a7f08a4cb6ee7061bf0bd86a40e1d6dc91 (patch) | |
tree | 96a4b4079640ca3435a929fa163bb07e921c3ecb /src/libutil/retry.hh | |
parent | 2fef4dd29673ef383b695480c9b8212f2e8d4711 (diff) |
Fix 'error 9 while decompressing xz file'
Once we've started writing data to a Sink, we can't restart a download request, because then we end up writing duplicate data to the Sink. Therefore we shouldn't handle retries in Downloader but at a higher level (in particular, in copyStorePath()). Fixes #2952. (cherry picked from commit a67cf5a3585c41dd9f219a2c7aa9cf67fa69520b)
Diffstat (limited to 'src/libutil/retry.hh')
-rw-r--r-- | src/libutil/retry.hh | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/src/libutil/retry.hh b/src/libutil/retry.hh new file mode 100644 index 000000000000..b45cb37f736b --- /dev/null +++ b/src/libutil/retry.hh @@ -0,0 +1,38 @@ +#pragma once + +#include "logging.hh" + +#include <functional> +#include <cmath> +#include <random> +#include <thread> + +namespace nix { + +inline unsigned int retrySleepTime(unsigned int attempt) +{ + std::random_device rd; + std::mt19937 mt19937; + return 250.0 * std::pow(2.0f, + attempt - 1 + std::uniform_real_distribution<>(0.0, 0.5)(mt19937)); +} + +template<typename C> +C retry(unsigned int attempts, std::function<C()> && f) +{ + unsigned int attempt = 0; + while (true) { + try { + return f(); + } catch (BaseError & e) { + ++attempt; + if (attempt >= attempts || !e.isTransient()) + throw; + auto ms = retrySleepTime(attempt); + warn("%s; retrying in %d ms", e.what(), ms); + std::this_thread::sleep_for(std::chrono::milliseconds(ms)); + } + } +} + +} |