Using rabbit descriptors

Descriptors are configuration objects, described here below.

Client descriptors

Each client on this SDK has a single dependency which holds all information to "describe" how client could be configured, and this is called Client descriptors.

BrokerDescriptor class

This is the base class for all client descriptors, and it's defined like this:

  • Address: The broker URI.
  • VirtualHost: The virtual host to use in the configuration.
  • Credentials: A complex object which will be used to authenticate against RabbitMQ broker.
  • EnableChannelEvents: A boolean value indicating if channel events should be captured by client.

SubscriberDescriptor class

  • MessageFormat: Indicates the format of messages, and this is an enum with these two possible values:

    • MessageFormat.Header : The incoming messages are incapsulated into a Message<T> object, this one holds other extra information.
    • MessageFormat.Headless: The incoming messages are sent directly, with no incapsulation by other objects, so subscribers must read them as original message format.
  • PrefetchCount: The prefetch value used by rabbitmq cluster.

  • Queue: A QueueDescriptor object used to configure the queue which this client will be subscribed with.
  • RetryPolicy: A RetryPolicyDescriptor object used to configure retry policies.
  • Arguments: A IDictionary<string, object> object used to configure channel with the underlying consumer.

BinderSubscriberDescriptor class

Inherents from SubscriberDescriptor class.

  • Binder: A BinderDescriptor object used to establish rule for binding.
  • Exchange: A ExchangeDescriptor object used to define the exchange object.

PublisherDescriptor class

  • Message: A default configuration (MessageDescriptor object) for incoming messages.
  • Exchange: An exchange configuration (ExchangeDescriptor object).
  • Confirmation: A default configuration (DeliveryConfirmation) for incoming messages.
  • OnBuildProperties: A custom action to use whenever BasicProperties object is initialized.

BinderPublisherDescriptor class

Inherents from PublisherDescriptor class.

  • Binder: A BinderDescriptor object used to establish rule for binding.
  • Queue: The QueueDescriptor object used to bind with the Exchange object defined in the base class.

RestBrokerDescriptor class

  • ServiceName: An identifier used to retrieve a service component which hosts a subscriber.
  • Durable: Indicates if all channel components are persistent.

RestPublisherDescriptor class

Inherents from RestBrokerDescriptor class.

  • FullDuplex: Indicates the capabilities for the client if the communication must be directional or not, (default: true).
  • IncludeContent: Indicates if the response includes the orginal message (json literal), (default: false).
  • Timeout: A timeout for requests, (default: null).
  • ContextType A content-type used to requests by rest publishers, (default: application/json).

Object descriptors

Object descriptors describes how queues, exchanges, binders, retry policies are configured.

RetryPolicyDescriptor class

Represents a common way to define a policy to re-send messages whenever they need to be re-processed.

  • Enabled: Indicates if this feature is enabled, (default: false).
  • MaxRetry: The misimum number of attempts to re-send messages, (default: 5).
  • Delayed: A TimeSpan object indicating the delay to apply before resend messages into the orginal queues (default: 5 seconds).
  • Durable: Indicates if all behind components (exchanges and queues) must be persistent, (default: false).
  • AutoDelete: Indicates if all behind components (exchanges and queues) could be deleted when no subscribers are running, (default: true).

This settings is related to subscribers (no publishers), and its configuration is based on the queue which is listening on. An important point to consider when this feature is enabled is clients create some rabbitmq objects, so:

  • A new exchange to forward messages (by subscriber) to be re-processed.
  • A new queue (retry queue) to park messages to be re-processed.
  • A new exchange (dead letter exchange) used by "retry queue"

So, all above rabbits are created in order to create a message retry workflow, see immage:

In the above example we have:

  • A consumer subscribed with demo queue.
  • The consumer forwards messages into demo/_dlx exchange when they need to be re-processed.
  • A demo/_retry queue used to host messages to be re-processed.
  • There's a binding between demo/_retry queue with demo/_dlx exchange.
  • Another a binding between demo queue with demo/_dlx exchange.

All messages presents in the retry queue, keep alive for a period indicated in Delayed property in RetryPolicyDescriptor instance. Just overcome the delay period, messages automatically are forwarded into its dead letter exchange, that in this example is demo/_retry.

