trampolining retries for clojure
Pull request Compare This branch is 46 commits behind joegallo:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.

Robert Bruce

Robert Bruce provides an easy way to execute a function and allow failures to be automatically retried. It's named after Robert the Bruce, whose determination was inspired by the sight a spider trying (and failing) many times to build a web.

Add this to your project.clj :dependencies list:

[robert/bruce "0.7.1"]


(use '[robert.bruce :only [try-try-again]])

;; arguments are like trampoline, if you want the default options
(try-try-again some-fn)
(try-try-again some-fn arg1 arg2)
(try-try-again #(some-fn arg1 arg2))

;; but with the addition of a first options arg, if you don't
(try-try-again {:sleep 5000 :tries 100} #(some-fn arg1 arg2))
(try-try-again {:sleep nil :tries 100} #(some-fn arg1 arg2))
(try-try-again {:decay :exponential :tries 100} #(some-fn arg1 arg2))

(try-try-again {;; all options are optional

                ;; :sleep is used to specify how long to sleep
                ;; between retries, it can be a number, or false
                ;; or nil if you don't want to sleep, 
                ;; default is 10 seconds (that is, 10000)
                :sleep 100

                ;; :tries is used to specific how many tries
                ;; will be attempted, it can also be :unlimited
                ;; default is 5
                :tries 100
                ;; if you want your sleep amount to change over
                ;; time, you can provide a decay function:
                ;; a number - your sleep will be multiplied by it
                ;; a function - your sleep will passed into it
                ;; a keyword - for out of the box decay algorithms
                ;;             :exponential, :double, :golden-ratio
                ;; default is identity
                :decay :exponential

                ;; if you want to only retry when particular
                ;; exceptions are thrown, you can add a :catch
                ;; clause.  it works with either a single type
                ;; or a collection.  
                ;; default is Exception
                :catch [ java.sql.SQLException]
                ;; if you would like a function to be called on
                ;; each failure (for instance, logging each failed
                ;; attempt), you can specify an error-hook.
                ;; The error that occurred is passed into the
                ;; error-hook function as an argument.
                ;; The error-hook method can also force a
                ;; short-circuit failure by returning false, or
                ;; force an additional retry by returning true.
                :error-hook (fn [e] (println "I got an error:" e))}
               #(some-fn arg1 arg2))

;; In addition, four dynamic variables are bound in both the
;; passed in and error-hook functions:
;; *first-try* - true if this is the first try
;; *last-try* - true if this is the last try
;; *try* - the current try number (starting at 1)
;; *error* - the last error that occurred

;; you can also use metadata on the function itself
(try-try-again ^{:decay :exponential :tries 100} #(some-fn arg1 arg2))


Copyright (C) 2011 Joe Gallo

Distributed under the Eclipse Public License, the same as Clojure.