class MessageGet(web.RequestHandler):
@gen.coroutine
def get( self, id ):
self.pika_client = self.application.settings.get('pika_client')
self.mq_ch = self.pika_client.channel
self.canceled = False
# Ensure we have a queue to consume
yield gen.Task(self.mq_ch.queue_declare, exclusive=False, queue=id)
# Consume messages from queue
self.consumer_tag = self.mq_ch.basic_consume(consumer_callback=self.receive_message,
queue=self.queue_name)
def receive_message(self, channel, method, header, body):
self.mq_ch.basic_ack( method.delivery_tag )
# Handle message content here.
self.write( "stuff" )
if not self.canceled:
# Cancel the consumer only once
self.canceled = True
self.mq_ch.basic_cancel( self.receive_cancel, self.consumer_tag )
def receive_cancel( self, info ):
self.write( "stuff" )
self.finish()
--
You received this message because you are subscribed to the Google Groups "Tornado Web Server" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python-tornad...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
When you use @gen.coroutine on a top-level method like get(), finish() will be called for you automatically. Therefore, you have to keep the coroutine alive until you want to finish the request; you can no longer call finish() explicitly. To combine coroutines and callbacks it helps to use classes from toro (http://toro.readthedocs.org), which will be included in Tornado in the upcoming 4.2 release:
@gen.coroutinedef get(self, id):...self.canceled = toro.Event()self.consumer_tag = self.mq_ch.basic_consume(consumer_callback=self.receive_message, queue=self.queue_name)yield self.canceled wait()self.write('stuff from receive_cancel')def receive_message(self, channel, method, header, body):self.mq_ch.basic_ack(method.delivery_tag)if not self.canceled.is_set():
self.mq.ch.basic_cancel(self.canceled.set, self.consumer_tag)
When you use @gen.coroutine on a top-level method like get(), finish() will be called for you automatically. Therefore, you have to keep the coroutine alive until you want to finish the request; you can no longer call finish() explicitly. To combine coroutines and callbacks it helps to use classes from toro (http://toro.readthedocs.org), which will be included in Tornado in the upcoming 4.2 release:That is contrary to the documentation I linked to, is it not?
@gen.coroutinedef get(self, id):...self.canceled = toro.Event()self.consumer_tag = self.mq_ch.basic_consume(consumer_callback=self.receive_message, queue=self.queue_name)yield self.canceled wait()self.write('stuff from receive_cancel')def receive_message(self, channel, method, header, body):self.mq_ch.basic_ack(method.delivery_tag)if not self.canceled.is_set():
self.mq.ch.basic_cancel(self.canceled.set, self.consumer_tag)That looks quite nice. How does it work though, threading? I will be having quite many connections, and I would like to avoid threading if I can.
For now, using @gen.engine (which in the code looks quite similar to coroutine to me, except the automatic finish) together with @asynchronous, and that seems to solve my problem. Not very well documented though.
-Morgan-
On Wed, Mar 25, 2015 at 4:48 AM, Morgan Tørvolt <mor...@torvolt.com> wrote:When you use @gen.coroutine on a top-level method like get(), finish() will be called for you automatically. Therefore, you have to keep the coroutine alive until you want to finish the request; you can no longer call finish() explicitly. To combine coroutines and callbacks it helps to use classes from toro (http://toro.readthedocs.org), which will be included in Tornado in the upcoming 4.2 release:That is contrary to the documentation I linked to, is it not?I hadn't thought of it this way but yes, the documentation is unclear. When you use both @coroutine and @asynchronous, the @asynchronous decorator is effectively ignored and everything works as if you used @coroutine alone. There's not actually any reason to do this except habits formed in the Tornado 2.x days, so we should probably just deprecate the use of both decorators together. Furthermore, once we get rid of the current unhelpful combination, we can consider making it work the way you thought it did: finish() is not called automatically at the end of an asynchronous coroutine, to make it easier to start with a coroutine and finish with callbacks.
I just realized that I think it works the way you expected if you reverse the decorators and use @coroutine before @asynchronous. This is subtle and I'm hesitant to actually endorse it though.