Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Tornado in 1 Hour (or Less)
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Kārlis Lauva
December 04, 2013
Programming
210
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Tornado in 1 Hour (or Less)
Tornado crash-course
Kārlis Lauva
December 04, 2013
More Decks by Kārlis Lauva
See All by Kārlis Lauva
Let's talk about PureScript
karlis
0
95
Going Full Monty with full.monty
karlis
1
120
The Transatlantic Struggle
karlis
0
93
Two Scoops of Scala
karlis
0
130
Valsts pārvaldes atvērto datu semantiskās integrācijas procesi
karlis
1
220
Other Decks in Programming
See All in Programming
モデルのリファクタリングが難しいと思ったら、そもそも複雑だったのはビジネス仕様だった ? / is-the-business-domain-the-real-complexity
hatsu38
0
450
コードレビューのボトルネックを"する側"と"される側"の両面から解消する
yub0n
2
1.5k
iOS 27でニュースアプリはどう変わる!? 〜日経電子版の新機能対応と、開発事例から〜
lynnswap
7
13k
難しいけど、読めた。- OSSの入口に立った話。
sts11142
0
140
動作中のプログラムの中身をリアルタイムに覗く / Realtime Debugger for CSharp with Roslyn
prota
1
1.8k
ハーネス設計入門 〜 基礎知識の整理から実務へのステップアップ 〜
kinopeee
20
21k
Atomic Design, Enforced: Scaling Mobile Design Systems (next.app devCon / droidCon Berlin 2026)
steliosf
PRO
0
120
大喜利で理解するLLM as a Judge / Understanding LLM-as-a-Judge through Ogiri
rockname
0
190
Heart of Swift Concurrency
koher
0
1.2k
MVNOの申込からeSIM開通までをiOSアプリでつなぐ- 本人確認・MNP・通信事業者基盤をまたぐ実装
satotakeshi
0
540
setup-vp GitLab対応の裏側
naokihaba
0
150
Are APIs Still Relevant in the AI Era?
soyuka
0
420
Featured
See All Featured
Paper Plane
katiecoart
PRO
4
53k
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
500
How STYLIGHT went responsive
nonsquared
100
6.3k
GitHub's CSS Performance
jonrohan
1033
470k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
700
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
570
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
300
Skip the Path - Find Your Career Trail
mkilby
1
240
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
63
46k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
3k
From π to Pie charts
rasagy
1
390
Transcript
TORNADO IN 1 HOUR (OR LESS) Kārlis Lauva @skazhy python.lv
meetup 2013.12.04
Tornado in 3 bullet points • High performance™ web framework
• Async networking library • Gets out of your way (most of the time)
Timeline • 2007.10 - FriendFeed is launched • 2009.08 -
Facebook acquires FriendFeed • 2009.09 - Tornado is open sourced • 2013.09 - Last stable release (3.1.1)
Who’s using it? …..and your company.
Installing pip install tornado pip install git+https://github.com/facebook/tornado.git
“Hello, World!” import tornado.web import tornado.ioloop class Handler(tornado.web.RequestHandler): def get(self):
self.finish("Hello World!") handlers = [tornado.web.URLSpec(r"/$", Handler)] app = tornado.web.Application(handlers) app.listen(1337) tornado.ioloop.IOLoop.instance().start()
MAIN INGREDIENTS
tornado.ioloop • I/O loop for non-blocking sockets • One per
application (or thread) • Uses epoll or kqueue
Example - TCP server def connection_ready(sock, fd, events): while True:
try: connection, address = sock.accept() except socket.error: return connection.setblocking(0) connection.send("Hello") sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.setblocking(0) sock.bind(("", 1337)) sock.listen(128) io_loop = ioloop.IOLoop.instance() callback = functools.partial(connection_ready, sock) io_loop.add_handler(sock.fileno(), callback, io_loop.READ) io_loop.start()
tornado.httpserver • Async web server • Utilizes a singleton IOLoop
• Subclass of TCP server (duh)
Example - HTTP server import tornado.httpserver import tornado.ioloop def handle_request(request):
message = "Hello world\n" request.write("HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s" % \ (len(message), message)) request.finish() http_server = tornado.httpserver.HTTPServer(handle_request) http_server.listen(8080) tornado.ioloop.IOLoop.instance().start()
tornado.web.Application • A collection of resource - handler mappings •
Setting container • Manages UI modules & rendering • Wraps tornado.httpserver • Supports virtual hosts
tornado.web.RequestHandler • Basic building block • If method exists -
call it, else raise HTTP 405 • Not limited to “standard” verbs • Unified request preparation / finalizing methods
A (blocking) request handler # in handler listing URLSpec(r"/users/(\w+)$", SomeHandler)
class Somehandler(tornado.web.RequestHandler): def post(self, user_id): if not self.get_argument(message): raise HTTPError(400, "No message") payload = { "user_id": user_id, "message": self.get_argument(message), } self.application.db.messages.insert(payload) response = HTTPClient().fetch("http://foo.bar.baz") self.render("template.html", {"data": response})
What else is there? • HTTP client • Templating system
• Option management / collection system • Generator interface for async calls • Auth mixins for OAuth • ...and more
ADDING ASYNC-SAUCE
Blocking request redux def post(self, user_id): if not self.get_argument(message): raise
HTTPError(400, "No message") payload = { "user_id": user_id, "message": self.get_argument(message), } self.application.db.messages.insert(payload) response = HTTPClient().fetch("http://foo.bar.baz") self.render("template.html", {"data": response})
Non-blocking request with callback @web.asynchronous def post(self, user_id): def callback(response):
self.render("template.html", {"data": response}) if not self.get_argument(message): raise HTTPError(400, "No message") payload = { "user_id": user_id, "message": self.get_argument(message), } self.application.db.messages.insert(payload) AsyncHTTPClient().fetch("http://foo.bar.baz", callback)
A non-blocking request with @gen @web.asynchronous @gen.engine def post(self, user_id):
def callback(response): if not self.get_argument(message): raise HTTPError(400, "No message") payload = { "user_id": user_id, "message": self.get_argument(message), } self.application.db.messages.insert(payload) resp = yield gen.Task(AsyncHTTPClient().fetch, "http://foo.bar.baz") self.render("template.html", {"data": resp})
Non-blocking calls for pymongo @gen.engine @web.asynchronous def post(self, user_id): def
callback(response): if not self.get_argument(message): raise HTTPError(400, "No message") payload = { "user_id": user_id, "message": self.get_argument(message), } motor.Op(self.application.db.messages.insert, payload) resp = yield gen.Task(AsyncHTTPClient().fetch, "http://foo.bar.baz") self.render("template.html", {"data": resp})
Caveats • Always raise in main thread • Don’t forget
to add decorators • @gen.Tasks are toxic
tornado.websocket class EchoHandler(websocket.WebSocketHandler): def open(self): # the same as handler.get()
logging.debug("WebSocket opened") def on_message(self, message): self.write_message(message) def on_close(self): logging.debug("WebSocket closed") // Client side var ws = new WebSocket("ws://localhost:1337/echo"); ws.onopen = function() { ws.send("Hello, world"); }; ws.onmessage = function (evt) { alert(evt.data); };
TORNADO TEMPLATING
• Django & Jinja2-esque • Easily extendible • Built-in helpers
for reverse urls, etc tornado.template
Example context = { "bugs": {"123": "Fix color scheme"} "uppercase":
lambda x: x.upper() } <ul> {% for bug_id, description in bugs.items() %} <li>{{ bug_id }} - {{ description }}</li> <p>{{ shout(“whoa”) }}</p> {% end %} </li>
TESTING + DEBUGGING
tornado.testing • Wrappers for unittest.TestCase • Helpers for testing async
handlers
PDB • Works as you'd expect app.listen(options.port) pdb.set_trace() tornado.ioloop.IOLoop.instance().start()
REAL WORLD TORNADO
Managing instances with supervisord [program:app-8000] directory=/srv/app/ command=python server.py --port=8101 --mongodb_host=localhost:27017
user=nginx stdout_logfile=/srv/app/logs/app.8000.log [program:app-8001] directory=/srv/app/ command=python server.py --port=8001 --mongodb_host=localhost:27017 user=nginx stdout_logfile=/srv/app/logs/app.8001.log [group:webapp] programs=app-8000,app-8001
Load balancing with nginx upstream webapp { server localhost:8000; server
localhost:8001; } server { server_name foobar; location / { proxy_pass http://webapp; } }
Utilize ngnix to it's full power • Do not serve
static files from Tornado • Whitelist routing (don't bug Tornado with 403s)
Load balancing while you load balance with Amazon ELB
Deployment / production settings python server.py --port=8001 --mongodb_host=localhost:27017 # In
application file from tornado.options import define, options define("port", default=1337, type=int) define("mongodb_host", default="localhost:27017", type=str) define("version", default="1", type=str) class Application(tornado.web.Application): def __init__(self): self.db = MongoClient(options.mongodb_host) handlers = [....] super(Application, self).__init__(handlers, version=options.version) def main(): options.parse_command_line() app = Application() application.listen(options.port)
Tornado and HTTPS • As easy as adding an option
to the application instance ssl_options={ "certfile": path_to_certfile, "keyfile": path_to_keyfile, } app = Application(handlers, ssl_options=ssl_options)
Error collection • Override RequestHandler.send_error() • Use error collection mixins
Sentry integration with Raven • Using mixins to capture exceptions
class Hadler(SentryMixin, tornado.web.RequestHandler): @tornado.web.asynchronous @tornado.gen.engine def get(self): try: raise ValueError() except Exception as e: response = yield tornado.gen.Task( self.captureException, exc_info=True ) self.finish()
Where to go next? • Read through the source •
Start building rad hacks • ??? • PROFIT!!
QUESTION TIME!