Discussion:
[bottlepy] Bottle 12 Very Slow Loading
Joe Cusick
2017-11-15 20:19:54 UTC
Permalink
We are having a problem upgrading bottle from 0.10 to 0.12 it is taking a
very long time to load.

We have built a rest based data server that we have kept adding to over
that last three years and it now has over 6000 routes defined in it. Using
bottle 0.10 or 0.11 it takes about 26 seconds to load, but using bottle
0.12.13 (the debian stretch default) its taking 149 seconds to load, so
long in fact that apache is timing out with a 504 before it can respond.

Most of our endpoints we use the bottle.route method to setup the route
like this:

bottle.route(urlbase, method='GET', callback=functionname)

after loading all the routes we call

application = bottle.default_app()

in our apache.wsgi module, in developer mode we will also call bottle.run()
passing in host, port and reloader=True) and the result is the same.

Any help would be appreciated as my manager is getting very impatient for
this upgrade to be finished.

Thanks

Joe Cusick.
--
--
You are member of the "bottlepy" group at google groups.
See http://groups.google.de/group/bottlepy for mailing list options.
See http://bottlepy.org/ for news and documentation.

---
You received this message because you are subscribed to the Google Groups "bottlepy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bottlepy+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Marcel Hellkamp
2017-11-16 10:18:54 UTC
Permalink
Hi Joe,
Post by Joe Cusick
We are having a problem upgrading bottle from 0.10 to 0.12 it is
taking a very long time to load.
CSV and legacy Google App Engine support was dropped for good, and thus,
load-time is no longer something worth optimizing for. The per-request
performance and sane error messages have a higher priority now. You got
bitten by a specific change: Bottle optimizes route-matching by
compiling routes into large regular expressions. This way, we can check
up to 100 routes with a single call to RegexObject.match(), which is in
parts written in C and quite fast. Up to 0.11 the re.compile() call was
delayed until the first request arrived, which made debugging quite
annoying as errors were thrown completely out of context. Starting with
0.12, routes are compiled immediately after they are added. This means
that each time you add a route, up to 100 regular expressions need to be
parsed, optimized and compiled. This is still quite fast and not an
issue for normal apps. The improved error handling and per-request
performance is well worth it.
Post by Joe Cusick
We have built a rest based data server that we have kept adding to
over that last three years and it now has over 6000 routes defined in
it. Using bottle 0.10 or 0.11 it takes about 26 seconds to load, but
using bottle 0.12.13 (the debian stretch default)  its taking 149
seconds to load, so long in fact that apache is timing out with a 504
before it can respond.
A single app with 6000 dynamic routes is a rather extreme use case and
sounds like a serious design flaw. If I'd have to guess, I'd say you are
doing something like this:

class DataItem:
    def __init__(self, id):
        route = '/api/%s/<action>' % id
        bottle.route("GET", route, callback=self.handle_get)
        bottle.route("POST", route, callback=self.handle_post)

items = []
for i in range(3000):
    items.append(DataItem(i))

I have seen this anti-pattern at least once already. Here is how the
same functionality can be achieved with just a hand full of routes:

items = {}
class DataItem:
    def __init__(self, id):
        pass

for i in range(a lot):
    items[i] = DataItem(i)

@bottle.get(/api/<item>/<action>)
def handle(item, action):
    if item not in items:
        bottle.abort(404)
    return items[item].handle_get(action)

@bottle.post(/api/<item>/<action>)
def handle(item, action):
    if item not in items:
        bottle.abort(404)
    return items[item].handle_post(action)

Two routes instead of 6000 will greatly improved load-time and
per-request performance.

I realize that your use-case is probably not /that/ simple, otherwise
you'd had the same idea already. But still, 6000 routes is way too much.
There are no plans to support this use-case or optimize for it, even if
it wouldn't be that hard to add a feature-flag for the delayed compilation.
Post by Joe Cusick
Any help would be appreciated as my manager is getting very impatient
for this upgrade to be finished.
Bottle 0.12 was released almost 4 years ago. You surely took your time.

mfg, Marcel
--
--
You are member of the "bottlepy" group at google groups.
See http://groups.google.de/group/bottlepy for mailing list options.
See http://bottlepy.org/ for news and documentation.

---
You received this message because you are subscribed to the Google Groups "bottlepy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bottlepy+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Loading...