Camel RabbitMQ connection using camel amqp - rabbitmq

I am trying to connect to rabbitmq in my camel route using camel-amqp (version 2.17) component.
I have configured it as below :
#Bean
CachingConnectionFactory jmsCachingConnectionFactory(){
JmsConnectionFactory pool = new JmsConnectionFactory();
pool.setRemoteURI("amqp://127.0.0.1:5672");
pool.setUsername("guest");
pool.setPassword("guest");
CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
cachingConnectionFactory.setTargetConnectionFactory(pool);
return cachingConnectionFactory;
}
#Bean
JmsConfiguration jmsConfig(){
JmsConfiguration configuration = new JmsConfiguration();
configuration.setConnectionFactory(jmsCachingConnectionFactory());
// configuration.setCacheLevelName("CACHE_CONSUMER");
return configuration;
}
#Bean
AMQPComponent amqp(){
AMQPComponent component = new AMQPComponent();
component.setConfiguration(jmsConfig());
return component;
}
The error I am getting is
javax.jms.JMSException: An existing connection was forcibly closed by
the remote host
at
org.apache.qpid.jms.exceptions.JmsExceptionSupport.create(JmsExceptionSupport.java:66)
~[qpid-jms-client-0.8.0.jar:0.8.0]
In my rabbitmq log I can see the below message which I am not able to understand
*
** Reason for termination ==
** {function_clause,
[{rabbit_amqp1_0_link_util,'-outcomes/1-lc$^0/1-0-',
[{list,
[{symbol,<<"amqp:accepted:list">>},
{symbol,<<"amqp:rejected:list">>},
{symbol,<<"amqp:released:list">>},
{symbol,<<"amqp:modified:list">>}]}],
[{file,"src/rabbit_amqp1_0_link_util.erl"},{line,49}]},
{rabbit_amqp1_0_link_util,outcomes,1,
[{file,"src/rabbit_amqp1_0_link_util.erl"},{line,49}]},
{rabbit_amqp1_0_outgoing_link,attach,3,
[{file,"src/rabbit_amqp1_0_outgoing_link.erl"},{line,41}]},
{rabbit_amqp1_0_session_process,with_disposable_channel,2,
[{file,"src/rabbit_amqp1_0_session_process.erl"},{line,377}]},
{rabbit_amqp1_0_session_process,handle_control,2,
[{file,"src/rabbit_amqp1_0_session_process.erl"},{line,197}]},
{rabbit_amqp1_0_session_process,handle_cast,2,
[{file,"src/rabbit_amqp1_0_session_process.erl"},{line,134}]},
{gen_server2,handle_msg,2,[{file,"src/gen_server2.erl"},{line,1049}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,240}]}]}
=ERROR REPORT==== 8-Jul-2016::17:09:27 ===
closing AMQP connection <0.29082.0> (127.0.0.1:55479 -> 127.0.0.1:5672):
{handshake_error,running,<0.29104.0>,
{{symbol,<<"amqp:internal-error">>},
"Session error: ~p~n~p~n",
[function_clause,
[{rabbit_amqp1_0_link_util,'-outcomes/1-lc$^0/1-0-',
[{list,
[{symbol,<<"amqp:accepted:list">>},
{symbol,<<"amqp:rejected:list">>},
{symbol,<<"amqp:released:list">>},
{symbol,<<"amqp:modified:list">>}]}],
[{file,"src/rabbit_amqp1_0_link_util.erl"},{line,49}]},
{rabbit_amqp1_0_link_util,outcomes,1,
[{file,"src/rabbit_amqp1_0_link_util.erl"},{line,49}]},
{rabbit_amqp1_0_outgoing_link,attach,3,
[{file,"src/rabbit_amqp1_0_outgoing_link.erl"},{line,41}]},
{rabbit_amqp1_0_session_process,with_disposable_channel,2,
[{file,"src/rabbit_amqp1_0_session_process.erl"},{line,377}]},
{rabbit_amqp1_0_session_process,handle_control,2,
[{file,"src/rabbit_amqp1_0_session_process.erl"},{line,197}]},
{rabbit_amqp1_0_session_process,handle_cast,2,
[{file,"src/rabbit_amqp1_0_session_process.erl"},{line,134}]},
{gen_server2,handle_msg,2,[{file,"src/gen_server2.erl"},{line,1049}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,240}]}]]}}
*
I have enabled amqp_1_0 plugin in rabbitmq.
Can someone help me resolve this.