Finally being a direct binding between demo/_retry and demo queue (original queue), messages could be re-processed again, a specific times (indicated in MaxRetry property on this descriptor).

A final consideration for this feature is consumers need to set Acknowledged=false and Requeue=true on MessageDeliverEventArgs<TData>, otherwise no messages could be re-processed.

MessageDescriptor class

Represents some features for messages.

  • Format: The format of messages should be sent (Header or Headless), (default: Header).
  • Ttl: The time-to-live used whenever a single message doesn't have one, (default: 15 minutes).
  • Persistent: Indicates if message should be persistent, (default: false).

DeliveryConfirmation class

Represent a configuration settings for publishers, used to receive confirmations by broker.

  • Enabled: Indicates if this feature is enabled, (default: false)
  • Timeout: It depends on WaitFor property, and if this is true so It will be applied before consumers go down (on disposing), in order to receive confirmations, (default: null).
  • WaitFor: Indicates if It should be applied a delay logic before closing / disposing the client, (default: false).

BinderDescriptor class

Represents a configuration for biding between exchanges and queues.

  • RoutingKey: A routing key used to bind, (default: string.Empty).
  • Arguments: A IDictionary<string, object> object used to configure the current binding, (default: empty dictionary).

ExchangeDescriptor class

This class is used to setup exchanges, and expose these properties:

  • Prefix: used for the final name in rabbit cluster, (default value: esb/exchange).
  • Name: name of exchange.
  • Durable: used to indicate if it is persisted on disk.
  • AutoDelete: used to auto-delete itself after subscribers lose biding with their queues, this is enabled if Durable is false.
  • Type: indicates the type of this exchange (Direct, Fanout, headers, Topic).
  • Arguments: a key / value structure used to set custom arguments.

QueueDescriptor class

This class is used to setup queues, and its properties are:

  • Prefix: used for the final name in rabbit cluster, (default value: esb/queue).
  • Name: name of queue
  • Durable: used to indicate if it is persisted on disk.
  • Exclusive: used to indicate if it can be bound only one subscriber at time.
  • AutoDelete: used to auto-delete itself after subscribers lose biding with their queues, this is enabled if Durable is false. Default value: true
  • Arguments: a key / value structure used to set custom arguments.

Queue Arguments in rabbit can hold many ones, and it could depend on the type of queue, in fact, there are 3 types:

  • Classic (default if it isn't specified)
  • Quorum (a modern way to manage queues, for high availability)
  • Stream (just another way to expose queues style "streaming"), used to reduce complexity on "exclusives" queues for group of subscribers.

The last two ones are implemented in the latest releases of rabbitmq, so their usage don't depend on this library, instead of the current version of your rabbitmq clusters, please read the docs

About quorum queues

As mentioned before, quorum queues represents a new smart way to manage queues, the motivation for this usage if for queue replication contexts, see docs for details.

// an example how to set a queue as quorum

var descriptor = new BinderPublisherDescriptor
{
  // .. other settings
  Queue = {
    Name = "my-queue",
    AutoDelete = false,
    Durable = true,
    Arguments = {
      {"x-queue-type", "quorum"}
      // -- other rabbitmq arguments for queues
    }
  }
}

In the above example, you can notice about AutoDelete and Durable properties ar set with those values for these reasons:

AutoDelete set a true cannot be done, because quorum queues are persistent, but in the case of volatile queues, you can set "x-expire" argument. Durable set a true, because this kind of queue is born for high availability, using replications whenever nodes are offline, doing otherwise It wouldn't make sense.

If you try to set differently, an exception must be thrown.

Note: please remember you can setup descriptors in your configuration files (appsettings.json), even for Arguments properties. The only thing to consider is about aguments value types, in the case of "x-queue-type" argument its value must be a string, and for "x-expires" value must be a numerical representation.

About numerical values for arguments, pay attention on appsettings.json, because in the case of IDictionary<string, object> (in this case the type of Arguments properties), all values are deserialized as string, causing a problem when they are used to setup queue or exchange components, throwing exception a runtime (on application setup), unfortunately this is a mistake non managed well by .NET core when deserialize dictionaries, and in these cases applications must drive in the right way the values (type) before sending to rabbitmq clusters.