Tuesday, September 10, 2013

Missing manuals of Gunicorn



Gunicorn provide a very convenience way to deploy Django/flask applications. What Gunicorn need is a WSGI app object, and some parameters to deinfe I/O model, worker numbers etc.

The command below will start the web app with 2 processes in sync mode.
$ gunicorn --workers=2 test:app

I ran into a requirement that needs to start the application with a configuration .ini file. But Gunicorn does not leave any interface for passing custom parameters.

I tried to dig a solution with the os.environ setting. Later was inspired by  a statement in Gunicorn document here:  http://docs.gunicorn.org/en/latest/run.html. It explained the Gunicorn command line format:

We must follow the foramt: $ gunicorn [OPTIONS] APP_MODULE

APP_MODULE must follow the pattern MODULE_NAME:VARIABLE_NAME while VARIABLE_NAME should be a callable object which could be find in MODULE_NAME.

A callable object >,<
I checked the source code of Gunicorn, and here's the key line in import_app method
https://github.com/benoitc/gunicorn/blob/master/gunicorn/util.py#L365
app = eval(obj, mod.__dict__)

if the variable obj is a object, the app will be assigned as a object. But if the obj is a function call expression, e.g. "func(1,2)" , the function func will execute!
def f(a,b):
  return a+b
execute eval("f(3,5"), you will get result 8.

This should enlighten you already. for example, in a Flask application.
previously, we have the WSGI object:
app = Flask(__name__)

Now, you can add a method in the application, say:
def get_app(arg1, arg2):
  print arg1, arg2 #now, you got the parameters from outside!
  #process sth.
  return app #return the real WSGI object

Start your web application with Gunicorn:
gunicorn "myapp:get_app('myarg1','myarg2')"

Do hope the solution helped you :)