I am new to Spring cloud and RabbitMQ.
I am trying to produce and consume messages from Rabbit MQ.
I am having difficulty in configuring exchange name and queue name for producer and consumer.
I want to connect to the existing exchange called to order and the existing queue called myQueue
Below is the application.properties
spring.rabbitmq.addresses=amqp://user:pass#localhost:5672/
spring.cloud.stream.function.bindings.processTable-out-0=order
spring.cloud.stream.function.bindings.processTable-in-0=order
spring.cloud.stream.bindings.order.group=myQueue
spring.cloud.stream.bindings.order.content-type=application/json
Above configuration is connecting to order exchange, however, it is creating and connecting a new queue called order.myQueue.
The consumer method is below.
#Bean
public Consumer<String> processTable(){
log.info("Conuming message......................");
Consumer<String> consumer = (request)-> System.out.println(request);
System.out.println(consumer);
return consumer;
}
What do I need to tweak in application.properties to connect to order exchange and myOrder queue?
See Using Existing Queues/Exchanges.
If you have an existing exchange/queue that you wish to use, you can completely disable automatic provisioning as follows, assuming the exchange is named myExchange and the queue is named myQueue:
spring.cloud.stream.bindings..destination=myExchange
spring.cloud.stream.bindings..group=myQueue
spring.cloud.stream.rabbit.bindings..consumer.bindQueue=false
spring.cloud.stream.rabbit.bindings..consumer.declareExchange=false
spring.cloud.stream.rabbit.bindings..consumer.queueNameGroupOnly=true
Related
In Cloud Stream for RabbitMQ I want to set a consumer that will consume from a Queue only the messages that have been forwarded with a specific routing key. Is this possible?
Here are my application.properties.
Producer:
spring.cloud.stream.rabbit.bindings..consumer.bindQueue=false
spring.cloud.stream.rabbit.bindings..consumer.declareExchange=false
spring.cloud.stream.bindings.producer1-out-0.destination=exchange1
spring.cloud.stream.rabbit.bindings.producer1-out-0.producer.routingKeyExpression='routing.key.1'
Consumer:
spring.cloud.stream.rabbit.bindings..consumer.bindQueue=false
spring.cloud.stream.rabbit.bindings..consumer.declareExchange=false
spring.cloud.stream.bindings.consumer1-in-0.destination=exchange1
spring.cloud.stream.bindings.consumer1-in-0.group=reports
spring.cloud.stream.rabbit.bindings.consumer1-in-0.consumer.queueNameGroupOnly=false
spring.cloud.stream.rabbit.bindings.consumer1-in-0.consumer.bindingRoutingKeyDelimiter=,
spring.cloud.stream.rabbit.bindings.consumer1-in-0.consumer.bindingRoutingKey='routing.key.1'
Exchanges and bindings are defined directly in RabbitMQ.
My expectation was if I change spring.cloud.stream.rabbit.bindings.consumer1-in-0.consumer.bindingRoutingKey to something else the consumer will stop consuming but it's not the case.
No; unlike JMS, RabbitMQ has no concept of a message selector; you will get all messages.
The canonical way to solve this issue is to use a different queue for each RK.
bindingRoutingKey is meaningless when bindQueue is false and, in any case, all it does is specify which routing key to use when binding the queue to the exchange.
I'm new in rabbitmq.I'm using spring-amqp to implement the feature.
As we know spring provide #RabbitListener to register a listener to queue when the app initialization.
I want to design a function when I click some button, a new consumer will be created and listen to a specified queue.
Java base provide channel.basicConsume() method to consume a queue.
Is spring provide such function ?
I want to implement like :
producer keep sending messages to a fanout exchange.
when a consume wants to join, call function1 -> create queue and binding to exchange -> consume messages.
when a consume wants leave, call function2 -> disconnect
There are a few options.
Use one of the RabbitTemplate.receive() or convertAndReceive() methods to get messages one-at-a-time, you can set a receiveTimeout in case there are no messages.
RabbitTemplate.execute() with a callback that gets a channel that you can call basicConsume() on. This is a lower-level option and won't do any conversion for you.
Create a SimpleMessageListenerContainer (or DirectMessageListenerContainer) dynamically and start/stop it as needed.
...
In all cases, you can use a RabbitAdmin to create/bind the queue, for all except option 1, it would probably an auto-delete queue that will be removed when the consumer is cancelled. With option 1, you would have to use a non-auto-delete queue and remove it with the RabbitAdmin.
I would suggest that #3 is the most efficient using pure Spring AMQP.
You could also use Spring Integration with an inbound channel adapter and a publish-subscribe channel; that way you only need one queue (per application instance) and then subscribe a new MessageHandler to the channel for each user.
I use rabbitmq as the middleware in cloud stream ,when I configure the application.yml
spring:
cloud:
stream:
bindings:
usertest: #channelName
content-type: application/json
group: testGroup
destination: topic888 #destination,
binder: rabbit1
I can't understand the key meaning of destination.
official definition is :
destination
The target destination of a channel on the bound middleware (e.g., the RabbitMQ exchange or Kafka topic). If the channel is bound as a consumer, it could be bound to multiple destinations and the destination names can be specified as comma separated String values. If not set, the channel name is used instead.
Also,I found when consumer and producer have different destinations , It did't stop consumer from consuming.
The destination depends on the binder type. For kafka, it's the topic; for RabbitMQ, it's an exchange.
The producer publishes to the exchange.
The consumer binds a queue to the exchange. Anonymous consumers bind a temporary, auto-delete queue, consumers with a group bind a queue called topic888.testGroup in your case (destination.group).
Also,I found when consumer and producer have different destinations , It did't stop consumer from consuming.
I don't see how that's possible, with the binder doing the provisioning, for the reasons discussed above.
It's possible if you manually bind a queue with the correct name to a different exchange that the producer is publishing to.
I am trying to connect from my Android app to one queue called "messages".
The producer (one webservices under AMQP protocol) is already connected, it can be check through RabbitMQ admin panel.
To connect from my Android device I am coding like this.
private void connect() throws Exception {
this.sampleClient = new MqttClient(this.broker, this.clientId);
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setUserName("user");
connOpts.setPassword("user".toCharArray());
/*connOpts.setConnectionTimeout(60 * 10);
connOpts.setKeepAliveInterval(60 * 5);*/
connOpts.setCleanSession(true);
this.sampleClient.connect(connOpts);
this.sampleClient.setCallback(this);
this.sampleClient.subscribe("messages");
if(!this.sampleClient.isConnected()){
System.out.println("Not Connected");
return;
}
System.out.println("Connected");
}
I have tried with "amq.topic", "amq.topic.*", "amq.topic.messages", etc... But when I look in the RabbitMQ queue section "messages" is with 0 consumers, and have been set one new queue called "mqtt-subscription-Sampleqos1" automatically.
What's happening? How can I susbscribe to "messages" queue?
There are two important points about this question.
According with the RabbitMQ MQTT documentation: http://www.rabbitmq.com/mqtt.html
Firstly, every queues are bound automatically to amq.topic exchange by the mqtt-plugin.
Secondly, every subscriber has his own queue which look like this, mqtt-subscription-{cliend_id}{qosX} (where X is the qos level of the subscription)
Therefore, producer must to publish the message to "amq.topic" exchange, and "amq.topic.." routing-key, and receiver must to subscribe to "amq.topic.." routing-key.
First, make sure MQTT plugin is enabled: rabbitmq-plugins enable rabbitmq_mqtt
From the client side (here is you Android app), you need subscriber to a topic, lets say, topic my/android/app/messages
this.sampleClient.subscribe("my/android/app/messages");
Then, from the server side, because of RabbitMQ's implementation, you need send the message to a special exchange 'amq.topic' with appropriate route key my.android.app.messages (notice the mapping between '/' and '.', MQTT use / and AMQP use .). For example if you publish by pika AMQP Python lib, the code will looks like following:
channel.basic_publish(
exchange='amq.topic',
routing_key='my.android.app.messages',
body='hello world'
)
In your case, you want to receive message from queue "messages", basically there is no way to directly subscriber message from that AMQP queue on your MQTT client. The work around is create a service running on your server side, work as AMQP subscriber, receive message from "messages" queue, and transparent forward message to exchange amq.topic with proper routing key.
Hope my answer helpful.
Using a SimpleMessageListenerContainer that is attached to multiple queues and configured with a ChannelAwareMessageListener. Is it possible to determine which queue a message has been consumed from? In particular if the message was routed to the queue from an Exchange.
It looks that if a message is sent directly to a queue that the MessageProperties#getReceivedRoutingKey will contain the queue name but if the message is routed to a queue via an Exchange then this information contains the routing key that was used.
I'm looking for a mechanism that would allow this information to be extracted correctly regardless of how the message was delivered to the queue. Or a mechanism to enrich the information with a header containing this information on the RabbitMQ side.
I had a similar issue where I wanted to add the queue name to slf4j MDC context.
The only solution I have found is to subclass SimpleMessageListenerContainer and set a ThreadLocal variable for the queue name or in my case the MDC context (which is basically threadlocals).
Because SimpleMessageListenerContainer still doesn't know exactly which queue (you can bind multiple queues to a container) you will have to allow only single queue per container which in my opinion is what you should do regardless.
In my companies own code base we have a magical SimpleMessageListenerContainerFactory that does the creation of custom SimpleMessageListenerContainer based on routing annotations (think spring mvc #RequestMapping for amqp). If there is interest perhaps we can expedite opensourcing it.