On Sep 17, 2010, at 8:24 AM, mdipierro wrote:
>
> I will take the patch and you may be fine if your thread does not
> access db.
Here's a slightly more complete patch. This should maintain backward
compatibility with apps that don't use app-specific routing. One that does can
call rewrite.select(app='name') at the start of a new thread.
This won't help when globals are based on threading.local, though; that's a
nastier problem.
diff -r 3645edf51f22 gluon/rewrite.py
--- a/gluon/rewrite.py Fri Sep 17 08:40:21 2010 -0500
+++ b/gluon/rewrite.py Fri Sep 17 08:50:17 2010 -0700
@@ -150,14 +150,15 @@
logger.debug('%s: [%s] -> %s (not rewritten)' % (tag, key, default))
return (default, query, original_uri)
-def select(e=None):
+def select(env=None, app=None):
"""
select a set of rewrite params for the current request
called from main.wsgibase before any URL rewriting
"""
- app = None
- if e and params.routes_app:
- (app, q, u) = filter_uri(e, params.routes_app, "routes_app")
+ if app:
+ thread.routes = params_apps.get(app, params)
+ elif env and params.routes_app:
+ (app, q, u) = filter_uri(env, params.routes_app, "routes_app")
thread.routes = params_apps.get(app, params)
else:
thread.routes = params # default to base rewrite parameters
@@ -180,6 +181,8 @@
def filter_out(url, e=None):
"called from html.URL to rewrite outgoing URL"
+ if not hasattr(thread, 'routes'):
+ select() # ensure thread.routes is set (for application threads)
if thread.routes.routes_out:
items = url.split('?', 1)
if e:
>
> On Sep 17, 10:20 am, Jonathan Lundell <[email protected]> wrote:
>> On Sep 16, 2010, at 10:44 PM, mdipierro wrote:
>>
>>
>>
>>> Jonathan,
>>
>>> I misunderstood your problem. You should not spawn threads from a
>>> web2py app. This is not just because the current routing mechanism
>>> does not support it. This is a very general with all web applications
>>> because threads are managed by the web server which starts/stops and
>>> kills them. If your thread spawns a new thread and the parent is
>>> killed by the web server you may end up with a memory leak.
>>
>>> Please explain what you are trying to achieve, perhaps show us some
>>> code, and I am sure there is another way.
>>
>> Here's a quick patch to rewrite.filter_out that should fix the problem for
>> URL() as long as app-specific routes are not in use:
>>
>> def filter_out(url, e=None):
>> "called from html.URL to rewrite outgoing URL"
>> + if not hasattr(thread, 'routes'):
>> + select() # ensure thread.routes is set (for application threads)
>> if thread.routes.routes_out:
>> items = url.split('?', 1)
>> if e:
>>
>> Massimo, this will be a little confusing, since there are two Jonathans on
>> this (message) thread, and both of us are using application threads.
>>
>> Here's my case:
>>
>> The application is a manager for a collection of servers, from tens to
>> possibly hundreds. On the central management page, I create a table that
>> summarizes the status of the servers. I get the status by sending an xmlrpc
>> query to each server, and the response can take several seconds (say 2-10).
>>
>> Because serializing these requests can take too long, I create a thread per
>> server to make the query and wait for the response. CPU time for such a
>> request is nil, so all the threads complete in approximately the time for
>> the slowest one.
>>
>> The code is very simple and very clean.
>>
>> No doubt I could accomplish something like it with Ajax, and effectively a
>> request thread for each server. But I hesitate to rely on the web server's
>> thread pool, assuming it has one big enough, and an Ajax solution wouldn't
>> be so straightforward, I don't think.
>>
>>
>>
>>> Massimo
>>
>>> On Sep 16, 2:26 pm, "Jonathan Z." <[email protected]> wrote:
>>>> I'm kicking off a threaded process. As part of the "run" method, I'm
>>>> calling: env("application", import_models=True) in order to work with
>>>> the web2py environment inside the context of my thread. As a result,
>>>> models are parsed and the following exception is raised:
>>
>>>> Traceback (most recent call last):
>>>> File ".../web2py/gluon/restricted.py", line 188, in restricted
>>>> exec ccode in environment
>>>> File "applications/app/models/db.py", line 32, in <module>
>>>> auth = Auth(globals(), db)
>>>> File ".../web2py/gluon/tools.py", line 804, in __init__
>>>> self.settings.login_url = self.url('user', args='login')
>>>> File ".../web2py/gluon/tools.py", line 762, in url
>>>> f=f, args=args, vars=vars)
>>>> File ".../web2py/gluon/html.py", line 228, in _URL
>>>> return URL(*args, **kwargs)
>>>> File ".../web2py/gluon/html.py", line 206, in URL
>>>> return XML(rewrite.filter_out(url, env))
>>>> File ".../web2py/gluon/rewrite.py", line 183, in filter_out
>>>> if thread.routes.routes_out:
>>>> AttributeError: 'thread._local' object has no attribute 'routes'
>>
>>>> As soon as URLs are parsed during Auth initialization, the thread hits
>>>> a case where an invalid "routes" attribute is dereferenced within
>>>> rewrite.py. My threaded code was working until the following change
>>>> was rolled into 1.84.x: "moved DAL and routes to thread.local"
>>
>>