Swaptacular nodes use STOMP to interoperably send Swaptacular Messaging Protocol (SMP) messages to each other. This project implements both a STOMP client (to send messages), and a STOMP server (to receive messages). The ultimate deliverable is a docker image, generated from the project's Dockerfile.
Note: This implementation supports only JSON serialization for the Swaptacular Messaging Protocol.
Containers started from the generated docker image must have access to the following services:
-
RabbitMQ server instance, which acts as broker for SMP messages. The rabbitmq_random_exchange plugin should be enabled.
For each peer node, at least one RabbitMQ queue must be configured on the broker instance, so that all SMP messages that need to be send to a given peer, are placed in the respective peer's queue(s). The STOMP client(s) for each peer node will read from the respective peer's queue(s). See the
configure-queue
command bellow.Also, a RabbitMQ exchange named
creditors_in
,debtors_in
, oraccounts_in
(depending on the type of the Swaptacular node) must be configured on the broker instance. This exchange is for the received messages, which eventually will be processed by the current Swaptacular node. The routing key will represent the highest 24 bits of the MD5 digest of the creditor ID, the debtor ID, or the debtor/creditor ID pair (again, depending on the type of the Swaptacular node). For example, if an "Accounting Authority" node receives a message with debtor ID "123", and creditor ID "456", the STOMP server will publish the message to theaccounts_in
exchange, and the routing key will be "0.0.0.0.1.0.0.0.0.1.0.0.0.1.0.0.0.0.1.1.0.1.0.0". This allows messages for different accounts to be routed to different servers for processing (sharding).Important note: The
rabbitmq_random_exchange
plugin must be enabled on the RabbitMQ server instance. -
A database containing the current Swaptacular node's data (including information about all peer nodes) must be available as a local directory mount in the container. To create and maintain such a database, you can use these scripts.
-
A server SSL certificate, and its corresponding private key must be available. Those will be used by both the client and the server, to authenticate before peer nodes. You can use the same scripts to generate the server certificate and the private key.
The behavior of the running container can be tuned with environment variables. Here are the most important settings with some random example values:
# TCP port for the STOMP server. The default is 1234.
SWPT_SERVER_PORT=1234
# A path to a server certificate PEM file. The certificate will
# be used (by both the client and the server) to authenticate
# before peer nodes. The default is "/etc/swpt/server.crt".
SWPT_SERVER_CERT=/etc/swpt/server.crt
# A path to a PEM file containing an *unencrypted* private key.
# The key will be used (by both the client and the server) to
# authenticate before peer nodes. The default
# is "/secrets/swpt-server.key".
SWPT_SERVER_KEY=/secrets/swpt-server.key
# The maximum number of messages that the STOMP server is allowed
# to store in memory. The default is 100.
SWPT_SERVER_BUFFER=100
# The maximum number of messages that the STOMP clinet is allowed
# to store in memory. The default is 100.
SWPT_CLIENT_BUFFER=100
# The URL of the database containing the current Swaptacular
# node's data, including information about all peer nodes.
# Currently, only the "file://" scheme is supported for the URL.
# The default is "file:///var/lib/swpt-nodedata".
SWPT_NODEDATA_URL=file:///var/lib/swpt-nodedata
# The URL for initiating connections with the RabbitMQ server
# which is responsible for brokering SMP messages. The default
# is "amqp://guest:guest@localhost:5672".
PROTOCOL_BROKER_URL=amqp://guest:guest@localhost:5672
# Set the minimum level of severity for log messages ("info",
# "warning", or "error"). The default is "warning".
APP_LOG_LEVEL=info
# Set format for log messages ("text" or "json"). The default is
# "text".
APP_LOG_FORMAT=text
For more configuration options, check the development.env file.
The entrypoint of the docker container allows you to execute the following documented commands:
-
swpt-server
Starts a STOMP server for a Swaptacular node. You can start simultaneously as many servers as you like.
For more information, run
swpt-server --help
. -
swpt-client
Initiates a long-lived client STOMP connection to a peer Swaptacular node. A peer node ID, and a queue name should be specified as arguments. You can start simultaneously as many clients as you like.
For more information, run
swpt-client --help
. -
swpt-drainer
Consumes (drains) a RabbitMQ queue associated with an already deactivated Swaptacular peer node, freeing up resources. A peer node ID, and a queue name should be specified as arguments. You can start simultaneously as many drainers as you like.
For more information, run
swpt-drainer --help
. -
configure-queue
Configures a RabbitMQ queue that will contain messages which have to be send to a specific peer Swaptacular node. A peer node ID, and a queue name should be specified as arguments.
For each peer node, before running the
swpt-client
command, you will have to run theconfigure-queue
command first. For each peer node, you may configure as many queues as you like, but you must make sure that for every configured queue, a correspondingswpt-client
will be running.For more information, run
configure-queue --help
.Important note: Peers that do not have an empty file with the name
ACTIVE
in their corresponding directory in the node's database (see theSWPT_NODEDATA_URL
environment variable), will be considered inactive, and no connections to/from them will be allowed. The existence of this file signals that all necessary objects related to the peer (configuration files, RabbitMQ queues, exchanges, bindings etc.) have been created.
Here are some examples how to use the generated docker image for different Swaptacular nodes:
-
Install Docker Engine and Docker Compose.
-
To create an .env file with reasonable defalut values, run this command:
$ cp development.env .env
-
To run the tests, use the following commands:
$ docker-compose build $ docker-compose run tests-dummy test
-
Install Poetry.
-
Create a new Python virtual environment and activate it.
-
To install dependencies, run this command:
$ poetry install
-
You can use
swpt-server
andswpt-client
to run the server or the client,configure-queue
to configure a queue, andpytest --cov=swpt_stomp --cov-report=html
to run the tests and generate a test coverage report.Note however, that the above commands rely on being able to connect to a RabbitMQ server instance at "amqp://guest:guest@localhost:5672". Also, note that because the RabbitMQ "guest" user can only connect from localhost, you should either explicitly allow the "guest" user to connect from anywhere, or create a new RabbitMQ user, and change the RabbitMQ connection URL accordingly (
PROTOCOL_BROKER_URL
in the .env file).Moreover, you need to enable the
rabbitmq_random_exchange
plugin by running:$ sudo rabbitmq-plugins enable rabbitmq_random_exchange