mirror of
https://github.com/taoensso/telemere.git
synced 2025-12-29 22:48:24 +00:00
[mod] Simplify middleware - don't auto compose
Previously:
It was possible to provide a vector of middleware fns when creating
signals or adding handlers, e.g.:
(event! ::ev-id1 {:middleware [fn1 fn2 ...]}),
(add-handler! ::handler-id1 <handler-fn> {:middleware [fn1 fn2 ...]})
After this commit:
Middleware is always expected to be a single fn, or nil.
A `comp-middleware` util has been added to make it easy to compose multiple
middleware fns into one.
Motivation:
The previous (auto-composition) behaviour was nice when adding handlers,
but incurred a (small but non-trivial) runtime cost when creating signals.
The actual benefit (convenience) of auto-composition is very small, so
I've decided to just remove this feature and add the `comp-middleware` util.
Note that I ruled out the option of doing auto-comp only when adding handlers
since that've meant an inconsistency and so complexity for little benefit.
This commit is contained in:
parent
63f488082b
commit
839143167b
4 changed files with 23 additions and 23 deletions
|
|
@ -22,7 +22,7 @@ Signal options (shared by all signal creators):
|
|||
`:sample-rate` - ?rate ∈ℝ[0,1] for signal sampling (0.75 => allow 75% of signals, nil => allow all)
|
||||
`:when` -------- Arb ?form; when present, form must return truthy to allow signal
|
||||
`:rate-limit` -- ?spec as given to `taoensso.telemere/rate-limiter`, see its docstring for details
|
||||
`:middleware` -- ?[(fn [signal])=>modified-signal ...] signal middleware
|
||||
`:middleware` -- Optional (fn [signal]) => ?modified-signal to apply when signal is created
|
||||
`:trace?` ------ Should tracing be enabled for `:run` form?
|
||||
|
||||
<kvs> ---------- Other arb user-level ?kvs to incl. in signal. Typically NOT included in
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@
|
|||
enc/chance
|
||||
enc/rate-limiter
|
||||
enc/newline
|
||||
enc/comp-middleware
|
||||
|
||||
impl/msg-splice
|
||||
impl/msg-skip
|
||||
|
|
@ -143,14 +144,13 @@
|
|||
|
||||
(comment (with-ctx {:a :A1 :b :B1} (with-ctx+ {:a :A2} *ctx*)))
|
||||
|
||||
;;;; Middleware
|
||||
;;;; Signal middleware
|
||||
|
||||
(enc/defonce ^:dynamic *middleware*
|
||||
"Optional vector of unary middleware fns to apply (sequentially/left-to-right)
|
||||
to each signal before passing it to handlers. If any middleware fn returns nil,
|
||||
aborts immediately without calling handlers.
|
||||
"Optional (fn [signal]) => ?modified-signal to apply (once) when
|
||||
signal is created. When middleware returns nil, skips all handlers.
|
||||
|
||||
Useful for transforming each signal before handling.
|
||||
Compose multiple middleware fns together with `comp-middleware.
|
||||
|
||||
Re/bind dynamic value using `with-middleware`, `binding`.
|
||||
Modify root (base) value using `set-middleware!`."
|
||||
|
|
@ -159,13 +159,13 @@
|
|||
#?(:clj
|
||||
(defmacro set-middleware!
|
||||
"Set `*middleware*` var's root (base) value. See `*middleware*` for details."
|
||||
[root-val] `(enc/set-var-root! *middleware* ~root-val)))
|
||||
[?root-middleware-fn] `(enc/set-var-root! *middleware* ~?root-middleware-fn)))
|
||||
|
||||
#?(:clj
|
||||
(defmacro with-middleware
|
||||
"Evaluates given form with given `*middleware*` value.
|
||||
See `*middleware*` for details."
|
||||
[init-val form] `(binding [*middleware* ~init-val] ~form)))
|
||||
[?middleware-fn form] `(binding [*middleware* ~?middleware-fn] ~form)))
|
||||
|
||||
;;;; Signal creators
|
||||
;; - signal! [ opts] ; => allowed? / run result (value or throw)
|
||||
|
|
|
|||
|
|
@ -632,9 +632,9 @@
|
|||
'~run-form ~'__run-result ~error-form)]
|
||||
|
||||
;; Final unwrapped signal value visible to users/handler-fns, allow to throw
|
||||
(if-let [call-middleware# ~middleware-form]
|
||||
((sigs/get-middleware-fn call-middleware#) ~'__signal) ; Can throw
|
||||
(do ~'__signal)))))]
|
||||
(if-let [sig-middleware# ~middleware-form]
|
||||
(sig-middleware# ~'__signal) ; Apply signal middleware, can throw
|
||||
(do ~'__signal)))))]
|
||||
|
||||
;; Could avoid double `run-form` expansion with a fn wrap (>0 cost)
|
||||
;; (let [run-fn-form (when run-form `(fn [] (~run-form)))]
|
||||
|
|
|
|||
|
|
@ -229,10 +229,10 @@
|
|||
|
||||
(testing "Call middleware"
|
||||
(let [c (enc/counter)
|
||||
[[rv1 _] [sv1]] (with-sigs :raw nil (sig! {:level :info, :run (c), :middleware [#(assoc % :m1 (c)) #(assoc % :m2 (c))]}))
|
||||
[[rv2 _] [sv2]] (with-sigs :raw nil (sig! {:level :info, :run (c), :middleware [#(assoc % :m1 (c)) #(assoc % :m2 (c))], :allow? false}))
|
||||
[[rv3 _] [sv3]] (with-sigs :raw nil (sig! {:level :info, :run (c), :middleware [#(assoc % :m1 (c)) #(assoc % :m2 (c))]}))
|
||||
[[rv4 _] [sv4]] (with-sigs :raw nil (sig! {:level :info, :middleware [(fn [_] "signal-value")]}))]
|
||||
[[rv1 _] [sv1]] (with-sigs :raw nil (sig! {:level :info, :run (c), :middleware (tel/comp-middleware #(assoc % :m1 (c)) #(assoc % :m2 (c)))}))
|
||||
[[rv2 _] [sv2]] (with-sigs :raw nil (sig! {:level :info, :run (c), :middleware (tel/comp-middleware #(assoc % :m1 (c)) #(assoc % :m2 (c))), :allow? false}))
|
||||
[[rv3 _] [sv3]] (with-sigs :raw nil (sig! {:level :info, :run (c), :middleware (tel/comp-middleware #(assoc % :m1 (c)) #(assoc % :m2 (c)))}))
|
||||
[[rv4 _] [sv4]] (with-sigs :raw nil (sig! {:level :info, :middleware (fn [_] "signal-value")}))]
|
||||
|
||||
[(is (= rv1 0)) (is (sm? sv1 {:m1 1 :m2 2}))
|
||||
(is (= rv2 3)) (is (nil? sv2))
|
||||
|
|
@ -260,31 +260,31 @@
|
|||
(let [c (enc/counter)
|
||||
sv-h1_ (atom nil)
|
||||
sv-h2_ (atom nil)
|
||||
wh1 (sigs/wrap-handler :hid1 (fn [sv] (reset! sv-h1_ sv)) nil {:async nil, :middleware [#(assoc % :hm1 (c)) #(assoc % :hm2 (c))]})
|
||||
wh2 (sigs/wrap-handler :hid2 (fn [sv] (reset! sv-h2_ sv)) nil {:async nil, :middleware [#(assoc % :hm1 (c)) #(assoc % :hm2 (c))]})]
|
||||
wh1 (sigs/wrap-handler :hid1 (fn [sv] (reset! sv-h1_ sv)) nil {:async nil, :middleware (tel/comp-middleware #(assoc % :hm1 (c)) #(assoc % :hm2 (c)))})
|
||||
wh2 (sigs/wrap-handler :hid2 (fn [sv] (reset! sv-h2_ sv)) nil {:async nil, :middleware (tel/comp-middleware #(assoc % :hm1 (c)) #(assoc % :hm2 (c)))})]
|
||||
|
||||
;; Note that call middleware output is cached and shared across all handlers
|
||||
(binding [impl/*sig-handlers* [wh1 wh2]]
|
||||
(let [;; 1x run + 4x handler middleware + 2x call middleware = 7x
|
||||
rv1 (sig! {:level :info, :run (c), :middleware [#(assoc % :m1 (c)) #(assoc % :m2 (c))]})
|
||||
rv1 (sig! {:level :info, :run (c), :middleware (tel/comp-middleware #(assoc % :m1 (c)) #(assoc % :m2 (c)))})
|
||||
sv1-h1 @sv-h1_
|
||||
sv1-h2 @sv-h2_
|
||||
c1 @c
|
||||
|
||||
;; 1x run
|
||||
rv2 (sig! {:level :info, :run (c), :middleware [#(assoc % :m1 (c)) #(assoc % :m2 (c))], :allow? false})
|
||||
rv2 (sig! {:level :info, :run (c), :middleware (tel/comp-middleware #(assoc % :m1 (c)) #(assoc % :m2 (c))), :allow? false})
|
||||
sv2-h1 @sv-h1_
|
||||
sv2-h2 @sv-h2_
|
||||
c2 @c ; 8
|
||||
|
||||
;; 1x run + 4x handler middleware + 2x call middleware = 7x
|
||||
rv3 (sig! {:level :info, :run (c), :middleware [#(assoc % :m1 (c)) #(assoc % :m2 (c))]})
|
||||
rv3 (sig! {:level :info, :run (c), :middleware (tel/comp-middleware #(assoc % :m1 (c)) #(assoc % :m2 (c)))})
|
||||
sv3-h1 @sv-h1_
|
||||
sv3-h2 @sv-h2_
|
||||
c3 @c ; 15
|
||||
|
||||
;; 4x handler middleware
|
||||
rv4 (sig! {:level :info, :middleware [(fn [_] {:my-sig-val? true})]})
|
||||
rv4 (sig! {:level :info, :middleware (fn [_] {:my-sig-val? true})})
|
||||
sv4-h1 @sv-h1_
|
||||
sv4-h2 @sv-h2_
|
||||
c4 @c]
|
||||
|
|
@ -321,7 +321,7 @@
|
|||
(tel/with-handler :hid1
|
||||
(fn [sv] (force (:data sv)) (reset! sv_ sv))
|
||||
{:async nil, :error-fn (fn [x] (reset! error_ x)), :rl-error nil,
|
||||
:middleware [(fn [sv] (if *throwing-handler-middleware?* (ex1!) sv))]}
|
||||
:middleware (fn [sv] (if *throwing-handler-middleware?* (ex1!) sv))}
|
||||
|
||||
[(is (->> (sig! {:level :info, :when (ex1!)}) (throws? :ex-info "Ex1")) "`~filterable-expansion/allow` throws at call")
|
||||
(is (->> (sig! {:level :info, :inst (ex1!)}) (throws? :ex-info "Ex1")) "`~inst-form` throws at call")
|
||||
|
|
@ -339,7 +339,7 @@
|
|||
|
||||
(testing "Throwing call middleware"
|
||||
(reset-state!)
|
||||
[(is (true? (sig! {:level :info, :middleware [(fn [_] (ex1!))]})))
|
||||
[(is (true? (sig! {:level :info, :middleware (fn [_] (ex1!))})))
|
||||
(is (= @sv_ :nx))
|
||||
(is (sm? @error_ {:handler-id :hid1, :error pex1?}))])
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue