Skip to content
This repository was archived by the owner on Apr 29, 2022. It is now read-only.

Commit 3239e27

Browse files
author
Anton Vorontsov
committed
Added changelog
1 parent 0e08ede commit 3239e27

File tree

6 files changed

+81
-64
lines changed

6 files changed

+81
-64
lines changed

docs/changelog.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
All notable changes to this library will be documented in this file.
44

5+
## [3.1.1] - 2020-01-20
6+
7+
### Added
8+
9+
- Pattern matching (`WildcardExtensions`) so message handlers can now
10+
- Extension methods which allow user to set the exact exchange from which messages will be processed by message handlers.
11+
- `MessageHandlingService` which is responsible for message processing.
12+
- `WildcardExtensions` and `MessageHandlingService` unit tests.
13+
514
## [2.2.1] copy of [3.1.0] - 2019-12-06
615

716
### Added

docs/exchange-configuration.md

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
### Basics
44

5-
Client applications work with exchanges and queues, and they must be "declared" and "bound" to each other is a certain way before they can be used.
6-
Queues and exchanges can also be customized by using additional parameters. This library allows to do this routine simply calling `AddExchange` method passing additional parameters to it.
5+
Client applications work with exchanges and queues which must be "declared" and "bound" to each other in a certain way before they can be used.
6+
Queues and exchanges can also be customized by using additional parameters. This library allows you to do this routine simply calling the `AddExchange` method passing additional parameters to it.
77
You are allowed to configure multiple exchanges with multiple queues bound to them.
88

