Post on 20-Aug-2015
Développement web asynchrone avec Tornado
Ronan Amicel@amicel
PyCon FR – Paris – 15 septembre 2012
Ronan Amicel
• Entrepreneur
• Startup advisor
• Python !
Tornado c’est quoi ?
• Un serveur web
– scalable et non-bloquant (utilise epoll ou kqueue)
• Un framework web
– proche de web.py ou webapp
– exploite l’infrastructure non-bloquante sous-jacente
Bonjour les gens !import tornado.ioloopimport tornado.web
class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Bonjour les gens !")
application = tornado.web.Application([ (r"/", MainHandler),])
if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
(Some) Batteries Included
• Moteur de templates
• Localisation
• Client HTTP asynchrone
• Client MySQL asynchrone
• OpenID et OAuth (Twitter, Facebook, Google)
• Web Socket
Cas d'utilisation
• Seul ou en complément d'un framework « classique »
• Sites à forte charge (milliers de requêtes / seconde)
• Messagerie instantanée, chat rooms
• Requêtes dépendant de services externes à latence variable(API Facebook, Twitter, etc.)
• Mises à jour « temps réel » dans une page web
Mises à jour « temps réel »Polling
(Ajax)
Long Polling(Comet)
Streaming(Web Socket)
Navigateur Serveur Navigateur Serveur Navigateur Serveur
événements
événements
événements
Web Socket(côté serveur)
from tornado.websocket import WebSocketHandler
class EchoWebSocket(WebSocketHandler):
def open(self): print "WebSocket opened"
def on_message(self, message): self.write_message(u"You said: " + message)
def on_close(self): print "WebSocket closed"
Web Socket(côté client)
var ws = new WebSocket("ws://localhost:8888/websocket");
ws.onopen = function () { ws.send("Hello, world");};
ws.onmessage = function (evt) { alert(evt.data);};
Requêtes asynchrones
from tornado.httpclient import AsyncHTTPClientfrom tornado.web import RequestHandler, asynchronous
class MyRequestHandler(RequestHandler):
@asynchronous def get(self): http = AsyncHTTPClient() http.fetch('http://friendfeed.com/', self._on_download)
def _on_download(self, response): self.write('Downloaded!') self.finish()
Masquer les callbacksavec tornado.gen
from tornado.gen import engine, Taskfrom tornado.httpclient import AsyncHTTPClientfrom tornado.web import RequestHandler, asynchronous
class MyRequestHandler(RequestHandler):
@asynchronous @engine def get(self): http = AsyncHTTPClient() response = yield Task(http.fetch, 'http://friendfeed.com/') self.write('Downloaded!') self.finish()
Tâches concurrentesavec tornado.gen
class MyRequestHandler(RequestHandler):
@asynchronous @engine def get(self): http = AsyncHTTPClient()
response1, response2 = yield [ Task(http.fetch, url1), Task(http.fetch, url2), ]
self.write('Downloaded!') self.finish()
Bibliothèques asynchrones
• PostgreSQL
• MongoDB
• Redis
• Memcache
• RabbitMQ
Qui utilise Tornado ?
focus.io
Historique
• 2007 : FriendFeed
• Août 2009 : rachat par Facebook
• Septembre 2009 : première version diffusée sous licence Apache 2.0
• Juillet 2010 : Tornado 1.0
• Juin 2011 : Tornado 2.0
• Septembre 2012 : Tornado 2.4
Les côtés négatifs
• Asynchrone
– Moins lisible que du code synchrone
– Plus complexe à déboguer
• Communauté
– Moins populaire que Django, Flask, Pyramid...
Ressources
• http://www.tornadoweb.org/
• http://pypi.python.org/pypi/tornado
• https://github.com/facebook/tornado/