
Python's Tornado has swept me off my feet - matticakes
http://blog.perplexedlabs.com/2010/07/01/pythons-tornado-has-swept-me-off-my-feet/
======
bitanarch
I've been building a web backend for an iPhone app with it in the past two
months. It's ideal for serving simple JSON requests that depend on other I/O
stuff (like, contacting Facebook) - but it's got plenty of problems:

1\. The callback architecture. I simply freakin' hate the IOLoop. If you have
just one asynchronous I/O operation, it's nice and easy. If you have one that
depends on another, you have to wrap and curry a callback inside another one.
Three? More wrapping and currying. I understand it's pretty much the same in
many other platforms like client side AJAX these days. But man, this is Python
and we DO have far better alternatives like gevent! You want the epoll() and
kqueue() for performance? Fine. But it's Python and you can do it with
coroutines without all that asynchronous event handling mess. And minus all
those function wrapping and curry, I'm sure it can be much faster, all the
while being easier to program with.

2\. The Facebook API in auth.py sucks. Just read its source code - it performs
all requests by GET - WTF?! It can't even upload files unless you hack it
(I've got a branch at <http://github.com/martinkou/tornado-upload> for that).
And look at that _signature function under the FacebookMixin class - it
doesn't even use session secrets? I'm not sure if I'm doing anything wrong,
and Facebook API's docs don't mention that.. but in my testing, if I just use
the application secret key all the way for the signature, Facebook gives me
104 errors. I had to hack it again to make it use session secrets in signing
requests.

I don't really care about databases. But last time I checked, psycopg2 has a
page telling you how to do async requests with gevent or libevent style
coroutines. Tornado? Good luck integrating that with IOLoop and currying your
callbacks. Sure you can still make it work, but it's unnecessarily
complicated.

~~~
bitanarch
btw, it's possible to run Tornado on $NUM_CPU forked processes, have them
listen to one port and so you wouldn't need nginx load balancing. Just read
httpserver.py and you'll find a fork() there. The downside? Assuming you're
still running your Tornado in your console and haven't daemonized it somehow -
you press Ctrl-C, it exits (the console part, I mean) - and the $NUM_CPU
children are still running. It's still not fixed today, and that doesn't
really speak of quality.

------
bdr
I like Tornado, too, but here are a couple problems:

\- Hard to test, at least relative to Django. There's no built-in support, and
being async makes it a little complicated. I have it working now, but it took
some bashing and plenty of the mock library.

\- Lack of libraries for things we might want to do asynchronously. I can buy
the argument that that's fine for databases, but for AMQP it's mandatory. The
lack of a (working) Tornado AMQP library drove me to use Cyclone, which is a
production-ready port of Tornado to the Twisted framework. Libraries ahoy.

------
russell_h
I had a few issues with Tornado when I tried it (back in February). They
pretty much came down to two things:

1\. Database queries are not asynchronous. This is a big deal for most
traditional web applications, and pretty much removes any benefit to using
Tornado for them. Even for things that rely mostly on HTTP APIs, there's still
a decent chance that you'll want to do authentication or something against a
database.

2\. It was generally lacking a lot of the maturity and handy declarative
syntax you can get with frameworks like Django. There was no ORM, form
helpers, etc.

That being said, I really like the idea, performance was great and development
seemed to be proceeding at a tremendous pace. The whole project is on GitHub
and they seemed very willing to accept both bug-fixes and features.

~~~
frognibble
re 1: Bret Taylor addressed db queries in the video on Tornado (the video is
on Facebook, but I cannot find the link). If you run more than one instance of
Tornado per core and you have a decent load balancer in front of the
instances, then short blocking calls to the db work just fine. If your db
calls are taking a long time, then it might be better to speed up the queries
with caching or query optimization before worrying about async.

I like this approach because I prefer writing app logic in a straight line
instead of in callbacks. The code is easier to understand and debug.

~~~
joshu
any recommendations re loadbalancers?

~~~
timr
haproxy is brilliant.

------
jrussbowman
I originally started unscatter.com on Tornado, then got caught up in the whole
node.js spin. I started rewriting the application using node.js, then realized
I was rewriting large chunks of Tornado in javascript. I went back to Tornado
and have since put up something that works, very quickly.

I use supervisord for maintaining multiple instances of the application
running. I found it the simplest way to manage it. It also gave me support for
watching and restarting any instances that hang. I'm also using nginx to
proxy. Currently I'm proxying 2 instance of tornado on a 4 core box. I'm also
running mongodb, memcached, and nginx on the same small 256MB ram box right
now.

In the future I could see me moving to node.js in the future, but for any
application that requires working with multiple APIs, Tornado was a much
better headstart, and the framework itself was more mature and ready to use
than anything from the node.js camp several months ago.

Unfortunately no one is actively supporting the auth portion of Tornado, and
it could use a maintainer. I'd set up, but with a newborn I'm not sure when
I'll get to it. I'll be releasing ( and have already done so in the past ) any
changes I make back to the Tornado project.

------
japherwocky
I've been building things with tornado and pymongo for going on six months,
absolutely love it. Light and fast, easy to customize, a solid auth system
builtin, a realtime chat demo (!); keep things simple and it is a joy.

