(additive-strategy increment)(additive-strategy initial-delay increment)Returns a retry strategy where, after the initial-delay (ms), the delay
increases by increment (ms) after each retry. The single argument version
uses the given increment as both the initial delay and the increment.
Returns a retry strategy where, after the `initial-delay` (ms), the delay increases by `increment` (ms) after each retry. The single argument version uses the given increment as both the initial delay and the increment.
Decides when a closed circuit breaker should trip open, from observed call outcomes. Implementations are immutable values; the breaker stores the current policy in its state and swaps in the next one after each recorded outcome. The state machine itself (open/half-open/closed) lives in the breaker runtime, not here. This is the extension seam for alternative trip policies (e.g. a rolling window) — implement the three methods over your own immutable value.
Decides when a closed circuit breaker should trip open, from observed call outcomes. Implementations are immutable values; the breaker stores the current policy in its state and swaps in the next one after each recorded outcome. The state machine itself (open/half-open/closed) lives in the breaker runtime, not here. This is the extension seam for alternative trip policies (e.g. a rolling window) — implement the three methods over your own immutable value.
(observe policy outcome now)Return an updated policy incorporating a call outcome (:success or
:failure) observed at now (epoch ms).
Return an updated policy incorporating a call `outcome` (`:success` or `:failure`) observed at `now` (epoch ms).
(reset policy)Return the policy with its accumulated outcome state cleared but its configuration preserved. Called when the breaker (re)closes.
Return the policy with its accumulated outcome state cleared but its configuration preserved. Called when the breaker (re)closes.
(tripped? policy now)True if the breaker should open, given the outcomes observed so far.
True if the breaker should open, given the outcomes observed so far.
(circuit-breaker policy)(circuit-breaker policy options)Returns a stateful circuit breaker driven by policy (a BreakerPolicy).
The breaker is shared across callers and threads; construct it once.
options keys (all namespaced under again.core):
::reset-timeout ms to stay open before admitting a half-open probe
(default 60000)
::on-event fn called with an event map after each notable event
(see with-circuit-breaker); defaults to a no-op
::user-context opaque value included in every ::on-event map
Returns a stateful circuit breaker driven by `policy` (a `BreakerPolicy`).
The breaker is shared across callers and threads; construct it once.
`options` keys (all namespaced under `again.core`):
`::reset-timeout` ms to stay open before admitting a half-open probe
(default 60000)
`::on-event` fn called with an event map after each notable event
(see `with-circuit-breaker`); defaults to a no-op
`::user-context` opaque value included in every `::on-event` map(circuit-open? e)True if e is the exception thrown when a call is short-circuited by an open
circuit breaker (see with-circuit-breaker).
True if `e` is the exception thrown when a call is short-circuited by an open circuit breaker (see `with-circuit-breaker`).
(circuit-state breaker)Returns the current state of breaker: :closed, :open, or :half-open.
Returns the current state of `breaker`: `:closed`, `:open`, or `:half-open`.
(clamp-delay delay retry-strategy)Replace delays in the strategy that are larger than delay with
delay.
Replace delays in the strategy that are larger than `delay` with `delay`.
(consecutive-failures threshold)Returns a BreakerPolicy that trips after threshold consecutive failures.
A single success resets the count.
Returns a `BreakerPolicy` that trips after `threshold` consecutive failures. A single success resets the count.
(constant-strategy delay)Generates a retry strategy with a constant delay (ms) between attempts, ie the delay is the same for each retry.
Generates a retry strategy with a constant delay (ms) between attempts, ie the delay is the same for each retry.
Default ms a breaker stays open before admitting a half-open probe.
Default ms a breaker stays open before admitting a half-open probe.
(immediate-strategy)Returns a retry strategy that retries without any delay.
Returns a retry strategy that retries without any delay.
(max-delay delay retry-strategy)Stop retrying once the a delay is larger than delay.
Stop retrying once the a delay is larger than `delay`.
(max-duration timeout retry-strategy)Stop retrying once the sum of past delays exceeds timeout (ms). Note: the sum
considers only the delays in the strategy, any time spent on executing the
operation etc is not included (that is, we're not measuring wallclock time
here).
Stop retrying once the sum of past delays exceeds `timeout` (ms). Note: the sum considers only the delays in the strategy, any time spent on executing the operation etc is not included (that is, we're not measuring wallclock time here).
(max-retries n retry-strategy)Stop retrying after n retries.
Stop retrying after `n` retries.
(max-wall-clock-duration timeout retry-strategy)Stop retrying once wall-clock time since the first attempt exceeds
timeout (ms). Unlike max-duration, this includes actual execution time,
not just accumulated delays.
Returns an options map for use with with-retries. Because it returns a map rather than a seq, it must be the outermost manipulator — other manipulators (max-retries, clamp-delay, etc.) should be applied to the strategy before passing it here.
The returned map can be merged with other with-retries options such as ::callback and ::user-context, or ::wall-clock-timeout can be set directly in the options map passed to with-retries instead of using this function.
Stop retrying once wall-clock time since the first attempt exceeds `timeout` (ms). Unlike max-duration, this includes actual execution time, not just accumulated delays. Returns an options map for use with with-retries. Because it returns a map rather than a seq, it must be the outermost manipulator — other manipulators (max-retries, clamp-delay, etc.) should be applied to the strategy before passing it here. The returned map can be merged with other with-retries options such as ::callback and ::user-context, or ::wall-clock-timeout can be set directly in the options map passed to with-retries instead of using this function.
(multiplicative-strategy initial-delay delay-multiplier)Returns a retry strategy with exponentially increasing delays, ie each previous
delay is multiplied by delay-multiplier to generate the next delay.
Returns a retry strategy with exponentially increasing delays, ie each previous delay is multiplied by `delay-multiplier` to generate the next delay.
(randomize-strategy rand-factor retry-strategy)Returns a retry strategy where all the delays have been scaled by a random
number between [1 - rand-factor, 1 + rand-factor]. rand-factor must be
greater than 0 and less than 1.
Returns a retry strategy where all the delays have been scaled by a random number between [1 - `rand-factor`, 1 + `rand-factor`]. `rand-factor` must be greater than 0 and less than 1.
(with-circuit-breaker breaker & body)Run body through breaker. While the breaker is closed (or admitting a
half-open probe) the body executes and its success or failure is recorded
against the breaker. While the breaker is open the body is NOT executed; a
circuit-open exception (recognised by circuit-open?) is thrown instead. Once
the breaker has been open for ::reset-timeout ms it admits a single half-open
probe: a successful probe closes the breaker, a failed one re-opens it.
Any thrown Exception counts as a failure: it is recorded against the breaker
and then rethrown — except InterruptedException, which is rethrown with the
interrupt flag restored and is NOT recorded (a caller interrupt is not a
dependency-health signal).
The breaker's ::on-event callback (see circuit-breaker) is invoked with a
map after each notable event: {::event <type> ::user-context <ctx>}, where
<type> is :success, :failure, :short-circuit, or :state-change. A
:state-change event also carries ::from and ::to states; a :failure
event also carries the ::exception; ::user-context is present only if one
was configured.
Compose with with-retries by nesting, breaker innermost, so the breaker sees
every attempt:
(with-retries strategy
(with-circuit-breaker breaker
(do-call)))
Run `body` through `breaker`. While the breaker is closed (or admitting a
half-open probe) the body executes and its success or failure is recorded
against the breaker. While the breaker is open the body is NOT executed; a
circuit-open exception (recognised by `circuit-open?`) is thrown instead. Once
the breaker has been open for `::reset-timeout` ms it admits a single half-open
probe: a successful probe closes the breaker, a failed one re-opens it.
Any thrown `Exception` counts as a failure: it is recorded against the breaker
and then rethrown — except `InterruptedException`, which is rethrown with the
interrupt flag restored and is NOT recorded (a caller interrupt is not a
dependency-health signal).
The breaker's `::on-event` callback (see `circuit-breaker`) is invoked with a
map after each notable event: `{::event <type> ::user-context <ctx>}`, where
`<type>` is `:success`, `:failure`, `:short-circuit`, or `:state-change`. A
`:state-change` event also carries `::from` and `::to` states; a `:failure`
event also carries the `::exception`; `::user-context` is present only if one
was configured.
Compose with `with-retries` by nesting, breaker innermost, so the breaker sees
every attempt:
(with-retries strategy
(with-circuit-breaker breaker
(do-call)))(with-circuit-breaker* breaker f)Functional core of with-circuit-breaker: runs f through breaker.
Functional core of `with-circuit-breaker`: runs `f` through `breaker`.
(with-retries strategy-or-options & body)Try executing body. If body throws an Exception, retry according to the
retry strategy.
A retry strategy is a seq of delays: with-retries will sleep the duration
of the delay (in ms) before each retry. The total number of attempts is the
number of elements in the strategy plus one. A simple retry stategy would
be: [100 100 100 100] which results in the operation being retried four times,
for a total of five attempts, with 100ms sleeps in between attempts. Note:
infinite strategies are supported, but maybe not encouraged…
Strategies can be built with the provided builder fns, eg additive-strategy,
and modified with the provided manipulator fns, eg clamp-delay, but you can
also create any custom seq of delays that suits your use case.
Instead of a simple delay sequence, you can also pass in the following type of
options map as the first argument to with-retries:
{:again.core/callback <fn> :again.core/strategy <delay strategy> :again.core/user-context <anything, but probably an atom> :again.core/wall-clock-timeout <ms>}
:again.core/callback is a callback function that is called after each
attempt.
:again.core/strategy is the sequence of delays (ie retry strategy).
:again.core/user-context is an opaque value that is passed to the callback
function as an argument.
:again.core/wall-clock-timeout stops retrying once wall-clock elapsed time
since the first attempt exceeds this value (ms). Unlike the delay-summing
max-duration manipulator, this accounts for actual execution time. Setting
this key directly is equivalent to using max-wall-clock-duration.
The callback function is called with the following type of map as its only argument:
{:again.core/attempts <the number of attempts thus far> :again.core/exception <the exception thrown by body> :again.core/slept <the sum of all delays thus far> :again.core/status <the result of the last attempt: :success, :retry, :failure, or :interrupted :again.core/user-context <the user context from the options map>}
The callback function can return :again.core/fail to instruct with-retries
to ignore the rest of the retry strategy and rethrow the previous
exception (ie return early).
Try executing `body`. If `body` throws an `Exception`, retry according to the
retry `strategy`.
A retry `strategy` is a seq of delays: `with-retries` will sleep the duration
of the delay (in ms) before each retry. The total number of attempts is the
number of elements in the `strategy` plus one. A simple retry stategy would
be: [100 100 100 100] which results in the operation being retried four times,
for a total of five attempts, with 100ms sleeps in between attempts. Note:
infinite strategies are supported, but maybe not encouraged…
Strategies can be built with the provided builder fns, eg `additive-strategy`,
and modified with the provided manipulator fns, eg `clamp-delay`, but you can
also create any custom seq of delays that suits your use case.
Instead of a simple delay sequence, you can also pass in the following type of
options map as the first argument to `with-retries`:
{:again.core/callback <fn>
:again.core/strategy <delay strategy>
:again.core/user-context <anything, but probably an atom>
:again.core/wall-clock-timeout <ms>}
`:again.core/callback` is a callback function that is called after each
attempt.
`:again.core/strategy` is the sequence of delays (ie retry strategy).
`:again.core/user-context` is an opaque value that is passed to the callback
function as an argument.
`:again.core/wall-clock-timeout` stops retrying once wall-clock elapsed time
since the first attempt exceeds this value (ms). Unlike the delay-summing
`max-duration` manipulator, this accounts for actual execution time. Setting
this key directly is equivalent to using `max-wall-clock-duration`.
The callback function is called with the following type of map as its only
argument:
{:again.core/attempts <the number of attempts thus far>
:again.core/exception <the exception thrown by body>
:again.core/slept <the sum of all delays thus far>
:again.core/status <the result of the last attempt: :success, :retry, :failure, or :interrupted
:again.core/user-context <the user context from the options map>}
The callback function can return `:again.core/fail` to instruct `with-retries`
to ignore the rest of the retry strategy and rethrow the previous
exception (ie return early).cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |