Last active
May 1, 2019 21:41
-
-
Save ghadishayban/98b975e5378518b101924cb98a0e9071 to your computer and use it in GitHub Desktop.
retry with completablefuture
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns retry | |
(:import [java.util.function Supplier] | |
[java.util.concurrent CompletableFuture TimeUnit])) | |
(defn with-retry | |
"given an op wanting retries, and a strategy for backoff, | |
returns a CompletableFuture that can be waited on | |
op takes no args | |
A backoff strategy is a function of an exception, returning nil or a number of milliseconds to backoff" | |
[op strategy] | |
(let [cf (CompletableFuture.)] | |
(CompletableFuture/supplyAsync | |
(reify Supplier | |
(get [this] | |
(try (.complete cf (op)) | |
(catch Exception e | |
(if-let [b (strategy e)] | |
(CompletableFuture/supplyAsync this (CompletableFuture/delayedExecutor b TimeUnit/MILLISECONDS)) | |
(.completeExceptionally cf e))))))) | |
cf)) | |
(defn exponential | |
"returns a strategy function | |
the strategy employed is exponential backoff, with a max limit | |
pred: a predicate of the exception, determining applicability | |
initial and max: bounds for the backoff in millis | |
factor: the exponential factor | |
num-retries: max number of retries" | |
[pred initial max factor num-retries] | |
(let [b (atom initial) | |
n (atom 0)] | |
(fn [ex] | |
(when (and (< @n num-retries) | |
(pred ex)) | |
(swap! n inc) | |
(first (swap-vals! b (fn [i] (min (* i factor) max)))))))) | |
(comment | |
(def f (with-retry | |
(fn API [] | |
(println "trying") | |
(throw (Exception. "oh no"))) | |
(exponential (constantly true) 400 2000 2 3)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment