Created
April 28, 2017 16:16
-
-
Save vvvvalvalval/2fc2067cb96270396154dca34a85c083 to your computer and use it in GitHub Desktop.
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
(defn exponential-backoff | |
"Implements exponential backoff. | |
* af is a function which accepts 3 channels (af =success= =error= =retry=), and should do exactly one of the following operations without blocking: | |
- put a successful value in =success= | |
- put an error in =error= (will break the loop) | |
- put an error which causes a retry in =retry=. | |
* the exponential backoff loop can be configured with :get-delay-ms, a function which returns a (potentially infinite) seq of backoff intervals, | |
and :imprecision-ms, a maximim number of milliseconds with which to randomly blurr the backoff intervals. | |
Returns a channel which will receive either the completed result or an error." | |
[{:as opts | |
:keys [get-delays-ms imprecision-ms] | |
:or {get-delays-ms (constantly [1000 2000 4000 8000 16000]) | |
imprecision-ms 1000}} | |
af] | |
(let [=success= (a/chan 1) | |
=retry= (a/chan 1) | |
=error= (a/chan 1)] | |
(go-safe | |
(loop [delays (get-delays-ms)] | |
(try | |
(af =success= =retry= =error=) | |
(catch Throwable err | |
(throw (ex-info "Error in bs.utils.misc/exponential-backoff body. Means that `af` was badly implemented, as it should never throw." | |
{} err)))) | |
(a/alt! | |
=success= ([v] v) | |
=error= ([err] (throw err)) | |
=retry= ([err] (if-let [delay-ms (first delays)] | |
(do | |
(a/<! (a/timeout (+ delay-ms (rand-int imprecision-ms)))) | |
(recur (next delays))) | |
(throw (ex-info "Failed exponential backoff" {} err))))) | |
)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment