How to Use RabbitMQ
The following article will cover the basics of using RabbitMQ for your Content Catalyst site.
You can find comprehensive tutorials at https://www.rabbitmq.com/. We recommend reading the core RabbitMQ concepts and subscribing to a queue by following tutorial 3.
(Please remember that you will only be given a read-only login to read from a pre-configured queue - you won’t be able to declare the queue or bind it, so skip those steps in the tutorial when trying against the live server.)
🔔Note: First, please contact support via support@contentcatalyst.com for the hostname and credentials to log in to our RabbitMQ instance.
Queues
RabbitMQ stores a copy of every message in a queue until the application is ready to receive it.
We recommend having a separate queue for each integration, so that they each receive a copy of the message.
Topics
Each queue you set up can be configured to listen to certain events - we use topic routing to make sure the queue only processes events relevant to it.
Each message is tagged with a topic, such as subscribers.requests.accountmanager (this can be found in the message ‘RoutingKey’ property).
If you wanted a queue to listen to all subscriber requests, you can request the topic subscribers.requests.*.
Alternatively, you can listen to all events by requesting the topic #.
Message Structure
Message Id
Each event created by iReports will have a unique and persistent id. We provide this as a GUID (UUID) in the message property MessageId. A message can, in some circumstances, be delivered twice (or more): this can be OK for some types of messages, but for others, we expect clients to de-duplicate the message.
Message Body
By default, event messages are UTF8 encoded JSON strings. Each message is wrapped in an ‘Envelope’ with the following properties:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Message envelope",
"description": "An envelope wrapping the message data, with standard properties shared between all messages.",
"type": "object",
"properties": {
"version": {
"type": "string",
"description": "A semantic version ('semver') string describing the version of the message. See versioning below."
},
"data": {
"description": "The content of the event (format varies for each topic - read the documentation for each one)."
},
"tenantId": {
"description": "A string used by the Content Catalyst system - safe for you to ignore.",
"type": "string"
},
"createdDate": {
"description": "The date/time when the event was triggered.",
"type": "string",
"format": "date-time"
},
"creator": {
"description": "The username of the user who triggered the event. (Can be null if a system event or an unauthenticated (anonymous) user). Subscribers should ignore events with their own username, so that infinite loops don't occur.",
"type": "string"
}
}
}
Unless otherwise specified, the JSON follows these conventions:
- Property names are camel-case, like JavaScript objects
- Properties whose values are the “default” are not included and will have to be populated client-side (‘default’ is: false for booleans, null for objects, 0 for numbers). This is done to reduce message size
- Enums will be serialised as strings
- Datetimes will be serialised as a string using the ISO 8601 standard e.g. 2012-03-19T07:22Z
- New properties can be added at any time - if the client doesn’t know about properties, they should ignore them or store them in an “extra properties” mapping.
Versioning
All messages contain a semantic version number for the message, in the form of “X.Y.Z” where X is the major version, Y is the minor version, and Z is the patch version.
When a major change is necessary, both the current major version and the next major version of a message will be added to the queue, so that dependent services can be updated. Because of this, you should ignore messages with major versions which your application does not know about. The old major version of the message will be removed after the notice period.
When a minor change is necessary, such as adding a new message or a property to an existing message, the minor or patch versions will be incremented as appropriate. There is no dual-running period of messages for minor changes, so your application should usually ignore the minor or patch version number.
Example clients
Clients for RabbitMQ can be written in many different programming languages. Here is a basic example C# console program that will connect to a queue and print any messages it receives:
using System;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;
using System.Threading;
internal class Program
{
private static void Main(string[] args)
{
var factory = new ConnectionFactory()
{
HostName = "RABBIT_MQ_ADDRESS",
Port = AmqpTcpEndpoint.UseDefaultPort,
UserName = "USERNAME",
Password = "PASSWORD",
VirtualHost = "/"
};
var queueName = "QUEUE_NAME";
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine("[x] {0}", message);
};
// This will open a background thread, listening to messages from RabbitMQ
channel.BasicConsume(queueName, true, consumer);
// Block the program from exiting so the user can see messages
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
}