summaryrefslogtreecommitdiff
path: root/repoze
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2010-09-07 20:48:54 +0000
committerChris McDonough <chrism@agendaless.com>2010-09-07 20:48:54 +0000
commit75aa412d1dadda6c955e094e91380c7ae70695fb (patch)
treec2155e3bd22304dd9195750ad9f6ab21149ec08d /repoze
parent0db2acfc4ce715d62f73a8e4d06784149ecd5071 (diff)
downloadpyramid-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.py21
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