Ruby AMQP persistent message is deleted after restarting RabbitMQ - ruby

I have a ruby script that creates a message using AMQP in RabbitMQ.
# above code sets up config for connecting to RabbitMQ via APMQ
AMQP.start(:host => 'localhost') do
amq = MQ.new
amq.queue('initiate', :durable => true).publish(message_id, :persistent => true)
AMQP.stop{ EM.stop }
end
If the RabbitMQ server is restarted, the message is no longer in the initiate queue (or any queue, for that matter). What am I doing wrong that the message is not persistent? I've also tried explicitly creating a durable exchange, and binding the queue to that exchange, but the message is still deleted after RabbitMQ restart.

As already mentioned, if you just mark messages as persistent they will not necessarily get persisted straight away, so if the server shuts down unexpectedly they may never end up on disk.
So what do you do if you really need the message to be on disk, even if the server crashes?
There are two things you can do. One is to wrap your publish in a transaction. When you have committed the transaction, the message will be on disk (if it's not already delivered to a consumer of course). However, this adds a synchronous call to the server, so it can slow you down. If you know you're going to publish a lot of messages, you can wrap a bunch of publishes in a transaction, then when you commit you know they're all on disk.
The other (higher performance) alternative is to use publish confirms. But these are new in the 2.3.1 server and I don't think any Ruby clients support them yet.
Finally, RabbitMQ will anyway periodically flush persistent messages to disk even in the absence of confirms, transactions and controlled shutdowns. However there's a bug in 2.2.0 which means that this sometimes doesn't happen for a long time, so upgrading to 2.3.1 might be worthwhile.

Funny I was just Googling for the same problem. RabbitMQ 2.2.0, default options. In my case, Ruby clients using rubygem-amqp-0.6.7-3.el5 from EPEL. Durable queues bound to Durable fanout exchange, publishing messages with :persistent => true. Messages lost on server restart.
-Alan

Yes, Simon is right. About publisher confirms (described at http://www.rabbitmq.com/blog/2011/02/10/introducing-publisher-confirms), I plan to support them in AMQP 0.8 which shall be released soon.
BTW, in the original example, the first argument for publish is supposed to be the actual data, everything else is specified via options, so it's publish(message, opts) rather than publish(message_id, opts).

Related

RabbitMQ/Spring AMQP - Leave message in a queue

I created a SpringBoot/Spring AMQP project where I configured a listener on a RabbitMQ queue. Question: Is there any way to leave the message in the queue? Let me explain: I consume the message and do some things (eg save on db), if something goes wrong I would like to be able to reconsume the message.
Thanks in advance
You need to think about configuring your listener container with transactions, so when DB call fails, the transaction is going to be rolled back and an AMQP message will not be acked on RabbitMQ.
See docs for more info: https://docs.spring.io/spring-amqp/docs/current/reference/html/#transactions
I don't know about the "Spring" way of accomplishing this, but what you describe is the normal behavior for AMQP consumers that do not automatically acknowledge.
From the documentation:
In automatic acknowledgement mode, a message is considered to be successfully delivered immediately after it is sent.
When you turn off automatic acknowledgment, your consumer must explicitly acknowledge the message, otherwise it will not be dequeued (or as you put it, it will be left "in the queue"). You will then need to simply ACK the message at the very end of your operation, when you are certain that your operation succeeded (and perhaps coordinated with your database transaction).
There is always the question of what to do first; acknowledge first or commit your database transaction first? Without adding complexity, you must choose what's best depending on what failure mode is less problematic for you, i.e. Would you rather tolerate a duplicated message or a missing message?

Allow rabbitmq to process current running message before shutdown

My application is spring boot micro service listening to a Rabbit MQ queue.
The queue receives messages from different sources.
The requirement is that when the application server is going down (this could happen because of many reasons, may be because we brought the site down, or we are deploying an updated software on to our application server) we would like the queue to process the current message. As of now, we lose the message that the queue is currently processing.
How can I achieve this?
The default shutdownTimeout is 5000ms; you can increase it.
You should not, however, lose any messages, it should be requeued (unless you are using AcknowledgeMode.NONE (which is generally a bad idea).

Two consumers on same Websphere MQ JMS Queue, both receiving same message

I am working with someone who is trying to achieve a load-balancing behavior using JMS Queues with IBM Websphere MQ. As such, they have multiple Camel JMS consumers configured to read from the same Queue. Despite that this behavior is undefined according to the JMS spec (last time I looked anyway), they expect a sort of round-robin / load-balancing behavior. And, while the spec leaves this undefined, I'm led to believe that the normal behavior of Websphere MQ is to deliver the message to only one of the consumers, and that it may do some type of load-balancing. See here, for example: When multi MessageConsumer connect to same queue(Websphere MQ),how to load balance message-consumer?
But in this particular case, it appears that both consumers are receiving the same message.
Can anyone who is more of an expert with Websphere MQ shed any light on this? Is there any situation where this behavior is expected? Is there any configuration change that can alleviate this?
I'm leaning towards telling everyone here to use the native Websphere MQ clustering facility and go away from having multiple consumers pointing at the same Queue, but that will be a big change for them, so I'd love to discover a way to make this work.
Not that I'm a fan of relying on anything that's undefined, but if they're willing to rely on IBM specific behavior, I'll leave that up to them.
The only way for them to both receive the same messages are:
There are multiple copies of the message.
The apps are browsing the message without a lock, then circling back to delete it.
The apps are backing out a transaction and making the message available again.
The connection is severed before the app acknowledges the message.
Having multiple apps compete for messages in a queue is a recommended practice. If one app goes down the queue is still served. In a cluster this is crucial because the cluster will continue to direct messages to the un-served queue instance until it fills up.
If it's a Dev system, install SupportPac MA0W and tell it to trace just that one queue and you will be able to see exactly what is happening.
See the JMS spec in section 4.4. The provider must never deliver a second copy of an acknowledged message. Exception is made for session handling in 4.4.13 which I cover in #4 above. That's pretty unambiguous and part of the official spec so not an IBM-specific behavior.

JMS durable subscriber persistent messages don't persist to the database

I am using weblogic 10.3 .
I am trying to configure a durable subscription with persistent messaged backed by a jdbc store (in Oracle DB). I have a topic to which an MDB is listening as a durable subscriber.
Under scenario-1 : If I send the message, it hits the MDB.
Under scenario-2 : I suspend the MDB hoping that the messages send to the topic will stay around as long as they don’t get consumed by the MDB (which is the only registered durable subscriber). But when I do send the message to the topic, it briefly shows up there and then it goes away (i see it using HermesJMS).
I was under the impression that the messages since they are not being consumed by the MDB will get logged into the JDBC store in this case but the the WLSTORE table in oracle db does not get any messages persisted in it either.
I later found out that the messages do show up in the topic > durable subscribers > Show messages in the admin console.
So apparantly what’s happening is topic doesn’t keep the message, but the durable subscription that’s registered under it, keeps it until the message does get consumed.
Question -1) But the fact that messages are not going to the Oracle based jdbc store, still doesn’t make sense ? What am I doing wrong here ?
Question -2) Even when I do resume the MDB to start listening for the messages, the topic keeps showing all the message still intact under the durable subscribers (in admin console) - I was hoping they will get removed from there as they got processed by the only registered durable subscriber.
Messages do not show up in the topic, since topics and queues are different communication models. Assume you have a durable topic with 2 (durable) subscribers: A and B. You want both of them to get the message. To ensure that, A and B both have to confirm they received the message.
This is also the reason why you get all message redelivered, after reconnecting, your MDB has to call commit() on the message, to tell the server it is done processing.
This also explains why the topic itself does not store messages, they are stored per durable consumer. Because A might commit the message, but B will not (might be "offline"). So you need a copy for each consumer.
I found a couple of interesting things in further testing -
for Question 1) _ Even if I don't configure the jdbc store for the JMS server in weblogic 10, it has its own default file store which is always working without any configuration. This file store is used for storing the persistent messages for durable subscriptions and that store will keep the messages around even across server restarts.
For more reading - http://docs.oracle.com/cd/E17904_01/web.1111/e13701/store.htm#i1130575
for Question 2)_ My MDB was expecting XML messages in certain format, during my testing to keep things simple, i started sending small text messages and forgot that they will not get processed successfully in the MDB. so the MDB was failing on all those messages, and rolling back the transaction which is why the messages were never getting removed when I resumed the MDB.
This pretty much answers both my questions.