This seems a bug in rabbitmq amqp 1.0 plugin. An issue has been logged with rabbitmq.
https://github.com/rabbitmq/rabbitmq-amqp1.0/issues/31

Related

Java Spring Stomp AMQP

I have three project:
Javascript SockJS STOMP client
Spring-boot STOMP endpoint and AMQP
Spring-boot AMQP (RabbitListener) client for testing
I am using RabbitMQ message broker (+Stomp plugin) and configured amqp and stomp endpoint normally..When I send message to queue with RabbitTemplate and third project (spring-boot amqp client for testing) normally subscribed this message , everything works fine !! But Javascript STOMP client didn't received this message..
P.S. When I send message with SimpMessagingTemplate , JS client receives message fine !
Javascript SockJS STOMP Client
var socket = new SockJS('http://localhost:8090/hello');
stompClient = Stomp.over(socket);
stompClient.connect('guest','guest', function(frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/testqueue', function(greeting){
showGreeting(JSON.parse(greeting.body).content);
});
});
spring-boot STOMP endpoint and AMQP
#Controller
public class SampleController {
Logger logger = Logger.getLogger(SampleController.class);
#Autowired
private RabbitTemplate rabbitTemplate;
private SimpMessagingTemplate messagingTemplate;
#Autowired
public SampleController(SimpMessagingTemplate messagingTemplate) {
this.messagingTemplate = messagingTemplate;
}
#GetMapping("/emit/{message}")
#ResponseBody
String queue1(#PathVariable("message") String message) throws Exception {
logger.info("Emit to testqueue");
rabbitTemplate.convertAndSend("/topic/testqueue", new Greeting("Salam olsun " + message));
Thread.sleep(60000); // simulated delay
return "Emit to testqueue";
}
}
spring-boot amqp client for testing
#Component
public class RabbitMqListener {
Logger logger = Logger.getLogger(RabbitMqListener.class);
#RabbitListener(queues = "/topic/testqueue")
public void processQueue1(String message) {
logger.info("Received from queue : " + message);
}
}
How I can mix amqp and stomp protocols in RabbitMQ ? I want to send message from another project with amqp protocol (RabbitTemplate) and receive this message from JS STOMP client (SockJS) .. Thanks.
I was changed rabbitTemplate.convertAndSend("/topic/testqueue", ...) to rabbitTemplate.convertAndSend("amq.topic","testqueue" ...) and everythink works fine ))) Especially thanks to Artem Bilan for support. Good Luck

Spring AMQP Inbound Adapter with empty queue name