99
Your `Startup` code will look like this.
@@ -57,26 +57,26 @@ And the `appsettings.json` file will be like this.
5757
}
5858
```
5959

60-
The RabbitMQ client configuration section not specified in this example, for more information see the [documentation](rabbit-configuration.md) file.
60+
The RabbitMQ client configuration section is not specified in this example, for more information see the [documentation](rabbit-configuration.md) file.
6161

6262
Exchanges can be configured with properties:
63-
- `Type` - exchange type (direct, topic, fanout). Default value is `"direct"`.
64-
- `Durable` - durability option. Default value is `true`.
65-
- `AutoDelete` - option for exchange auto deleting. Default value is `false`.
66-
- `Arguments` - dictionary of additional arguments. Default value is `null`.
67-
- `RequeueFailedMessages` - option that specifies behaviour of re-queueing failed messages with delay through dead-letter-exchange. Default value is `true`. Mechanism of sending delayed messages covered in the [documentation](message-production.md).
68-
- `DeadLetterExchange` - default value for dead-letter-exchange. Default value for dead-letter-exchange name is `"default.dlx.exchange"`.
69-
- `Queues` - collection of queues bound to the exchange.
63+
- `Type` - an exchange type (direct, topic, fanout). The default value is `"direct"`.
64+
- `Durable` - a durability option. The default value is `true`.
65+
- `AutoDelete` - an option for exchange auto deleting. The default value is `false`.
66+
- `Arguments` - a dictionary of additional arguments. The default value is `null`.
67+
- `RequeueFailedMessages` - an option that specifies behaviour of re-queueing failed messages with certain delay through the dead-letter-exchange. The default value is `true`. The mechanism of sending delayed messages is covered in the [documentation](message-production.md).
68+
- `DeadLetterExchange` - a value for dead-letter-exchange. The default value for the dead-letter-exchange name is `"default.dlx.exchange"`.
69+
- `Queues` - a collection of queues bound to the exchange.
7070

7171
Queue options:
72-
- `Name` - queue name.
73-
- `Durable` - durability option. Default value is `true`.
74-
- `AutoDelete` - option for queue auto deleting. Default value is `false`.
75-
- `Exclusive` - exclusive option. Default value is `false`.
76-
- `Arguments` - dictionary of additional [arguments](https://www.rabbitmq.com/queues.html#optional-arguments). Default value is `null`.
77-
- `RoutingKeys` - collection of routing keys that queue "listens".
72+
- `Name` - a queue name.
73+
- `Durable` - a durability option. The default value is `true`.
74+
- `AutoDelete` - an option for queue auto deleting. The default value is `false`.
75+
- `Exclusive` - an exclusive option. The default value is `false`.
76+
- `Arguments` - a dictionary of additional [arguments](https://www.rabbitmq.com/queues.html#optional-arguments). The default value is `null`.
77+
- `RoutingKeys` - a collection of routing keys that the queue "listens".
7878

79-
Taking into account all the default values that you can skip configuration will look like this.
79+
Taking into account all the default values that you can skip, configuration will look like this.
8080

8181
```json
8282
{
@@ -92,7 +92,7 @@ Taking into account all the default values that you can skip configuration will
9292
}
9393
```
9494

95-
If you want to use routing keys matching with queue names you can skip `"RoutingKeys"` option and queues will be bound to the exchange by their names.
95+
If you want to use routing keys matching with queue names you can skip the `"RoutingKeys"` option and queues will be bound to the exchange by their names.
9696

9797
```json
9898
{
@@ -184,5 +184,6 @@ services.AddRabbitMqClient(clientConfiguration)
184184
.AddConsumptionExchange("ConsumptionExchange", exchangeConfiguration);
185185
```
186186

187-
For the RabbitMQ client configuration see the [Previous page](rabbit-configuration.md) <br>
187+
For the RabbitMQ client configuration see the [Previous page](rabbit-configuration.md)
188+
188189
For message production features see the [Next page](message-production.md)

docs/message-consumption.md

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
### Starting a consumer
44

5-
The first step that has to be done to retrieve messages from queues is to start a consumer. This can be achieved by calling `StartConsuming` method of the `IQueueService`.
6-
Consumption exchanges will work only in message-production mode if `StartConsuming` method won't be called.
5+
The first step that has to be done to retrieve messages from queues is to start a consumer. This can be achieved by calling the `StartConsuming` method of `IQueueService`.
6+
Consumption exchanges will work only in a message-production mode if the `StartConsuming` method won't be called.
77

88
Let's say that your configuration looks like this.
99

@@ -27,7 +27,7 @@ public class Startup
2727
}
2828
```
2929

30-
You can register an `IHostedService` and inject the instance of the `IQueueService` into it.
30+
You can register `IHostedService` and inject an instance of `IQueueService` into it.
3131

3232
```c#
3333
services.AddSingleton<IHostedService, ConsumingService>();
@@ -108,7 +108,7 @@ public class Worker : BackgroundService
108108

109109
The second step without which receiving messages does not make sense - configuration of message handling services. If there are no message handlers then received messages will not be processed.
110110

111-
Message handlers are classes that implement `IMessageHandler` interface (or a few others) and contain functionality including error handling for processing messages.
111+
Message handlers are classes that implement the `IMessageHandler` interface (or a few others) and contain functionality (including error handling) for processing messages.
112112
You can register `IMessageHandler` in your `Startup` like this.
113113

114114
```c#
@@ -134,7 +134,8 @@ public class Startup
134134

135135
RabbitMQ client and exchange configuration sections are not specified in this example, but covered [here](rabbit-configuration.md) and [here](exchange-configuration.md).
136136

137-
`IMessageHandler` implementation will "listen" for messages by specified routing key, or a collection of routing keys. If it is necessary you can also register multiple message handler at once.
137+
`IMessageHandler` implementation will "listen" for messages by the specified routing key, or a collection of routing keys. If it is necessary, you can also register multiple message handler at once.
138+
138139
```c#
139140
services.AddRabbitMqClient(clientConfiguration)
140141
.AddExchange("ExchangeName", isConsuming: true, exchangeConfiguration)
@@ -151,7 +152,7 @@ services.AddRabbitMqClient(clientConfiguration)
151152
.AddMessageHandlerSingleton<AnotherCustomMessageHandler>(new[] { "#.key", "third.*" });
152153
```
153154

154-
You are also allowed to specify the exact exchange which will be "listened" by message handler with the given routing key (or pattern).
155+
You are also allowed to specify the exact exchange which will be "listened" by a message handler with the given routing key (or a pattern).
155156

156157
```c#
157158
services.AddRabbitMqClient(clientConfiguration)
@@ -178,8 +179,8 @@ services.AddRabbitMqClient(clientConfiguration)
178179
.AddMessageHandlerSingleton<OneMoreCustomMessageHandler>("first.routing.key");
179180
```
180181

181-
`IMessageHandler` consists of one method `Handle` that gets a message in string format. You can deserialize it (if it is a json message) or handle a raw value.
182-
Thus, message handler will look like this.
182+
`IMessageHandler` consists of one method `Handle` that gets a message in a string format. You can deserialize it (if it is a json message) or handle a raw value.
183+
Thus, a message handler will look like this.
183184

184185
```c#
185186
public class CustomMessageHandler : IMessageHandler
@@ -192,7 +193,7 @@ public class CustomMessageHandler : IMessageHandler
192193
}
193194
```
194195

195-
You can also inject services inside `IMessageHandler` constructor.
196+
You can also inject services inside the `IMessageHandler` constructor.
196197

197198
```c#
198199
public class CustomMessageHandler : IMessageHandler
@@ -210,7 +211,7 @@ public class CustomMessageHandler : IMessageHandler
210211
}
211212
```
212213

213-
The only exception is `IQueueService`. You can't inject it inside a message handler because of the appearance of cyclic dependencies. If you want to use an instance of `IQueueService` (e.g. handle one message and send another) use `INonCyclicMessageHandler`.
214+
The only exception is the `IQueueService`. You can't inject it inside a message handler because of the appearance of cyclic dependencies. If you want to use an instance of `IQueueService` (e.g. handle one message and send another) use `INonCyclicMessageHandler`.
214215
`INonCyclicMessageHandler` can be registered the same way as `IMessageHandler`. There are similar semantic methods for adding it in **singleton** or **transient** modes.
215216

216217
```c#
@@ -298,7 +299,7 @@ So you can use async/await power inside your message handler.
298299

299300
The message handling process is organized as follows:
300301

301-
- `IQueueMessage` receives a message and delegates it to the `IMessageHandlingService`.
302+
- `IQueueMessage` receives a message and delegates it to `IMessageHandlingService`.
302303
- `IMessageHandlingService` gets a message (as a byte array) and decodes it to the UTF8 string. It also checks if there are any message handlers in collections of `IMessageHandler`, `IAsyncMessageHandler`, `INonCyclicMessageHandler` and `IAsyncNonCyclicMessageHandler` instances and forwards a message to them.
303304
- All subscribed message handlers (`IMessageHandler`, `IAsyncMessageHandler`, `INonCyclicMessageHandler`, `IAsyncNonCyclicMessageHandler`) process the given message.
304305
- `IMessageHandlingService` acknowledges the message by its `DeliveryTag`.

docs/message-production.md

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
`IQueueService` represents a service that handles all the work of sending and receiving messages. You can inject `IQueueService` wherever you want in order to use it.
66

77
It can be a custom service or a controller.
8+
89
```c#
910
[Route("api/[controller]")]
1011
public class HomeController : Controller
@@ -42,9 +43,10 @@ public static class Program
4243
}
4344
```
4445

45-
To publish a message to an exchange, use one of the `IQueueService` sending methods.
46+
To publish a message to an exchange, use one of `IQueueService` sending methods.
4647

4748
You can send objects using `Send` or `SendAsync` methods. Objects will be serialized into json and sent with `IBasicProperties` where content type set as `"application/json"` and `Persistent` set as `true`.
49+
4850
```c#
4951
var message = new
5052
{
@@ -66,7 +68,7 @@ await queueService.SendJsonAsync(message, exchangeName: "exchange.name", routing
6668
```
6769

6870
If you want to send a message in another format different from json you can use `SendString` methods.
69-
In this case `IBasicProperties` will be only with `Persistent` property set as `true`, so you can send any string you want (e.g. an XML string).
71+
In this case `IBasicProperties` will be only with the `Persistent` property set as `true`, so you can send any string you want (e.g. an XML string).
7072

7173
```c#
7274
var message = "<?xml version="1.0" encoding="UTF-8"?><message>Hello World!</message>";
@@ -75,7 +77,8 @@ queueService.SendString(message, exchangeName: "exchange.name", routingKey: "rou
7577
await queueService.SendStringAsync(message, exchangeName: "exchange.name", routingKey: "routing.key");
7678
```
7779

78-
And if you want to manage everything by yourself you can use `Send` methods passing message as byte array and `IBasicProperties` as parameters.
80+
And if you want to manage everything by yourself you can use `Send` methods passing message as a byte array and `IBasicProperties` as parameters.
81+
7982
```c#
8083
var properties = queueService.Channel.CreateBasicProperties();
8184
// Set everything you want.
@@ -87,7 +90,8 @@ queueService.Send(bytes, properties, exchangeName: "exchange.name", routingKey:
8790
await queueService.SendAsync(bytes, properties, exchangeName: "exchange.name", routingKey: "routing.key");
8891
```
8992

90-
You are also allowed to send messages with delay (in seconds). All of the previously listed methods have an overload that takes delay parameter.
93+
You are also allowed to send messages with delay (in seconds). All of previously listed methods have an overload that takes a `delay` parameter.
94+
9195
```c#
9296
// Objects
9397
queueService.Send(message, exchangeName: "exchange.name", routingKey: "routing.key", secondsDelay: 10);
@@ -107,24 +111,26 @@ await queueService.SendAsync(bytes, properties, exchangeName: "exchange.name", r
107111
```
108112

109113
### Mechanism of sending delayed messages
114+
110115
The implementation of sending deferred (delayed) messages in this project is quite tricky.
111116
The image below shows a model of the whole process of passing the message from the producer to the consumer.
112117
![Model of sending delayed messages](./images/delayed-message-model.png)
113118

114-
**Prerequisites.** Let's say that producer want to send a message to the exchange **"Exchange B"** with a routing key **"routing.key"** and delay in **30 seconds**.
115-
- Message goes to the exchange **"Exchange A"** whose responsibility is to manage delaying (storing) the message.
116-
- After that a queue with a compound name and special arguments is being created. Name consists of three parts: routing key of sent message, word "delayed" and number of seconds delay.
119+
**Prerequisites.** Let's say that producer want to send a message to the exchange **"Exchange B"** with a routing key **"routing.key"**, and a delay in **30 seconds**.
120+
- Message goes to the exchange **"Exchange A"** whose responsibility is to manage delaying (storing) the message.
121+
- After that a queue with a compound name and special arguments is being created. Name consists of three parts: the routing key of the sent message, a word "delayed", and a number of delay seconds .
117122
Queue arguments are as follows.
118123
```
119124
x-dead-letter-exchange : Exchange В
120125
x-dead-letter-routing-key : routing.key
121126
x-message-ttl : secondsDelay * 1000
122127
x-expires : secondsDelay * 1000 + 60000
123128
```
124-
- A message, which gets in that queue, will have a specified ttl (time to live) and an exchange to which the message will be sent after expiration.
129+
- A message, which gets in that queue, will have a specified ttl (time to live), and an exchange to which the message will be sent after expiration.
125130
- That new queue bounds to the **Exchange A**. That queue will be automatically deleted if there are no more messages in it within a minute.
126-
- Message goes to that queue, waits until expiration and goes in the **"Exchange B"**, which routes it as it should be.
127-
- Message gets in the destination queue and consumer can retrieve that message.
131+
- Message goes to that queue, waits until an expiration moment and goes in the **"Exchange B"**, which routes it as it should be.
132+
- Message gets in the destination queue, and the consumer can retrieve that message.
133+
134+
For the exchange configuration see the [Previous page](exchange-configuration.md)
128135

129-
For the exchange configuration see the [Previous page](exchange-configuration.md) <br>
130136
For message consumption features see the [Next page](message-consumption.md)

docs/rabbit-configuration.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# RabbitMQ configuration
22

3-
To connect to a RabbitMQ, it is necessary to instantiate an `IQueueService` and configure it to use desired endpoint, credentials and other valuable connection settings.
4-
`IQueueService` allows clients to configure queues to exchange bindings, and to consume and produce messages in different ways (sync or async, with or without delay). To add `IQueueService` in your application simply use `AddRabbitMqClient` extension method as in the example below.
3+
To connect to a RabbitMQ server, it is necessary to instantiate `IQueueService` and configure it to use a desired endpoint, credentials and other valuable connection settings.
4+
`IQueueService` allows clients to configure queues to exchange bindings, and to consume and produce messages in different ways (sync or async, with or without delay). To add `IQueueService` in your application simply use the `AddRabbitMqClient` extension method as in the example below.
55

66
```c#
77
public class Startup
@@ -24,7 +24,7 @@ public class Startup
2424
}
2525
```
2626

27-
RabbitMQ client can be configured via configuration section located in the `appsettings.json` file. This configuration section must be of a certain format and down below is an example of all configuration options used in `IQueueService`.
27+
A RabbitMQ client can be configured via a configuration section located in the `appsettings.json` file. This configuration section must be of a certain format and down below is an example of all configuration options used in `IQueueService`.
2828

2929
```json
3030
{
@@ -43,7 +43,7 @@ RabbitMQ client can be configured via configuration section located in the `apps
4343
}
4444
```
4545

46-
RabbitMQ connection can be configured with properties:
46+
A RabbitMQ connection can be configured with properties:
4747
- `HostName` - RabbitMQ server,
4848
- `HostNames` - collection of RabbitMQ hostnames,
4949
- `TcpEndpoints` - collection of AMPQ TCP endpoints,
@@ -70,7 +70,7 @@ RabbitMQ connection can be configured with properties:
7070
}
7171
```
7272

73-
For high availability RabbitMQ clusters with multiple nodes you can set hosts collection with `HostNames` option.
73+
For high availability RabbitMQ clusters with multiple nodes you can set hosts collection with the `HostNames` option.
7474

7575
```json
7676
{
@@ -109,9 +109,9 @@ If nodes are running on different hosts with different ports you have an option
109109
}
110110
```
111111

112-
There is an importance of `TcpEndpoints`, `HostNames`, `HostName` options. If all of them are set connection will be created using `TcpEndpoints` option. The second will be option `HostNames` and the `HostName` option is the least important between those three.
112+
There is an importance of `TcpEndpoints`, `HostNames`, `HostName` options. If all of them are set connection will be created using the `TcpEndpoints` option. The second will be the option `HostNames` and the `HostName` option is the least important between those three.
113113

114-
If `.json` configuration files unacceptable for you there is another `AddRabbitMqClient` extension method that takes manually created `RabbitMqClientOptions` configuration as a parameter. `RabbitMqClientOptions` is the model class used for injecting RabbitMQ client configuration as an `IOtions<T>` instance so properties named the same as in the previous method.
114+
If `.json` configuration files unacceptable for you there is another `AddRabbitMqClient` extension method that takes manually created `RabbitMqClientOptions` configuration as a parameter. `RabbitMqClientOptions` is the model class used for injecting a RabbitMQ client configuration as an `IOtions<T>` instance so properties named the same as in the previous method.
115115

116116
```c#
117117
public class Startup

0 commit comments

Comments
 (0)