Search code examples
pythonmultithreadingcherrypybottle

Bottle with CherryPy does not behave multi-threaded when same end-point is called


As far as I know Bottle when used with CherryPy server should behave multi-threaded. I have a simple test program:

from bottle import Bottle, run
import time

app = Bottle()

@app.route('/hello')
def hello():
    time.sleep(5)

@app.route('/hello2')
def hello2():
    time.sleep(5)

run(app, host='0.0.0.0', server="cherrypy", port=8080)

When I call localhost:8080/hello by opening 2 tabs and refreshing them at the same time, they don't return at the same time but one of them is completed after 5 seconds and the other is completed after 5 more seconds.

But when I call /hello in one tab and /hello2 in another at the same time they finish at the same time.

Why does Bottle not behave multi-threaded when the same end-point is called twice? Is there a way to make it multi-threaded?

Python version: 2.7.6

Bottle version: 0.12.8

CherryPy version: 3.7.0

OS: Tried on both Ubuntu 14.04 64-Bit & Windows 10 64-Bit


Solution

  • I already met this behaviour answering one question and it had gotten me confused. If you would have searched around for related questions the list would go on and on.

    The suspect was some incorrect server-side handling of Keep-Alive, HTTP pipelining, cache policy or the like. But in fact it has nothing to do with server-side at all. The concurrent requests coming to the same URL are serialised because of a browser cache implementation (Firefox, Chromium). The best answer I've found before searching bugtrackers directly, says:

    Necko's cache can only handle one writer per cache entry. So if you make multiple requests for the same URL, the first one will open the cache entry for writing and the later ones will block on the cache entry open until the first one finishes.

    Indeed, if you disable cache in Firebug or DevTools, the effect doesn't persist.

    Thus, if your clients are not browsers, API for example, just ignore the issue. Otherwise, if you really need to do concurrent requests from one browser to the same URL (normal requests or XHRs) add random query string parameter to make request URLs unique, e.g. http://example.com/concurrent/page?nocache=1433247395.