I'm developing a consumer application using Spring AMQP that receives messages from RabbitMQ. There is a topic exchange declared. To connect to Rabbit I create a queue with an empty name, because the broker will provide an automatic queue name, see the InterCor M4 Upgraded Specifications Hybrid specifications:
#Bean
public TopicExchange exchange() {
TopicExchange topicExchange = new TopicExchange(topicExchangeName);
topicExchange.setShouldDeclare(false);
return topicExchange;
}
#Bean
public Queue queue() {
return new Queue("", queueDurable, queueExclusive, queueAutoDelete, queueParameters);
}
#Bean
public Binding binding(Queue queue, TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(routingKey);
}
But when I try to configure an AMQP Inbound Channel Adapter using the Spring Integration Java DSL:
#Autowired
private Queue queue;
#Bean
public IntegrationFlow amqpInbound(ConnectionFactory connectionFactory) {
return IntegrationFlows.from(Amqp.inboundAdapter(connectionFactory, queue))
.handle(m -> System.out.println(m.getPayload()))
.get();
}
I get an error 'queueName' cannot be null or empty
2018-05-25 13:39:15.080 ERROR 14636 --- [erContainer#0-1] o.s.a.r.l.SimpleMessageListenerContainer : Failed to check/redeclare auto-delete queue(s).
java.lang.IllegalArgumentException: 'queueName' cannot be null or empty
at org.springframework.util.Assert.hasText(Assert.java:276) ~[spring-core-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.amqp.rabbit.core.RabbitAdmin.getQueueProperties(RabbitAdmin.java:337) ~[spring-rabbit-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.redeclareElementsIfNecessary(AbstractMessageListenerContainer.java:1604) ~[spring-rabbit-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:963) [spring-rabbit-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_162]
How can I set a value of the message queue name to an empty string?
That is not a good solution.
The problem is that with a broker-generated queue name, if the connection is lost and re-established, the queue name will change, but the container won't know about the new queue and will try to consume from the old one.
AnonymousQueue solves this problem by the framework generating the random name.
But, anonymous queues are not durable, are exclusive and are auto-delete.
If you want a Queue with different properties to that, but still want a random name, use
#Bean
public Queue queue() {
return new Queue(new AnonymousQueue.Base64UrlNamingStrategy().generateName(),
queueDurable, queueExclusive, queueAutoDelete, queueParameters);
}
That way, if the connection is lost and re-established, the queue will get the same name.
The AMQP-816 issue has been fixed and now is available in Spring Boot 2.1.0.
Updating the parent of the project fixes the issue:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
</parent>
Empty queue name
spring:
rabbitmq:
queue:
name:
durable: false
exclusive: true
autoDelete: true
creates an automatic queue name amq.gen-U1vKiSfIvy8bO11jLD29Sw:
Non-empty queue name
spring:
rabbitmq:
queue:
name: abc
durable: false
exclusive: true
autoDelete: true
creates a queue named abc:

Spring AMQP client hangs

There is a behavior in RabbitMQ server that it will not accept subsequent connections / operations when it reaches to watermark value till the time it rebalances itself.
RabbitMQ client elegantly gets timeout when such situations happen after the connection timeout , But we are using Spring AMQP it continues to hang.
Steps to Reproduce
o Create a RabbitMQ HA cluster
o Create a simple program which produces and consumes message
a) Using Spring AMQP
b) Using RabbitMQ client
o Make RabbitMQ server reach high watermark value in memory so that it cannot accept any new connections or perform any operations say for 10 min
o Create Q, Send message from
a) Spring AMQP ( It will hang )
b) RabbitMQ client ( It will get timeout ) say after 1 min if connection timeout is being set as 1 min.
Spring Binaries Version
a) spring-rabbit-1.6.7.RELEASE.jar
b) spring-core-4.3.6.RELEASE.jar
c) spring-amqp-1.6.7.RELEASE.jar
We tried upgrading to Spring Rabbit and AMQP 2.0.2 version as well , But it didn’t helped.
You don't describe what your "RabbitMQ Client" is, but the java amqp-client uses classic Sockets by default. So you should get the same behavior with both (since Spring AMQP uses that client). Perhaps you are referring to some other language client.
With java Sockets, when the connection is blocked, the thread is "stuck" in socket write which is not interruptible, nor does it timeout.
To handle this condition, you have to use the 4.0 client or above and use NIO.
Here is an example application that demonstrates the technique.
#SpringBootApplication
public class So48699178Application {
private static Logger logger = LoggerFactory.getLogger(So48699178Application.class);
public static void main(String[] args) {
SpringApplication.run(So48699178Application.class, args);
}
#Bean
public ApplicationRunner runner(RabbitTemplate template, CachingConnectionFactory ccf) {
ConnectionFactory cf = ccf.getRabbitConnectionFactory();
NioParams nioParams = new NioParams();
nioParams.setWriteEnqueuingTimeoutInMs(20_000);
cf.setNioParams(nioParams);
cf.useNio();
return args -> {
Message message = MessageBuilder.withBody(new byte[100_000])
.andProperties(MessagePropertiesBuilder.newInstance()
.setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT)
.build())
.build();
while (true) {
try {
template.send("foo", message);
}
catch (Exception e) {
logger.info(e.getMessage());
}
}
};
}
#Bean
public Queue foo() {
return new Queue("foo");
}
}
and
2018-02-09 12:00:29.803 INFO 9430 --- [ main] com.example.So48699178Application : java.io.IOException: Frame enqueuing failed
2018-02-09 12:00:49.803 INFO 9430 --- [ main] com.example.So48699178Application : java.io.IOException: Frame enqueuing failed
2018-02-09 12:01:09.807 INFO 9430 --- [ main] com.example.So48699178Application : java.io.IOException: Frame enqueuing failed

