about summary refs log tree commit diff
path: root/src/libutil
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil')
-rw-r--r--src/libutil/retry.hh38
-rw-r--r--src/libutil/types.hh2
2 files changed, 40 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));
+        }
+    }
+}
+
+}
diff --git a/src/libutil/types.hh b/src/libutil/types.hh
index 92bf469b5c6f..88e3243f47a5 100644
--- a/src/libutil/types.hh
+++ b/src/libutil/types.hh
@@ -109,6 +109,8 @@ public:
     const string & msg() const { return err; }
     const string & prefix() const { return prefix_; }
     BaseError & addPrefix(const FormatOrString & fs);
+
+    virtual bool isTransient() { return false; }
 };
 
 #define MakeError(newClass, superClass) \