The concept of a
message exchange is borrowed from the world of
messaging and enterprise integration. The
exchange acts like a
kind of mailbox, accepting inputs from
producers and forwarding
these messages to one or more
consumers, depending on the
implementation's semantics.
This module provides some basic types of message exchange and exposes
an API for defining your own custom
exchange types.
The broadcast exchange type, started via
broadcastExchange,
forward their inputs to all registered consumers (as the name
suggests). This exchange type is highly optimised for local
(intra-node) traffic and provides two different kinds of client
binding, one which causes messages to be delivered directly to the
client's mailbox (viz
bindToBroadcaster), the other providing a
separate stream of messages that can be obtained using the
expect and
receiveX family of messaging primitives
(and thus composed with other forms of input selection, such as typed
channels and selective reads on the process mailbox).
Important: When a
ProcessId is registered via
bindToBroadcaster, only the payload of the
Message
(i.e., the underlying
Serializable datum) is forwarded to the
consumer,
not the whole
Message itself.
The
router API provides a means to selectively route messages
to one or more clients, depending on the content of the
Message. Two modes of binding (and client selection) are
provided out of the box, one of which matches the message
key,
the second of which matches on a name and value from the
headers. Alternative mechanisms for content based routing can
be derived by modifying the
BindingSelector expression passed
to
router
See
messageKeyRouter and
headerContentRouter for the
built-in routing exchanges, and
router for the extensible
routing API.
Both the
broadcast and
router exchanges are implemented
as custom
exchange types. The mechanism for defining custom
exchange behaviours such as these is very simple. Raw exchanges are
started by evaluating
startExchange with a specific
ExchangeType record. This type is parameterised by the internal
state it holds, and defines two API callbacks in its
configureEx and
routeEx fields. The former is evaluated
whenever a client process evaluates
configureExchange, the
latter whenever a client evaluates
post or
postMessage.
The
configureEx callback takes a raw
Message (from
Control.Distributed.Process) and is responsible for decoding
the message and updating its own state (if required). It is via this
callback that custom exchange types can receive information about
clients and handle it in their own way. The
routeEx callback is
evaluated with the exchange type's own internal state and the
Message originally sent to the exchange process (via
post) and is responsible for delivering the message to its
clients in whatever way makes sense for that exchange type.