Delay message to send to listener using Spring AMQP

I have a requirement to send message to MessageListener after certain duration , So is there any way to achieve using Spring AMQP.
Eg .
Producer produces the message and message goes to RabbitMQ Q , The message gets received Listener listening to that Q immediately, I want to delay that message to be received at consumer side say after some configuration parameter say 1000ms
The RabbitMQ provides for this purpose Delayed Exchange feature.
Starting with version 1.6 Spring AMQP also provides a high level API on the matter: http://docs.spring.io/spring-amqp/reference/html/_reference.html#delayed-message-exchange:
<rabbit:topic-exchange name="topic" delayed="true" />
MessageProperties properties = new MessageProperties();
properties.setDelay(15000);
template.send(exchange, routingKey,
MessageBuilder.withBody("foo".getBytes()).andProperties(properties).build());
UPDATE
Before Spring AMQP 1.6 you should do like this:
#Bean
CustomExchange delayExchange() {
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-delayed-type", "direct");
return new CustomExchange("my-exchange", "x-delayed-message", true, false, args);
}
...
MessageProperties properties = new MessageProperties();
properties.setHeader("x-delay", 15000);
template.send(exchange, routingKey,
MessageBuilder.withBody("foo".getBytes()).andProperties(properties).build());
Also see this question and its answer: Scheduled/Delay messaging in Spring AMQP RabbitMq
If you use spring boot, it can be like this:
#Bean
Queue queue() {
return QueueBuilder.durable(queueName)
.withArgument("x-dead-letter-exchange", dlx)
.withArgument("x-dead-letter-routing-key", dlq)
.build();
}
#Bean
TopicExchange exchange() {
return (TopicExchange) ExchangeBuilder.topicExchange(topicExchangeName)
.delayed()
.build();
#Bean
Binding binding() {
return BindingBuilder.bind(queue()).to(exchange()).with(queueName);
}

ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN

I have installed "erlang" and "rabbitmq" in my windows 7 machine. But when I am trying to run this code I am getting One exception.
package com.rabbitmq;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class SendMessage {
private final static String QUEUE_NAME = "hello";
public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
String message = "Hello World!";
channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));
System.out.println(" [x] Sent '" + message + "'");
channel.close();
connection.close();
}
}
I am getting this Exception.
Exception in thread "main" com.rabbitmq.client.AuthenticationFailureException: ACCESS_REFUSED -
Login was refused using authentication mechanism PLAIN. For details
see the broker logfile.
This is the log:
11-Apr-2016::12:45:06 === Adding vhost 'localhost'
=INFO REPORT==== 11-Apr-2016::14:08:52 === accepting AMQP connection <0.360.0> (127.0.0.1:55327 -> 127.0.0.1:5672)
=ERROR REPORT==== 11-Apr-2016::14:08:52 === Error on AMQP connection <0.360.0> (127.0.0.1:55327 -> 127.0.0.1:5672, state: starting):
=INFO REPORT==== 11-Apr-2016::14:08:52 === closing AMQP connection <0.360.0> (127.0.0.1:55327 -> 127.0.0.1:5672)
When I am trying to list the users I am not getting any existing user and add_user is also not working in cmd link
In your ConnectionFactory you need to set your username and password, if your have created any or you can use the default user "guest" with password "guest", which can be accessible only from localhost.
you can create new user (userA) and password (userA123).
And set
factory.setHost("your_pc_ip");
factory.setUsername("userA");
factory.setPassword("userA123");
in sender and receiver classes.