aboutsummaryrefslogtreecommitdiff
path: root/src/libutil/retry.hh
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2019-06-24 21:48:52 +0200
committerEelco Dolstra <edolstra@gmail.com>2019-06-24 21:59:51 +0200
commit78fa47a7f08a4cb6ee7061bf0bd86a40e1d6dc91 (patch)
tree96a4b4079640ca3435a929fa163bb07e921c3ecb /src/libutil/retry.hh
parent2fef4dd29673ef383b695480c9b8212f2e8d4711 (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.hh38
1 files changed, 38 insertions, 0 deletions
diff --git a/src/libutil/retry.hh b/src/libutil/retry.hh
new file mode 100644
index 000000000..b45cb37f7
--- /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));
+ }
+ }
+}
+
+}