JMS p2p failover pattern in order to guarantee delivery

Im a web developer ended up in some j2ee development (newbie). I sincerely need this theory confirmed.
I been given the privilege to deliver a message from our system (producer) to the SOA Enterprice service bus (consumer) when the user hits the save button. The information can not be missed or not delivered and the delivery order must be kept.
Environment:
Jboss eap 5.1 as the producer.
JNDI server is the ESB (maybe standard).
Jboss ESB as the consumer.
My weapon of choice is JMS, p2p, due to the asynchronous nature.
When the producer is abut to send the message some problems can occur:
ESB is down causing JNDI exception
Queue manager is for some reason not awake or wrongly configured. This should cause some JMS exception.
Network hickup, causing a JMS error.
So Im looking for some failover pattern. Here is my suggestion:
Add a internal JMS queue to which the message is initially added.
Add a MDB that listen to the internal queue and tries to send it to the target queue (ESB).
If failing in any way log fatal and send email to cool support people.
This should generate a reliable pattern where a message remains on the internal que until processed by the MDB.
Please advice.
Best Regards
ds
Well a 'temporary' queue is not a totally bad idea, but during the time from moving data from one queue to putting it on another you'll have a potential window of risk. Even though that window is close to nothing, what would happen if you got some failure right there and then? -You'd have to put the message back on the queue (and there you'd get into the problem with getting it in the correct order - nasty stuff!) or hold on to it in some way until you put it the other queue (which in turn can be cumbersome if you'd e g get into some failure-situaton.
A more stable solution would be to put data in a db with a queue-order column. You can then select your data in the correct order, send it to the new queue, and finally flag it as 'done' or something or even (better?) remove the data in the db.

Resources