diff options
| author | Chris McDonough <chrism@agendaless.com> | 2010-09-07 20:48:54 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2010-09-07 20:48:54 +0000 |
| commit | 75aa412d1dadda6c955e094e91380c7ae70695fb (patch) | |
| tree | c2155e3bd22304dd9195750ad9f6ab21149ec08d /repoze | |
| parent | 0db2acfc4ce715d62f73a8e4d06784149ecd5071 (diff) | |
| download | pyramid-75aa412d1dadda6c955e094e91380c7ae70695fb.tar.gz pyramid-75aa412d1dadda6c955e094e91380c7ae70695fb.tar.bz2 pyramid-75aa412d1dadda6c955e094e91380c7ae70695fb.zip | |
- Prevent a race condition which could result in a ``RuntimeError``
when rendering a Chameleon template that has not already been
rendered once. This would usually occur directly after a restart,
when more than one person or thread is trying to execute the same
view at the same time: https://bugs.launchpad.net/karl3/+bug/621364
Diffstat (limited to 'repoze')
| -rw-r--r-- | repoze/bfg/renderers.py | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/repoze/bfg/renderers.py b/repoze/bfg/renderers.py index 13e578d36..e4e19013c 100644 --- a/repoze/bfg/renderers.py +++ b/repoze/bfg/renderers.py @@ -1,5 +1,6 @@ import os import pkg_resources +import threading from webob import Response @@ -150,7 +151,12 @@ def string_renderer_factory(name): # utility functions, not API -def template_renderer_factory(spec, impl): +# Lock to prevent simultaneous registry writes; used in +# template_renderer_factory. template_renderer_factory may be called +# at runtime, from more than a single thread. +registry_lock = threading.Lock() + +def template_renderer_factory(spec, impl, lock=registry_lock): reg = get_current_registry() if os.path.isabs(spec): # 'spec' is an absolute filename @@ -159,7 +165,12 @@ def template_renderer_factory(spec, impl): renderer = reg.queryUtility(ITemplateRenderer, name=spec) if renderer is None: renderer = impl(spec) - reg.registerUtility(renderer, ITemplateRenderer, name=spec) + # cache the template + try: + lock.acquire() + reg.registerUtility(renderer, ITemplateRenderer, name=spec) + finally: + lock.release() else: # spec is a package:relpath resource spec renderer = reg.queryUtility(ITemplateRenderer, name=spec) @@ -178,7 +189,11 @@ def template_renderer_factory(spec, impl): renderer = impl(abspath) if not _reload_resources(): # cache the template - reg.registerUtility(renderer, ITemplateRenderer, name=spec) + try: + lock.acquire() + reg.registerUtility(renderer, ITemplateRenderer, name=spec) + finally: + lock.release() return renderer |
