In ordinary Clojure code, the binding macro can be used to override the thread-bound values of
dynamic Vars; this is not possible with interceptors, as the interceptor function will return before
the next interceptor is executed.
 
Instead, an interceptor that needs to override or communicate a value via a dynamic binding will instead
modify the :bindings key of the context.
 
Any bindings associated this way will stay present until they are dissoc-ed from the :bindings map; a binding
added by one interceptor during the :enter phase will still be present during the :leave phase.
 
It is not uncommon for an interceptor to provide an :enter function to bind a var, and a
corresponding :leave function to remove the binding:
 
(def ^:dynamic *request-id* nil)
(def request-id-interceptor
  {:name ::mdc
   :enter (fn [context]
            (update context :bindings assoc #'*request-id* (str (random-uuid)))
   :leave (fn [context]
            (update context :bindings dissoc #'*request-id*))})