Slide 1

Slide 1 text

MORE THAN A WSGI SERVER Python FOSDEM 2016

Slide 2

Slide 2 text

WHAT IS GUNICORN

Slide 3

Slide 3 text

A WSGI SERVER ▸ PEP 3333 ▸ pre-fork worker model ▸ Python > 2.6x ▸ handle Django & Paste configuration ▸ support any concurrency framework

Slide 4

Slide 4 text

ADDITIONS TO WSGI ▸ ALREADY_HANDLED: take control of the socket ▸ ‘gunicorn.socket’ environ ▸ ‘gunicorn.raw_uri’ environ ▸ `transfer-encoding: chunked`

Slide 5

Slide 5 text

PREFORK WORKER MODEL ARBITER WORKER WORKER share socket WORKER listen handle signals supervise accept WSGI server handle signals

Slide 6

Slide 6 text

SHARE NOTHING ▸ share only file descriptors ▸ Privilege separation ▸ Worker: simple process with a run function

Slide 7

Slide 7 text

WORKER accept loop setup signals sockets configuration log parent pid tempfile class MyWorker(WorkerBase): def __init__(..): … def init_process(self): … def run(self): …

Slide 8

Slide 8 text

LET IT CRASH ▸ run the application ▸ need to notify the arbiter ▸ tempfile updates ▸ handle application errors ▸ but should crash on errors most of the time

Slide 9

Slide 9 text

set application set Config EMBED class MyApp(BaseApplication): def load_config(self): … def load(self): …
 return self.application

Slide 10

Slide 10 text

DO MORE >

Slide 11

Slide 11 text

DO MORE. BE SAFER. ▸ improve listening in the sync worker ▸ remove the tempfile ▸ prepare for the new protocols ▸ improve logging ▸ going further

Slide 12

Slide 12 text

ACCEPT WHEN NEEDED ▸ place the listening sockets in an event loop ▸ on read, start to accept ▸ also have a timer

Slide 13

Slide 13 text

IMPORT GUNICORN.IMSG

Slide 14

Slide 14 text

GUNICORN.IMSG ▸ communicate between processes ▸ use UNIX socket ▸ sendmsg/recvmsg + buffer ▸ 2 methods: send, receive ▸ zero copy memory

Slide 15

Slide 15 text

child parent IMSG EXAMPLE fds =socket.socketpair() pid = os.fork() if pid != 0: # parent socket.close(fds[1]) imsg = IMSG(fds[0] return main(imsg) # child socket.close(fds[0]) var imsg = IMSG(fds[1]) return main(imsg)

Slide 16

Slide 16 text

wait for a message send a message IMSG EXAMPLE main(imsg): imsg.send(“sometype”, “somemsg”), dispatch_msg(imsg) dispatch_msg(imsg): while True: msg = imsg.recv() if msg is None: sleep(1) continue print(msg.data)

Slide 17

Slide 17 text

REMOVING TEMPFILE ▸ a socket pair is opened for each workers ▸ an imsg object is created for each ▸ imsg object are placed in an eventloop to read asynchronously ▸ maybe extracted from the code as a simple lib

Slide 18

Slide 18 text

DETACHED MODE ▸ rework ALREADY_HANDLED ▸ socket control is given to app ▸ but still supervised ▸ simple API

Slide 19

Slide 19 text

simple proc abstraction return a proc instance EXAMPLE def app(environ, start_response): ..
 start_response(status, headers) proc = MyProc(environ) return proc class MyProc(gunicorn.Proc): def status(self): return STATUS_ALIVE def terminate(self, Reason): ….

Slide 20

Slide 20 text

IMPROVE LOGGING ▸ logging will now be handled in its own process ▸ log infos passed via imsg and dispatched by the arbiter ▸ fix privilege separation issues

Slide 21

Slide 21 text

GOING FURTHER ▸ HTTP 2 ▸ static file server? ▸ fastcgi?

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

HTTP://GUNICORN.ORG Gunicorn HTTP://ENKIM.EU Enki Multimedia