Example for worker queue here:
https://www.rabbitmq.com/tutorials/tutorial-two-dotnet.html
In the worker-queue scenario, why are messages published to a Queue, and not an Exchange?
channel.BasicPublish(exchange: "",
routingKey: "task_queue",
basicProperties: properties,
body: body);
Because when you give routing key to "" - nameless exchange (so you actually are always publishing to an exchange), that routing key "is" actually the queue name.
Here is a quote from tutorial 3:
Nameless exchange
In previous parts of the tutorial we knew nothing about exchanges, but
still were able to send messages to queues. That was possible because
we were using a default exchange, which we identify by the empty
string ("").
Recall how we published a message before:
var message = GetMessage(args); var body =
Encoding.UTF8.GetBytes(message); channel.BasicPublish(exchange: "",
routingKey: "hello",
basicProperties: null,
body: body);
The first parameter is the the name of the exchange. The empty string denotes the default or nameless exchange: messages are routed to the queue with the name specified by
routingKey, if it exists.
Related
I have registered receive endpoint in SingleActiveConsumer mode. However I can't find a way to send a message directly to queue by using sendEndpoint. I receive following error:
The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text='PRECONDITION_FAILED - inequivalent arg 'x-single-active-consumer' for queue 'test' in vhost '/': received none but current is the value 'true' of type 'bool'',
I tried setting header "x-single-active-consumer"=true by using bus configurer:
var bus = Bus.Factory.CreateUsingRabbitMq(cfg =>
{
cfg.Host("localhost", "/", h =>
{
h.Username("guest");
h.Password("guest");
});
cfg.ConfigureSend(a => a.UseSendExecute(c => c.Headers.Set("x-single-active-consumer", true)));
});
and directly on sendEndpoint:
await sendEndpoint.Send(msg, context => {
context.Headers.Set("x-single-active-consumer", true);
});
If you want to send directly to a receive endpoint in MassTransit, you can use the short address exchange:test instead, which will send to the exchange without trying to create/bind the queue to the exchange with the same name. That way, you decouple the queue configuration from the message producer.
Or, you could just use Publish, and let the exchange bindings route the message to the receive endpoint queue.
I would like to use micronaut-rabbitmq to send messages between services via topics.
Therefore I've created an exchange, queues and bindings in the ChannelInitializer like this:
channel.exchangeDeclare("registration", BuiltinExchangeType.TOPIC, true)
channel.queueDeclare("user_new", true, false, false, null)
channel.queueBind("user_new", "registration", "user.new.#")
channel.queueDeclare("user_all", true, false, false, null)
channel.queueBind("user_all", "registration", "user.#")
When I try to send a message to the routingkey "user.new" it is not send to any of the queues.
#Binding("user.new")
override fun userCreated(event: UserCreatedEvent)
I would expect, that it is send to both of the queues because of the topics routingkeys.
If I rename the "user_new" queue to "user.new" the message is send to this queue. But as I want to have the message in both queues this is no option.
Any help would be appreciated!
Thank you
My Problem was, that I didn't declare the exchange on the #RabbitClient
After changing #RabbitClient to #RabbitClient("registration") everything works perfectly.
For troubleshooting purpose I want to get list of producers sending messages to a particular queue or exchange. I dont see any option in rabbitmq console to get the above details. Some producers are piling up a paricular queue, I am trying to figure out the IP of producer piling up messages in the queue.
Can any one please guide me on this.
you don't have this information by default, but you can use the message headers to do that.
for example:
string message = "Hello World!";
var body = Encoding.UTF8.GetBytes(message);
var properties = new BasicProperties();
properties.Headers = new Dictionary<string, object>();
properties.Headers.Add("senderip", InetAddress.getLocalHost().getHostAddress());
properties.Headers.Add("custominfo", "info" );
channel.BasicPublish(exchange: "", routingKey: "mykey", basicProperties: properties,body: body);
When you recevice the message you can decode the headers
I'm getting my basicQos ignored when consumer is down and, after, consumer gets up. For instance, suppose that consumer is down and 5 messages arrives from a producer. If consumer is not running, these messages will be stored in disk (I think!) if exchanger/queue is (are) durable.
if I set basicQos as channel.basicQos(0, 3, true), my consumer receives more than 3 messages when it gets UP. Why?!?
On the other hand, everything works properly (only 3 messages are read from the queue) if consumer is running when it receives messages from the queues... My code is as follows:
factory = new ConnectionFactory();
factory.setHost(mRabbitMQHost); //may get server address from file configuration.
factory.setUsername(mRabbitMQUsername);
factory.setPassword(mRabbitMQPassword);
connection = factory.newConnection();
channel = connection.createChannel();
channel.exchangeDeclare("exchangeName", "direct", true); //True enables durability
consumer = new QueueingConsumer(channel);
for (QGQueues queue : QGQueues.values()) {
String queueName = queue.getQueueName();
channel.queueDeclare(queueName, true, false, false, null);
channel.queueBind(queueName, "exchangeName", queue.getRoutingKey());
channel.basicConsume(queueName, false, consumer); //false enables ACK message to RabbitMQ server
}
channel.basicQos(0, 3, true);
Thanks!
My bet would be that you need to set the QoS before you do anything else.
Change your code to this order:
channel = connection.createChannel();
// set QoS immediately
channel.basicQos(0, 3, true);
channel.exchangeDeclare("exchangeName", "direct", true); //True enables durability
consumer = new QueueingConsumer(channel);
for (QGQueues queue : QGQueues.values()) {
String queueName = queue.getQueueName();
channel.queueDeclare(queueName, true, false, false, null);
channel.queueBind(queueName, "exchangeName", queue.getRoutingKey());
channel.basicConsume(queueName, false, consumer); //false enables ACK message to RabbitMQ server
}
this will ensure the prefetch limit is set before you try to consume any messages.
The below code shows how I am setting header and message type to AMQP message.
MessageProperties properties = new MessageProperties();
properties.setHeader("KEY", "HOUSE");
properties.setContentType(MessageProperties.CONTENT_TYPE_JSON);
Message message = new Message("1234567;Branch A;SALES;3000.50;Pending approval".getBytes(), properties);
rabbitTemplate.sendAndReceive("", QUEUE_NAME, message);
After sending the message in the queue, the message is received by Transformer.
#Transformer(inputChannel = "inboundChannel", outputChannel = "toutboundChannel")
public Property buildProperty(Message<String> property){
LOGGER.info("message received :: HEADERS: {}, PAYLOAD :{}", property.getHeaders(), property.getPayload());
....
}
In the logs, the header "KEY: HOUSE" is missing and even the message type is not JSON and "text/plain" instead.
LOGS:
[SimpleAsyncTaskExecutor-1] INFO com.demo.maven.spring.integration.endpoint.TransformerRequestBuilder - message received :: HEADERS: {amqp_receivedRoutingKey=mobile.queue, amqp_deliveryTag=2, amqp_replyTo=amq.rabbitmq.reply-to.g2dkABByYWJiaXRAbG9jYWxob3N0AAAW9QAAAAAD.tTIFOS2gsM7qIlGYaybfrg==, amqp_deliveryMode=PERSISTENT, amqp_redelivered=true, id=399dda4f-4ba1-7cf4-2310-03dbfbac82b6, contentType=text/plain, timestamp=1421649922840}, PAYLOAD :1234567;Branch A;SALES;3000.50;Pending approval
MessagePropertiesBuilder class is for that.
By default Spring Integration AMQP Inbound Endpoint (AmqpInboundChannelAdapter and AmqpInboundGateway) maps only standard AMQP headers. That's is a default behaviour of DefaultAmqpHeaderMapper. To accept any user-specofic headers you should inject AmqpHeaderMapper (setHeaderMapper) to that inbound endpoint with an option setRequestHeaderNames("*"). Or provide full list of names of desired custom headers.
Re. contentType=text/plain: I think something between AMQP Inbound Endpoint and that #Transformer(inputChannel = "inboundChannel" overrides the received from AMQP contentType header. Because RabbitTemplate doesn't do that, if you send Message not any other Object. Please, share DEBUG logs for the org.springframework.integration category for the message receiver. Of course we need that part of logs, when you receive message till that #Transformer
This will work, you have to build the messageproperties correctly.
MessageProperties properties = new MessageProperties();
properties.builder()
.contentType(MediaType.APPLICATION_JSON)
//headers here
.headers(Map<String, Object>)
.build();