Skip to content

Instantly share code, notes, and snippets.

@jgrodziski
Last active August 8, 2019 17:25
Show Gist options
  • Save jgrodziski/b0cfd4cd943bc3d000f5bf7eaa39a56f to your computer and use it in GitHub Desktop.
Save jgrodziski/b0cfd4cd943bc3d000f5bf7eaa39a56f to your computer and use it in GitHub Desktop.
(ns promesa-retry
(:require
["util" :refer [format]]
[promesa.core :as p :refer [reject! resolve!] :refer-macros [alet await]]
[promesa.async-cljs :refer-macros [async]]
[cljs.test :as t :include-macros true]))
(defn backoff-duration [retries-count interval]
(+ (* interval retries-count) (rand-int interval)))
(defn- internal-retry
[p f retries-left retries-count interval]
(-> (f)
(p/catch (fn [err]
(js/console.error (format "Catch failure before retrying (%s retried left): %s" retries-left (.-message err)))
(if (= 0 retries-left)
(p/reject! p err)
(let [d (backoff-duration retries-count interval)]
(js/console.log (format "Will wait %s ms before retrying (%s retries left, tried %s times)" d retries-left retries-count))
(-> (p/delay d "Retry msg ")
(p/then (fn [msg]
(internal-retry p f (dec retries-left) (inc retries-count) interval))))))))
(p/catch (fn [err]));this catch is needed to get the promise returned by the the previous catch in case of a retry, we catch the error cause and do nothing with it
(p/then (fn [return]
(p/resolve! p return))))
p)
(defn retry
([f retries-left]
(retry f retries-left 1000))
([f retries-left interval]
(internal-retry (p/promise) f retries-left 1 interval)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Test ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def counter (atom 0))
(defn dummy-function []
(async
(if (< @counter 6)
(do (println "Dummy function failed!")
(swap! counter inc)
(throw (ex-info "it failed !" {:counter @counter})))
(println "yo it works!"))))
(t/deftest retry-test-success-in-the-end
(reset! counter 0)
(t/async done
(-> (retry dummy-function 15 10)
(p/catch (fn [err]
(t/is err)
(done)))
(p/then (fn []
(js/console.log (format "Done retrying, success in the end"))
(done))))))
(t/deftest retry-test-failure-in-the-end
(reset! counter 0)
(t/async done
(-> (retry dummy-function 3 10)
(p/catch (fn [err]
(js/console.log "Done retrying, error in the end")
(t/is err)
(done)))
(p/then (fn []
(js/console.log "Done retrying successfully")
(done)))
)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment