Reusable primitives for implementing the cicruit-breaker pattern in Clojure, plus two concrete implementations (cb-fn
/cb-agent
).
The Circuit-breaker pattern lets you protect against some process that is likely to fail, and provides wait-for-recovery semantics for when that happens (assuming recovery is indeed possible). Anything that goes out-of-process (recoverable remote service/drive) is a good candidate for wrapping with a circuit-breaker. For things that are in-process it may be an overkill, but ultimately, that will depend on the actual use-case.
FIXME
Three things are needed in order to implement a circuit-breaker:
Looking at the circuit-breaker-fn.primitives
namespace, we can see there are exactly three Vars:
cb-init
(static map)cb-error-handler
(is the right error-handler after partially binding all but the last arg)cb-wrap-handler
(returns the right processing-handler)The above are needed for building a complete circuit-breaker component.
Using the primitives described in the previous section, we can start building more meaningful constructs.
Obviously, the most general/reusable construct we can apply circuit-breaking semantics to, is the function itself:
Returns a function that wraps <f> with circuit-breaker semantics.
fail-limit
: How many Exceptions (within ) before transitioning from CLOSED => OPEN.fail-window
: Time window (in fail-window-unit
) in which fail-limit
has an effect.fail-window-unit
: One of #{:micros :millis :seconds :minutes :hours :days}
.open-timeout
: How long (in timeout-unit
) to wait before transitioning from OPEN => HALF-OPEN.timeout-unit
: Same as `fail-window-unit.success-limit
: How many successful calls before transitioning from HALF-OPEN => CLOSED.success-block
: Function (or positive integer) expected to produce an artificial delay (via Thread/sleep
) after each successful call to f
. If provided MUST be accounted for in fail-window
!drop-fn
: Function to handle all requests while in OPEN state (arg-list per ). If a default value makes sense in your domain this is your chance to use it.ex-fn
: Function of 3 args to be called last when handling errors. Takes the Exception itself (do NOT rethrow it!), the time it occurred (per System/nanoTime
) & the current fail count.locking?
: Boolean indicating whether the handler that wraps f
should run after acquiring a lock (will wait for it).try-locking?
: Boolean indicating whether the handler that wraps f
should run after trying to acquire a lock (will NOT run if it fails to acquire one).Returns a vector with two elements:
Same options as per cb-fn
, apart from the last two (locking?
/try-locking?
), simply because these don't make sense in the context of an agent (which queues actions).
All options are spec-ed and validated (see validation.clj
). If validation fails, an ex-info
carrying the result of s/explain-data
is thrown.
As a result of using clojure.spec
for validation, the minimum Clojure version that will work is 1.9.0
.
Copyright © 2019 Dimitrios Piliouras
This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0.
This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version, with the GNU Classpath Exception which is available at https://www.gnu.org/software/classpath/license.html.
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close