Skip to content

sanych-sun/RabbitMQ.Next

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

image

Many thanks for JetBrains for providing Open Source Development license for best in class IDEs for this project.

RabbitMQ.Next

NuGet CI License MIT

RabbitMQ.Next is an experimental low-level RabbitMQ client for .Net with number of high-level APIs (created from scratch, no dependencies to another libraries, so no conflicts!). The motivation to create the library was to separate protocol-level code into a package that could be used as a base block for high-level API libraries. The second goal was to reduce allocation as much as possible and maintain reasonable performance. And the last it was sound cool to create a library that can work with sockets on low-level 😁.

Performance and Allocation

The library was created with idea of the minimal possible allocation. Here is performance and allocations comparison with official dotnet driver:

Publisher benchmarks Find more details

image

Consumer benchmarks Find more details

image

(not that beautiful as publisher one, but I'm working on it)

Packages

Too much packages instead of a single... explained:

Serializers:

More API and integration libraries are coming.

Getting started

First of all have to open the connection to RabbitMQ server:

using RabbitMQ.Next;
...

var connection = await ConnectionBuilder.Default
    .Endpoint("amqp://guest:password@localhost:5672/")
    .ConnectAsync();

And basically that's it. Now all ready to make some useful stuff.

Topology builder

RabbitMQ.Next.TopologyBuilder library contains number of methods to manipulate exchanges, queues and bindings. Create an exchange and bind a queue - it's easy with the library. Complete code of Topology Builder example available here.

using RabbitMQ.Next.TopologyBuilder;
...

await connection.ConfigureAsync(async topology =>
{
  await topology.Exchange.DeclareAsync("my-exchange", ExchangeType.Topic);
  Console.WriteLine("'my-exchange' was created with using library defaults (durable by default)");

  await topology.Exchange.DeclareAsync("my-advanced-exchange", ExchangeType.Topic,
    builder => builder
      .AutoDelete());
  Console.WriteLine("'my-advanced-exchange' was created by explicitly configuring to be auto-delete");

  Console.WriteLine("--------------------------------------------------------------");

  await topology.Queue.DeclareQuorumAsync("my-queue");
  Console.WriteLine("Declare quorum queue named 'my-queue'");

  await topology.Queue.DeclareClassicAsync("my-advanced-queue",
    builder => builder
      .AutoDelete()
      .MaxLength(1000));
  Console.WriteLine("'my-advanced-queue' was created by explicitly configuring to be auto-delete and max-length 1000");

  Console.WriteLine("--------------------------------------------------------------");

  await topology.Queue.BindAsync("my-queue", "my-exchange", "cat");
  await topology.Queue.BindAsync("my-queue", "my-exchange", "dog");
  Console.WriteLine("my-queue was bound to my-exchange by 2 bindings.");
});

Serializers

Message publisher and consumer require to use serializer, so library know how to format and parse message payloads. So far there are 3 serializers supported:

  1. RabbitMQ.Next.Serialization.PlainText
  2. RabbitMQ.Next.Serialization.SystemJson
  3. RabbitMQ.Next.Serialization.MessagePack

However there is no rocket-science to implement other popular formats integration. Please post an issue in the issue tracker and I'll consider implementation of provide some code examples for you.

Message consumer

RabbitMQ.Next.Consumer library let client code to consume messages. Complete example is here

using RabbitMQ.Next.Consumer;
using RabbitMQ.Next.Serialization.PlainText;
...

await using var consumer = connection.Consumer( // IConsumer implements IAsyncDisposable, do not forget to dispose it 
  builder => builder
    .BindToQueue("test-queue")  // It's possible to bind to multiple queues
    .PrefetchCount(10)          // there are some more tweacks could be applied to consumer
    .UsePlainTextSerializer()); // and we need serializer

// and start message consumption by providing handler and cancellation token
await consumer.ConsumeAsync(async message =>
{
    Console.WriteLine($"Message received via '{message.Exchange}' exchange: {message.Content<string>()}");
}, cancellation.Token);

Message publisher

RabbitMQ.Next.Publisher library let client application to publish messages. Complete code is here.

using RabbitMQ.Next.Publisher;
using RabbitMQ.Next.Serialization.PlainText;
...

await using var publisher = connection.Publisher("amq.fanout", // IPublisher implements IAsyncDisposable, do not forget to dispose it
  builder => builder
    .UsePlainTextSerializer()); // It's required to specify the serializer, so library know how to format payload.

// And that's it, publisher is ready. There also some more tweaks could be applied to the publisher via publisher builder 
// (for example disable Publisher confirms)
await publisher.PublishAsync("Some cool message");

// Also there is optional message builder, that could be used to set message properties
await publisher.PublishAsync("test message", 
  message => message
    .Priority(5)
    .Type("MyDto"));

This is how the last message looks like on the server:

image

Message publisher declarative message attributes

RabbitMQ.Next.Publisher.Attributes let client code to initialize message properties from declarative attributes assigned to the DTO class or onto the assembly. This is not replacement for the RabbitMQ.Next.Publisher library, but convinient extension:

This example require to use some serializer that supports objects serialization, for example RabbitMQ.Next.Serialization.SystemJson

using RabbitMQ.Next.Publisher;
using RabbitMQ.Next.Publisher.Attributes;
using RabbitMQ.Next.Serialization.SystemJson; 
...

// have to define DTO, and assign attributes on it
[PriorityAttribute(5)]
[TypeAttribute("MyDto")]
public class SampleDto
{
  public string Title { get;set; }
} 

...
// Small ammendments needed to publisher builder:
await using var publisher = connection.Publisher("amq.fanout",
  message => message
    .UseSystemJsonSerializer()
    .UseAttributesInitializer());  

// and now it's ready for use
await publisher.PublishAsync(new SampleDto { Title = "test message" }); 

This is how the message is looks like:

image

Contribute

Contributions to the package are always welcome!