Quiver contains two components that have switchable underlying implementations, arrows and servers. An arrow usually plays the role of a client, though it can be used in peer-to-peer mode as well. A server is a message broker or router.
Implementations live under impls/
in the source tree, with a name
starting with quiver-arrow-
or quiver-server-
. Any build or
install logic should be placed in the project Makefile
.
The details of new implementations should be provided by adding an
_Impl
instance to python/quiver/common.py.in
.
The quiver-arrow
command is a wrapper that invokes an implementation
executable using standard arguments. quiver-arrow
takes
responsibility for "cooking" its inputs so implementations can focus
on mechanics. By the same token, implementation outputs are
intentionally left raw so quiver
and quiver-arrow
can do the work
of presenting the results.
An arrow implementation terminates when it has run longer than the requested duration or it has sent or received the expected number of messages. Each invocation uses a single connection to a single queue, meaning that a sending and a receiving implementation together constitute a pair of communicating endpoints.
The implementations take named arguments, with key and value separated
by =
. They must process the following arguments:
connection-mode string 'client' or 'server'
channel-mode string 'active' or 'passive'
operation string 'send' or 'receive'
id string A unique identifier for the application
host string The socket name
port string The socket port (or '-')
path string A named source or target for a message, often a queue
duration integer Run time in seconds; 0 means no limit
count integer Number of messages to transfer; 0 means no limit
rate integer Target message rate; 0 to disable
body-size integer Length of generated message body
credit-window integer Size of credit window to maintain
transaction-size integer Size of transaction batches; 0 means no transactions
durable integer 1 if messages are durable; 0 if non-durable
set-message-id integer 1 if messages have message IDs; 0 if not
If an implementation does not support a particular option, for
instance connection mode server
, it should raise an error at start
time.
Each unit of credit-window
represents one message (not one byte).
The following arguments are optional:
scheme string protocol scheme
username string username used to connect to the peer
password string password used to connect to the peer
cert string certificate file that identifies the arrow to the peer
key string private key file associated with the certificate
Implementations should avoid validating inputs. That's the job of the wrapper. The wrapper and the implementation are closely coupled by design.
Implementations must print sent transfers to standard output, one transfer per line.
<send-time>,0\n # The second element is reserved for future use
Implementations must print received transfers to standard output, one transfer per line.
<send-time>,<receive-time>\n
Time values are unix epoch milliseconds.
1472344673324,1472344673345
To avoid any performance impact, take care that writes to standard output are buffered. Make sure any buffered writes are flushed before the implementation exits.
Implementations must return zero on successful completion. If there is an error, they must return a non-zero exit code. Some language runtimes (notably Java) won't automatically convert uncaught exceptions to non-zero exit codes, so you may have to do the conversion yourself.
Implementations must create one connection only. They must connect
using the SASL mechanism ANONYMOUS
.
When connection-mode
is client
, the implementation must establish
an outgoing connection. When it is server
, the imlementation must
listen for an incoming connection.
Implementations must use only one queue (or similar addressable resource), and only one link to that queue, either a sending or a receiving link.
If the implementation API offers sessions (that is, a sequential context for links), then the implementation must create only one session.
When channel-mode
is active
, the implementation must initiate
creation of the sessions and links. When it is passive
, the
implementation must instead wait for initiation from the peer and then
confirm their creation.
Implementations must set an application property named SendTime
containing a long
representing the send time in milliseconds.
By convention, message bodies are filled with as many x
s as
indicated by the body-size
parameter. The x
must be a single
byte, not a multi-byte Unicode character.