io.pedestal.interceptor.chain

Interceptor pattern. Executes a chain of Interceptor functions on a common “context” map, maintaining a virtual “stack”, with error handling and support for asynchronous execution.

add-observer

added in 0.7.0

(add-observer context observer-fn)

Adds an observer function to the execution; observer functions are notified after each interceptor executes. If the interceptor is asynchronous, the notification occurs once the new context is conveyed through the returned channel.

The function is passed an event map:

Key Type Description
:execution-id integer Unique per-process id for the execution
:stage :enter, :leave, or :error
:interceptor-name keyword or string The interceptor that was invoked (either its :name or a string)
:context-in map The context passed to the interceptor
:context-out map The context returned from the interceptor

The observer is only invoked for interceptor executions; when an interceptor does not provide a callback for a stage, the interceptor is not invoked, and so the observer is not invoked.

The value returned by the observer is ignored.

If an observer throws an exception, it is associated with the interceptor, exactly as if the interceptor had thrown the exception.

When multiple observer functions are added, they are invoked in an unspecified order.

The debug-observer function is used to create an observer function; this observer can be used to log each interceptor that executes, in what phase it executes, and how it modifies the context map..

bind

macro

added in 0.7.0

(bind context var value)

Updates the context to add a binding of the given var and value. This is a convenience on modifying the :bindings key (a map of Vars and values).

Bound values will be available in subsequent interceptors.

enqueue

(enqueue context interceptors)

Adds interceptors to the end of context’s execution queue. Creates the queue if necessary. Returns updated context.

enqueue*

(enqueue* context & interceptors-and-seq)

Like enqueue but accepting a variable number of arguments. If the last argument is itself a sequence of interceptors, they’re unpacked and added to the context’s execution queue.

execute

(execute context)(execute context interceptors)

Executes a queue of Interceptors attached to the context. Context must be a map, Interceptors are added with ‘enqueue’.

An Interceptor is record with the keys :enter, :leave, and :error. The value of each key is a function; missing keys or nil values are ignored. When executing a context, first all the :enter functions are invoked in order. As this happens, the Interceptors are pushed on to a stack. Interceptor may also have a :name, which is used when logging.

When execution reaches the end of the queue, it begins popping Interceptors off the stack and calling their :leave functions. Therefore :leave functions are called in the opposite order from :enter functions.

Both the :enter and :leave functions are passed a single argument, the context map, and return an updated context.

If any Interceptor function throws an exception, execution stops and begins popping Interceptors off the stack and calling their :error functions. The :error function takes two arguments: the context and an exception. It may either handle the exception, in which case the execution continues with the next :leave function on the stack; or re-throw the exception, passing control to the :error function on the stack. If the exception reaches the end of the stack without being handled, execute will throw it

Functions may return a core.async channel; this represents an asynchronous process. When this happens, the initial call to execute returns nil immediately, with the process exepected to write an updated context into the channel when its work completes.

The function on-enter-async is used to provide a callback for when an interceptor chain execution first switches from in-thread to asynchronous execution.

Processing continues in core.async threads - including even when a later interceptor returns an immediate context, rather than a channel.

execute-only

deprecated in 0.7.0

(execute-only context interceptor-key)(execute-only context interceptor-key interceptors)

Like execute, but only processes the interceptors in a single direction, using interceptor-key (i.e. :enter, :leave) to determine which functions to call.

Executes a queue of Interceptors attached to the context. Context must be a map, Interceptors are added with ‘enqueue’.

An Interceptor Record has keys :enter, :leave, and :error. The value of each key is a function; missing keys or nil values are ignored. When executing a context, all the interceptor-key functions are invoked in order. As this happens, the Interceptors are pushed on to a stack.

on-enter-async

added in 0.7.0

(on-enter-async context f)

Adds a callback function to be executed if the execution goes async, which occurs when an interceptor returns a channel rather than a context map.

The supplied function is appended to the list of such functions. All the functions are invoked, but only invoked once (a subsequent interceptor also returning a channel does not have this side effect.

The callback function will be passed the context, but any returned value from the function is ignored.

queue

added in 0.7.0

(queue context)

Returns the contents of the queue, the as-yet uninvoked interceptors during the :enter phase of chain execution.

Prior to 0.7.0, this was achieved by accessing the :io.pedestal.interceptor.chain/queue key; future enhancements may change how the interceptor queue and stack are stored.

terminate

(terminate context)

Removes all remaining interceptors from context’s execution queue. This effectively short-circuits execution of Interceptors’ :enter functions and begins executing the :leave functions.

terminate-when

(terminate-when context pred)

Adds a predicate establishing a terminating condition for execution of the interceptor chain.

pred is a function that takes a context as its argument. It will be invoked after every Interceptor’s :enter function. If pred returns logical true, execution will stop at that Interceptor.

unbind

macro

added in 0.7.0

(unbind context var)

Updates the context to remove a previous binding.