I have a queue, and I've stuffed some n elements from it.
I want to take 1 element from it, and then exit the callback.The pika examples all use a callback mechanism, which really does not make sense in the application structure.
Defining a callback as follows
def callback(...):
do_data_thinggs(...)
exit(0)
doesn't work, as the message stays in the queue
What's the usual idiom for doing this?
You will want to look at the basic_get method on the channel, have a look at:
https://github.com/pika/pika/blob/03542ef616a2a849e8bfb0845427f50e741ea0c6/docs/examples/blocking_basic_get.rst for an example, this will block until a message is received.
If I understand correctly, I think this has to do with you not ACKing.
take a look at this tutorial: RabbitMQ tutorial 2
Related
I would like to use Pika / RabbitMQ in a pattern similar to a standard socket: that is, set up the connection, then make blocking synchronous calls to receive a single message each time I'm ready to do more work.
Option A: basic_get
The basic_get method of the BlockingConnection offers the ability to receive a message, but it returns immediately if there is no message available to receive. This is like a socket recv call with blocking disabled. I could use this approach with a timeout to poll continuously, but that's not efficient.
Option B: basic_consume
The basic_consume method of BlockingConnection could do the job, but it has the strange requirement that I have start_consuming() somewhere else, in a thread by itself. Since my callers of my receive method are already expecting to block, waiting for a message, this seems like a waste of a thread.
Is it possible with Pika to do the equivalent of socket.recv(blocking=True)?
Run Pika on its own thread and basic_consume with a prefetch value of 1 (if you really want a single message at a time). Insert messages into some sort of synchronized data structure on which your callers can block.
Be sure to acknowledge your messages correctly from other threads (example)
NOTE: the RabbitMQ team monitors the rabbitmq-users mailing list and only sometimes answers questions on StackOverflow.
Use the channel's basic_get method like in this example:
credentials = pika.PlainCredentials('username', 'password')
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost', credentials=credentials))
channel = connection.channel()
inmessage = channel.basic_get("your_queue_name", auto_ack=True)
inmessage is a tuple of 3 elements, element with index of 2 is your message's body.
I'm using jruby and java's com.rabbitmq.client to make an rpc call to a worker process through rabbitmq. The call could take up to 8 hours to complete. Using RPC seems wrong but since it's basically just a pub/sub I'm wondering if it's actually a reasonable thing to do.
I'm assuming that you are using an exclusive replyto/callback queue. The only problem with this approach is that if the producer goes down, the queue will vanish, and the response will be lost. A better approach maybe to use a DB to log the job's state/response, and fire events on the job's state change, which interested parties may subscribe to. I'd generally avoid coupling in any fashion for such long running jobs.
I have a producer sending durable messages to a RabbitMQ exchange. If the RabbitMQ memory or disk exceeds the watermark threshold, RabbitMQ will block my producer. The documentation says that it stops reading from the socket, and also pauses heartbeats.
What I would like is a way to know in my producer code that I have been blocked. Currently, even with a heartbeat enabled, everything just pauses forever. I'd like to receive some sort of exception so that I know I've been blocked and I can warn the user and/or take some other action, but I can't find any way to do this. I am using both the Java and C# clients and would need this functionality in both. Any advice? Thanks.
Sorry to tell you but with RabbitMQ (at least with 2.8.6) this isn't possible :-(
had a similar problem, which centred around trying to establish a channel when the connection was blocked. The result was the same as what you're experiencing.
I did some investigation into the actual core of the RabbitMQ C# .Net Library and discovered the root cause of the problem is that it goes into an infinite blocking state.
You can see more details on the RabbitMQ mailing list here:
http://rabbitmq.1065348.n5.nabble.com/Net-Client-locks-trying-to-create-a-channel-on-a-blocked-connection-td21588.html
One suggestion (which we didn't implement) was to do the work inside of a thread and have some other component manage the timeout and kill the thread if it is exceeded. We just accepted the risk :-(
The Rabbitmq uses a blocking rpc call that listens for a reply indefinitely.
If you look the Java client api, what it does is:
AMQChannel.BlockingRpcContinuation k = new AMQChannel.SimpleBlockingRpcContinuation();
k.getReply(-1);
Now -1 passed in the argument blocks until a reply is received.
The good thing is you could pass in your timeout in order to make it return.
The bad thing is you will have to update the client jars.
If you are OK with doing that, you could pass in a timeout wherever a blocking call like above is made.
The code would look something like:
try {
return k.getReply(200);
} catch (TimeoutException e) {
throw new MyCustomRuntimeorTimeoutException("RabbitTimeout ex",e);
}
And in your code you could handle this exception and perform your logic in this event.
Some related classes that might require this fix would be:
com.rabbitmq.client.impl.AMQChannel
com.rabbitmq.client.impl.ChannelN
com.rabbitmq.client.impl.AMQConnection
FYI: I have tried this and it works.
I'm using Django Celery with Redis to run a few tasks like this:
header = [
tasks.invalidate_user.subtask(args = (user)),
tasks.invalidate_details.subtask(args = (user))
]
callback = tasks.rebuild.subtask()
chord(header)(callback)
So basically the same as stated in documentation.
My problem is, that when this task chord is called, celery.chord_unlock task keeps retrying forever. Tasks in header finish successfully, but because of chord_unlock never being done, callback is never called.
Guessing that my problem is with not being able to detect that the tasks from header are finished, I turned to documentation to look how can this be customized. I've found a section, describing how the synchronization is implemented, there is an example provided, what I'm missing is how do I get that example function to be called (i.e. is there a signal for this?).
Further there's a note that this method is not used with Redis backend:
This is used by all result backends except Redis and Memcached, which increment a counter after each task in the header, then applying the callback when the counter exceeds the number of tasks in the set.
But also says, that Redis approach is better:
The Redis and Memcached approach is a much better solution
What approach is that? How is it implemented?
So, why is chord_unlock never done and how can I make it detect finished header tasks?
I'm using: Django 1.4, celery 2.5.3, django-celery 2.5.5, redis 2.4.12
You don't have an example of your tasks, but I had the same problem and my solution might apply.
I had ignore_result=True on the tasks that I was adding to a chord, defined like so:
#task(ignore_result=True)
Apparently ignoring the result makes it so that the chord_unlock task doesn't know they're complete. After I removed ignore_result (even if the task only returns true) the chord called the callback properly.
I had the same error, I changed the broker to rabbitmq and chord_unlock is working until my task finishes (2-3 minutes tasks)
when using redis the task finishes and chord_unlock only retried like 8-10 times every 1s, so callback was not executing correctly.
[2012-08-24 16:31:05,804: INFO/MainProcess] Task celery.chord_unlock[5a46e8ac-de40-484f-8dc1-7cf01693df7a] retry: Retry in 1s
[2012-08-24 16:31:06,817: INFO/MainProcess] Got task from broker: celery.chord_unlock[5a46e8ac-de40-484f-8dc1-7cf01693df7a] eta:[2012-08-24 16:31:07.815719-05:00]
... just like 8-10 times....
changing broker worked for me, now I am testing #Chris solution and my callback function never receives the results from the header subtasks :S, so, it does not works for me.
celery==3.0.6
django==1.4
django-celery==3.0.6
redis==2.6
broker: redis-2.4.16 on Mac OS X
This could cause a problem such that; From the documentation;
Note:
If you are using chords with the Redis result backend and also overriding the Task.after_return() method, you need to make sure to call the super method or else the chord callback will not be applied.
def after_return(self, *args, **kwargs):
do_something()
super(MyTask, self).after_return(*args, **kwargs)
As my understanding, If you have overwritten after_return function in your task, it must be removed or at least calling super one.
Bottom of the topic:http://celery.readthedocs.org/en/latest/userguide/canvas.html#important-notes
The "retry" system with NServiceBus is great. It works fantastic in making sure small things like dead locks don't mess us up.
However, sometimes I KNOW that a message is bad. Bad in the sense that no amount of retries is going to help.
Is there a way to tell NServiceBus: "This message is a bad apple, move it to the error queue"? (And have it skip the retries?)
If you are using NSB 3, you can take a look at the IManageMessageFailures interface. This will allow you to plug in your functionality, but this is after the message has failed. If you would like to get at the message earlier, then take a look at the Message Mutators feature. This gets you in both at the transport layer and at the application layer.
Would calling Bus.DoNotContinueDispatchingCurrentMessageToHandlers(); inside the handler not be a simpler way of doing this?