I have ActiveMQ persistent queue and due to performance i'm publishing to producer using async mode.
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerURL);
factory.setUseAsyncSend(true);
PooledConnectionFactory connectionFactory = new PooledConnectionFactory(factory);
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProduer producer = session.createProducer(destination);
Queue queue = session.createQueue(qName);
producer.send(queue, message);
Is there a way to register handler to get the error/success of producer.send() method ?
Seems like jms 1.1 specification does not allow to register call back in send method and jms 2.0 allows it ( http://www.oracle.com/technetwork/articles/java/jms2messaging-1954190.html ). Since ActiveMq based on jms 1.1 there's no standard way to register callback. However ActvieMQ javax.jms.MessageProducer implementation org.apache.activemq.ActiveMQMessageProducer allows to register callback and I used that to create my solution ( but unfortunately i had to abandon PooledConnectionFactory because there was no way to get org.apache.activemq.ActiveMQMessageProducer from PooledConnectionFactory approach.
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerURL);
factory.setUseAsyncSend(true);
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProduer producer = session.createProducer(destination);
Queue queue = session.createQueue(qName);
((ActiveMQMessageProducer)producer).send(queue, message, new AsyncCallback() {
#Override
public void onSuccess() {
}
#Override
public void onException(JMSException exception) {
}
};);
Related
As Jedis documentation state that Jedis client is not thread-safe.
A single Jedis instance is not threadsafe!
So I am using JedisPool. I want to push data to browser's WebSocket client from server. For this I am using Redis's PubSub mechanism.
#ServerEndpoint(value = "/websocket/{channelName}", configurator = GetHttpSessionConfigurator.class)
public class WSEndpoint {
private WSJedisPubSub wsJedisPubSub;
private static JedisPool jedisPool = null;
#OnOpen
public void onOpen(Session session,
#PathParam("channelName") String channelName) throws IOException,
EncodeException {
// FIXME proper synchronization is required here
if (jedisPool == null) {
initPool();
}
wsJedisPubSub = new WSJedisPubSub(session);
try (Jedis redisClient = jedisPool.getResource()) {
redisClient.subscribe(wsJedisPubSub, channelName);
}
private void initPool() {
JedisPoolConfig jedisConfiguration = new JedisPoolConfig();
jedisPool = new JedisPool(jedisConfiguration, "localhost", 6379);
}
}
full code
My application can have thousands of websockets connected to it. I have doubts about following piece of code.
try (Jedis redisClient = jedisPool.getResource()) {
redisClient.subscribe(wsJedisPubSub, channelName);
}
This redisClient should get close after try-with-resouce block, but still it is working(getting subscribed events). How ?
By default, pool size is 8. I can set to n but eventually I will have n+1 web sockets. What is the best way to deal with this ? Should I have only one Jedis instance and do the routing of message by myself ?
If Jedis client gets disconnected, then what is the recommended way for reconnect here ?
I have a separate publisher and consumer.I start publisher and publish messages.Now i start consumer and problem is that the messages move from ready queue to unack queue marking the messages as redelivered which i want to avoid.So what i want is it should be marked as redelivered only if i send ack and not on consumer restart or start
Configuration :
#Bean
public org.springframework.amqp.rabbit.connection.Connection mqConnection() {
CloudFactory cloudFactory = new CloudFactory();
Cloud cloud = cloudFactory.getCloud();
return cloud.getServiceConnector("mqservicename", ConnectionFactory.class,
null).createConnection();
}
#Bean
public StatefulRetryOperationsInterceptor interceptor() {
return RetryInterceptorBuilder.stateful().retryOperations(retryTemplate()).recoverer(new RejectAndDontRequeueRecoverer())
.build();
}
#Bean
public SimpleMessageListenerContainer listenerContainer() {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setMessageListener(new MessageListenerAdapter());
container.setAdviceChain(new Advice[] {
interceptor()
});
return container;
}
#Bean
public RetryTemplate retryTemplate(){
Map map=new HashMap<Class<? extends Throwable>, Boolean>();
map.put(CustomException.class, true);
RetryTemplate retryTemplate=new RetryTemplate();
retryTemplate.setRetryPolicy(new SimpleRetryPolicy(3,map));
return retryTemplate;
}
If you are using Spring AMQP, you need to show your configuration when asking questions like this.
If you set the ack mode to MANUAL, you are responsible for the acks. Read the documentation. For AUTO ackmode, the container will ack the message when the listener returns normally.
I have a program in Java that sends messages to RabbitMQ. All I know is the exchange name. No queues, bindings, and so on.
My question is this: how can I see if the program sends these successfully, knowing only the exchange name?
Thanks.
Regards,
Serban
You can enable publisher confirmation with RabbitMQ. It's like having a send-transaction, where RabbitMQ will tell you whether or not the message was sent successfully.
Assume that we have RabbitMQ Exchange we need to create an queue to push the message to the exchange and consume it from the queue as following
private static final String EXCHANGE_NAME = "2022";
private static final String QUEUE_NAME = "2022";
private final static boolean durable = true;
// now we need to create a connection to rabbitmq server //
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername("guest");
factory.setPassword("guest");
factory.setVirtualHost("/");
factory.setHost("127.0.0.1");
factory.setPort(5672);
Connection conn = factory.newConnection();
// create rabbitmq connection chaneel
Channel channel = conn.createChannel();
//Declare Exchange //
channel.exchangeDeclare(EXCHANGE_NAME, "topic", true);
// push message to rabbitmq exchange
channel.basicPublish(EXCHANGE_NAME, "routingkey", null, yourmessage.getBytes());
the above work as producer now we need to create queue consumer
private static final String EXCHANGE_NAME = "2022";
private static final String QUEUE_NAME = "2022";
private final static boolean durable = true;
// now we need to create a connection to rabbitmq server //
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername("guest");
factory.setPassword("guest");
factory.setVirtualHost("/");
factory.setHost("127.0.0.1");
factory.setPort(5672);
Connection conn = factory.newConnection();
// create rabbitmq connection chaneel
Channel channel = conn.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "topic", true);
//Queue Declare //
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
//Queue bind //
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "routingkey");
// Queue Consume //
QueueingConsumer consumer = new QueueingConsumer(channel);
while (true)
{
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
System.out.println(" [x] Received '" + message + "'");
}
Please look here: https://www.rabbitmq.com/tutorials/tutorial-three-java.html
String queueName = channel.queueDeclare().getQueue();
channel.queueBind(queueName, "EXCHANGE_NAME", "");
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
Consumer consumer = new DefaultConsumer(channel) {
#Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException
{
String message = new String(body, "UTF-8");
System.out.println(" [x] Received '" + message + "'");
}
};
channel.basicConsume(queueName, true, consumer);
In a few words, you have to:
create a queue, in this case anonymous queue
bind the queue to your exchange
It is important to know what kind of the exchange you have since the binding can change, between fanout or topic or direct
In this example is fanout
I went through the API of RabbitTemplate. It provides only receive method which gets the message from queue. However there is no way to get a message with a particular correlation id. Can you please help me understand what I am missing here.
Currently, I am using JMS API's from ActiveMQ to receive messages using the following code which createConsumer with message selector. Looking to do the same with Spring AMQP with RabbitMQ:
private ObjectMessage receiveMessage(final String readQueue, final UUID correlationId, final boolean isBroadcastMessage, final int readTimeout) throws JMSException
{
final ActiveMQConnectionFactory connectionFactory = this.findConnectionFactory(readQueue);
Connection connection = null;
Session session = null;
MessageConsumer consumer = null;
ObjectMessage responseMessage = null;
try
{
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue(readQueue);
consumer = session.createConsumer(destination, "correlationId = '" + correlationId + "'");
final Message message = consumer.receive(readTimeout);
}
finally
{
if (consumer != null)
{
consumer.close();
}
if (session != null)
{
session.close();
}
if (connection != null)
{
connection.close();
}
}
return responseMessage;
}
You are using a messageSelector string in JMS; RabbitMQ/AMQP does not have an equivalant.
Instead, each consumer gets its own queue and you use a direct or topic exchange in the broker to do the routing. I suggest you take a look at the tutorials on the rabbitmq web site and topics.
If you are using the correlationId for request/reply processing, consider using the inbuilt sendAndReceive or convertSendAndReceive methods in the template. See the reference documentation for more information.
We are trying to make asynchronous call in RabbitMQ using Spring AMQP, could any one please tell me how to configure replyqueue, correlationId, (properties) using spring amqp?
String corrId = java.util.UUID.randomUUID().toString();
BasicProperties props = new BasicProperties
.Builder()
.correlationId(corrId)
.replyTo(replyQueueName)
.build();
channel.basicPublish("", requestQueueName, props, message.getBytes());
I assume you need to use RabbitTemplate:
rabbitTemplate.convertAndSend(requestQueueName, myObj, new MessagePostProcessor() {
Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setReplyTo(replyQueueName);
return message;
}
}, new CorrelationData(corrId));
HTH