Skip to content

Instantly share code, notes, and snippets.

@brimcfadden
Created August 31, 2011 18:40
Show Gist options
  • Save brimcfadden/1184323 to your computer and use it in GitHub Desktop.
Save brimcfadden/1184323 to your computer and use it in GitHub Desktop.
Use stormed-amqp with tornado.web.RequestHandlers
#!/usr/bin/env python
# tornadoweb_stormed.py
import logging
import sys
import stormed
import tornado.ioloop
import tornado.web
__author__ = 'Brian McFadden'
__email__ = 'brimcfadden@gmail.com'
HTML_HEADER = '<html><head><title>Tornado/Stormed RPC</title></head><body>'
HTML_FOOTER = '</body></html>'
class Fib(tornado.web.RequestHandler):
"""This is a different version of the file implementing tutorial #6.
The original version is located at https://gist.github.com/1150229/
This version always raises an HTTP 500 error which causes some unexplained
behavior.
"""
@tornado.web.asynchronous
def get(self, number=''):
if not number:
self.redirect('/30') # GET / --> GET /30
self.number = number
mq_conn = self.application.settings.get('mq_conn')
self.mq_ch = mq_conn.channel()
self.mq_ch.queue_declare(exclusive=True,
callback=self._on_q_declare)
def _on_q_declare(self, qinfo):
self.mq_ch.consume(qinfo.queue, self._on_mq_response)
self.corr_id = corr_id = str(id(self))
msg = stormed.Message(str(self.number), delivery_mode=2,
reply_to=qinfo.queue, correlation_id=corr_id)
self.mq_ch.publish(msg, exchange='', routing_key='rpc_queue')
def _on_mq_response(self, response_msg):
self.send_error(500)
def main():
logging.basicConfig(level=logging.DEBUG)
mq_conn = stormed.Connection(host='localhost')
def on_connect():
print 'Connected to AMQP broker.'
mq_conn.connect(on_connect)
application = tornado.web.Application(
[(r'/([0-9]*)', Fib)],
**{'mq_conn': mq_conn}
)
try:
port = int(sys.argv[1]) # $ python tornadoweb_stormed.py 80
except:
port = 8080
application.listen(port)
print "Tornado is serving on port {0}.".format(port)
tornado.ioloop.IOLoop.instance().start()
if __name__ == '__main__':
main()
@brimcfadden
Copy link
Author

Notice on line 42, a Tornado exception is raised. However, it seems to mess up the connection to rabbit. Upon accessing this handler with a browser (GET /20, for example), this is the output with an excerpt of the traceback:

Tornado is serving on port 8080.
Connected to AMQP broker.
ERROR:root:Uncaught exception, closing connection.
Traceback (most recent call last):
  File "/usr/local/lib/python2.6/dist-packages/tornado/iostream.py", line 230, in _run_callback
    callback(*args, **kwargs)
  File "/usr/local/lib/python2.6/dist-packages/tornado/stack_context.py", line 173, in wrapped
    callback(*args, **kwargs)
  File "/usr/local/lib/python2.6/dist-packages/stormed/frame.py", line 35, in _with_payload
    self.callback(self.frame)
  File "/usr/local/lib/python2.6/dist-packages/stormed/connection.py", line 111, in _frame_loop
    self.channels[frame.channel].process_frame(frame)
  File "/usr/local/lib/python2.6/dist-packages/stormed/frame.py", line 115, in process_frame
    processor(frame.payload)
  File "/usr/local/lib/python2.6/dist-packages/stormed/frame.py", line 131, in process_content_body
    self.handle_method(self._msg_builder.content_method)
  File "/usr/local/lib/python2.6/dist-packages/stormed/frame.py", line 140, in handle_method
    method.handle(self)
  File "/usr/local/lib/python2.6/dist-packages/stormed/method/basic.py", line 26, in handle
    ch.consumers[self.consumer_tag].callback(msg)
  File "./tornadoweb_stormed_broken.py", line 42, in _on_mq_response
    raise tornado.web.HTTPError(500)

I say "excerpt" because the traceback repeats itself several times, despite only one request being made. Also, the connection hangs in the browser, so the HTTPError isn't being raised correctly within the web server. While continuing to run, a second request, GET /20, can be made to the server which produces the following traceback:

ERROR:root:Uncaught exception GET /20 (192.168.1.134)
HTTPRequest(protocol='http', host='ubuntu:8080', method='GET', uri='/20', version='HTTP/1.1', remote_ip='192.168.1.134', body='', headers={'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'Connection': 'keep-alive', 'Accept-Language': 'en-us,en;q=0.5', 'Accept-Encoding': 'gzip, deflate', 'Host': 'ubuntu:8080', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:6.0.1) Gecko/20100101 Firefox/6.0.1'})
Traceback (most recent call last):
  File "/usr/local/lib/python2.6/dist-packages/tornado/web.py", line 861, in _execute
    getattr(self, self.request.method.lower())(*args, **kwargs)
  File "/usr/local/lib/python2.6/dist-packages/tornado/web.py", line 941, in wrapper
    return method(self, *args, **kwargs)
  File "./tornadoweb_stormed_broken.py", line 30, in get
    self.mq_ch = mq_conn.channel()
  File "/usr/local/lib/python2.6/dist-packages/stormed/connection.py", line 99, in channel
    ch.open(callback)
  File "/usr/local/lib/python2.6/dist-packages/stormed/channel.py", line 50, in open
    self.send_method(Open(out_of_band=''), callback)
  File "/usr/local/lib/python2.6/dist-packages/stormed/frame.py", line 152, in send_method
    self._flush()
  File "/usr/local/lib/python2.6/dist-packages/stormed/frame.py", line 159, in _flush
    self.write_method(method)
  File "/usr/local/lib/python2.6/dist-packages/stormed/frame.py", line 171, in write_method
    self.conn.stream.write(f)
  File "/usr/local/lib/python2.6/dist-packages/tornado/iostream.py", line 164, in write
    self._check_closed()
  File "/usr/local/lib/python2.6/dist-packages/tornado/iostream.py", line 378, in _check_closed
    raise IOError("Stream is closed")
IOError: Stream is closed
ERROR:root:500 GET /20 (192.168.1.134) 2.30ms

@brimcfadden
Copy link
Author

I discovered that this problem can be avoided by writing line 42 as:

self.send_error(500)

instead of using the exception.

@brimcfadden
Copy link
Author

The update to this gist solves the problem as described in my last comment, but the redirect still causes problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment