Support for in-memory, thread-blocking retrying. | (ns metabase.util.retry (:require [metabase.config :as config] [metabase.models.setting :refer [defsetting]] [metabase.util.i18n :refer [deferred-tru]]) (:import (io.github.resilience4j.core IntervalFunction) (io.github.resilience4j.retry Retry RetryConfig) (java.util.function Predicate))) |
(set! *warn-on-reflection* true) | |
(defsetting retry-max-attempts
(deferred-tru "The maximum number of attempts for an event.")
:type :integer
:default (if config/is-dev?
1
7)) | |
(defsetting retry-initial-interval (deferred-tru "The initial retry delay in milliseconds.") :type :integer :default 500) | |
(defsetting retry-multiplier (deferred-tru "The delay multiplier between attempts.") :type :double :default 2.0) | |
(defsetting retry-randomization-factor (deferred-tru "The randomization factor of the retry delay.") :type :double :default 0.1) | |
(defsetting retry-max-interval-millis (deferred-tru "The maximum delay between attempts.") :type :integer :default 30000) | |
Returns a map with the default retry configuration. | (defn retry-configuration
[]
{:max-attempts (retry-max-attempts)
:initial-interval-millis (retry-initial-interval)
:multiplier (retry-multiplier)
:randomization-factor (retry-randomization-factor)
:max-interval-millis (retry-max-interval-millis)}) |
(defn- make-predicate [f] (reify Predicate (test [_ x] (f x)))) | |
Returns a randomized exponential backoff retry named | (defn random-exponential-backoff-retry
^Retry [^String retry-name
{:keys [^long max-attempts ^long initial-interval-millis
^double multiplier ^double randomization-factor
^long max-interval-millis
retry-on-result-pred retry-on-exception-pred]}]
(let [interval-fn (IntervalFunction/ofExponentialRandomBackoff
initial-interval-millis multiplier
randomization-factor max-interval-millis)
base-config (-> (RetryConfig/custom)
(.maxAttempts max-attempts)
(.intervalFunction interval-fn))
retry-config (cond-> base-config
retry-on-result-pred
(.retryOnResult (make-predicate retry-on-result-pred))
retry-on-exception-pred
(.retryOnException (make-predicate retry-on-exception-pred)))]
(Retry/of retry-name (.build retry-config)))) |
Returns a function accepting the same arguments as | (defn decorate
([f]
(decorate f (random-exponential-backoff-retry (str (random-uuid)) (retry-configuration))))
([f ^Retry retry]
(fn [& args]
(let [callable (reify Callable (call [_]
(apply f args)))]
(.call (Retry/decorateCallable retry callable)))))) |
Make a retrying function from (let [retrier (retry/make retry-config)] (retrier f)) | (defn make
[retry-config]
(fn [f]
((decorate f (random-exponential-backoff-retry (str (random-uuid)) retry-config))))) |