You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Implement GPRABBITMQ-29: allow full configuration of listeners.
This commit allows users to configure almost every aspect of their service listeners through a combination of the bean property override mechanism and the rabbitQueue/rabbitSubscribe properties. This includes determining whether a particular service listener is transactional, what message converter is uses, and how many consumers it has.
The change involved a fairly significant refactor that made it easy to add automatic reloading of service listeners - so users can modify them on the fly now too!
log.debug "Connecting to rabbitmq ${connectionFactoryUsername}@${connectionFactoryHostname} with ${configHolder.getDefaultConcurrentConsumers()} consumers."
Copy file name to clipboardExpand all lines: src/docs/guide/configuration.gdoc
+2-1Lines changed: 2 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -22,5 +22,6 @@ rabbitmq.connectionfactory.password | The password for connection to the server
22
22
rabbitmq.connectionfactory.hostname | The host name of the server | (none)
23
23
rabbitmq.connectionfactory.virtualHost | The name of the virtual host to connect to | '/'
24
24
rabbitmq.connectionfactory.channelCacheSize | The connection channel cache size | 10
25
-
rabbitmq.concurrentConsumers | The number of concurrent consumers to create per message handler. Raising the number is recommendable in order to scale the consumption of messages coming in from a queue. Note that ordering guarantees are lost when multiple consumers are registered. | 1
25
+
rabbitmq.concurrentConsumers | The number of concurrent consumers to create per message handler. Raising the number is recommended in order to scale the consumption of messages coming in from a queue. Note that ordering guarantees are lost when multiple consumers are registered. | 1
26
+
rabbitmq.disableListening | Disables all service listeners so that they won't receive any messages. | false
When you need fine-grained control over your service listeners, you can tap into the power of Spring. Since each service listener is implemented as a set of Spring beans, you can use Grails' [bean property override|http://grails.org/doc/latest/guide/spring.html#propertyOverrideConfiguration] mechanism to provide your own low-level settings.
2
+
3
+
So how are these beans set up? If a service has either a @rabbitQueue@ or @rabbitSubscribe@ property, then you will have these beans:
4
+
5
+
* @<serviceName>_MessageListenerContainer@ of type [SimpleMessageListenerContainer|api:org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer]
6
+
* @<serviceName>RabbitAdapter@ of type [MessageListenerAdapter|api:org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter]
7
+
8
+
As an example, let's say you have a @MessageStoreService@ like so:
You can then customise things like the number of concurrent consumers, whether the channel is transacted, what the prefetch count should be, and more! Simply add code like this to your runtime configuration (Config.groovy):
18
+
19
+
{code}
20
+
beans {
21
+
messageStoreService_MessageListenerContainer {
22
+
channelTransacted = false
23
+
concurrentConsumers = 10
24
+
prefetchCount = 5
25
+
queueNames = ["q1", "q2"] as String[]
26
+
}
27
+
28
+
messageStoreServiceRabbitAdapter {
29
+
encoding = "UTF-8"
30
+
responseRoutingKey = "replyQueue"
31
+
}
32
+
}
33
+
{code}
34
+
35
+
This approach works for any property that accepts a basic type. But what about bean references? In this case, you can't use the bean property overrides. Fortunately, the most common bean reference you are likely to want to override, the message converter, has a dedicated configuration option:
This is a global setting that accepts the name of a message converter bean. For the rare occasions that you need to override other bean references, you can declare your own @<serviceName>_MessageListenerContainer@ or @<serviceName>_RabbitAdapter@ beans in resources.groovy.
42
+
43
+
Finally, you can override some of the global config options on a per-service basis:
44
+
45
+
{code}
46
+
rabbitmq {
47
+
services {
48
+
messageStoreService {
49
+
concurrentConsumers = 50
50
+
disableListening = true
51
+
}
52
+
}
53
+
}
54
+
{code}
55
+
56
+
There are many options for customisation and we hope the above will get you started.
Copy file name to clipboardExpand all lines: src/docs/guide/configuration/configuringExchanges.gdoc
+8Lines changed: 8 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -68,6 +68,14 @@ This approach isn't limited to topic exchanges: you can automatically bind queue
68
68
# the 'binding' is ignored for fanout exchanges; and
69
69
# the headers exchange requires a map of message header names and values for its binding.
70
70
71
+
{note}
72
+
RabbitMQ has several built-in exchanges with names of the form 'amq.*', for example 'amq.direct'. If you want to bind to these, you currently have to declare them with the correct attributes, i.e.
As you can imagine, these few building blocks allow you to configure some pretty complex messaging systems with very little effort. You can tailor the messaging system to your needs rather than tailor your applications to the messaging system.
Copy file name to clipboardExpand all lines: src/docs/guide/consumingMessages/manualQueueManagement.gdoc
+8Lines changed: 8 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -15,4 +15,12 @@ class DemoService {
15
15
16
16
As with the pub/sub model, messages are delivered to the service by invoking the @handleMessage()@ method. That's all there is to it! The real trick is to configure your exchanges and queues with appropriate bindings, as we described in the configuration section.
17
17
18
+
If you want more say in the configuration of the underlying listener, then you can also specify a map:
The "queues" option can either be a simple queue name or a list of queue names. Again, have a look at the [advanced configuration section|guide:advancedConfig] for information about the extra properties you can set here.
25
+
18
26
One last subject to discuss is the form that the messages take.
Copy file name to clipboardExpand all lines: src/docs/guide/consumingMessages/messages.gdoc
+20Lines changed: 20 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -30,3 +30,23 @@ class DemoService {
30
30
{code}
31
31
32
32
This is a great convenience, but be aware that using serializable Java objects limits the types of client you can interact with. If all the clients you're interested in are using Spring AMQP, then you should be fine, but don't expect Ruby or Python clients to handle @Map@ messages! For production systems, we recommend you use strings and byte arrays.
33
+
34
+
Sometimes you want access to the raw message, particularly if you want to look at the message headers. If so, just change the signature of the @handleMessage()@ method and add an extra option to your @rabbitQueue@ or @rabbitSubscribe@ property:
println "Received message with content type ${msg.contentType};${msg.encoding}"
47
+
...
48
+
}
49
+
}
50
+
{code}
51
+
52
+
As you can see, all you have to do is accept an argument of type @Message@ and add the @messageConverterBean@ option with an empty string as its value. This disables the automatic message conversion, allowing you to interrogate the raw message as required.
Copy file name to clipboardExpand all lines: src/docs/guide/consumingMessages/pubSub.gdoc
+11Lines changed: 11 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -40,3 +40,14 @@ In this example, the service will only receive messages that have a routing key
40
40
41
41
Under the hood, the plugin creates a temporary, exclusive queue for your service which is removed from the broker when your application shuts down. There is no way for you to control the name of the queue or attach another listener to it, but then that's the point in this case. If you do need more control, then you must manage the queues and their bindings yourself.
42
42
43
+
The map syntax also allows you to customise the properties of the Spring message listener container and the corresponding listener adapter (see the section on [advanced configuration|guide:advancedConfig] for more details on these). For example,
44
+
45
+
{code}
46
+
static rabbitSubscribe = [
47
+
name: 'shares',
48
+
routingKey: 'NYSE.GE',
49
+
encoding: "ISO-8859-1",
50
+
prefetchCount: 1]
51
+
{code}
52
+
53
+
will set the encoding and prefetch count for just this service listener. This technique is also possible for straight queue listeners as well.
0 commit comments