Another way to make Python web app do concurrency

I'm developing a Python web app that emulate WifiDog for remote demo purpose. It is not just a normal web app because it has to run 2 jobs as the same time:

  • Run as a webserver, to redirect user visit to the URL of WifiDog's remote Auth Server.

  • Periodically report system state to Auth Server as a normal HTTP request.

Make the first one is easy. The web part actually don't have much thing to do. It only builds some URL and redirect user to. A small script based on Bootle is enough. What make me concern is the second requirement. Normally, when I build a website on Django or Flask and I need the web do some periodic task, I just use Celery. But here I don't want to use Celery because Celery require me to run another command (celery) beside the main one (which is to launch my web app). Using Celery also means that I have to install more programs like RabbitMQ. It is a waste for just a small, simple web app.

So I start looking to some Python libraries, especially it would be the best if it uses Python built-in stuff. I can use thread but it is not so recommended. I also have bad experience with web server in multi-threaded enviroment so I want to avoid it to save my hair. At the same time, I want to use the lastest software, Python v3.4. Hearing some buzz around Python's new asyncio feature, I'm really curious and want to try it.

Asyncio

After many days research and try, I found a way to combine a WSGI-compliant web app with asyncio to do periodic job while serving a web. To archive this, I need aiowsgi as a WSGI server.

Here is the example code:

import asyncio

import aiowsgi

from wifidemo import setting
from wifidemo.views import app

# This is the periodic task
def ping(loop):
    # Do something
    # Do again after each 40s
    loop.call_later(40, ping, loop)


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.call_soon(ping, loop)
    aiowsgi.serve(app, loop=loop, host=setting.GATEWAY_ADDRESS, port=setting.GATEWAY_PORT)
    

So the key here is the aiowsgi package. With a normal WSGI, you have no way to pass loop variable of asyncio and thus, cannot work with asyncio. Though you can find something related to web and asyncio in PyPI, but most of them are just a web microframework, using asyncio internally, hidden and expose no asyncio handle explicitly to connect with another task (as the loop variable above is needed to connect between ping and aiowsgi.serve).