[Repoze-checkins] r1095 - in repoze.retry/trunk: . repoze/retry
Chris McDonough
chrism at agendaless.com
Sun Jun 15 23:53:56 EDT 2008
Author: Chris McDonough <chrism at agendaless.com>
Date: Sun Jun 15 23:53:55 2008
New Revision: 1095
Log:
Fixed concurrency bug whereby a response from one request might be
returned as result of a different request.
Initial PyPI release.
Modified:
repoze.retry/trunk/CHANGES.txt
repoze.retry/trunk/README.txt
repoze.retry/trunk/repoze/retry/__init__.py
repoze.retry/trunk/repoze/retry/tests.py
repoze.retry/trunk/setup.py
Modified: repoze.retry/trunk/CHANGES.txt
==============================================================================
--- repoze.retry/trunk/CHANGES.txt (original)
+++ repoze.retry/trunk/CHANGES.txt Sun Jun 15 23:53:55 2008
@@ -1,3 +1,10 @@
+0.9 (2008-06-15)
+
+ Fixed concurrency bug whereby a response from one request might be
+ returned as result of a different request.
+
+ Initial PyPI release.
+
0.8
Added WSGI conformance testing for the middleware.
Modified: repoze.retry/trunk/README.txt
==============================================================================
--- repoze.retry/trunk/README.txt (original)
+++ repoze.retry/trunk/README.txt Sun Jun 15 23:53:55 2008
@@ -1,27 +1,38 @@
repoze.retry README
+=====================
- Overview
+This package implements a WSGI middleware filter which intercepts
+"retryable" exceptions and retries the WSGI request a configurable
+number of times. If the request cannot be satisfied via retries, the
+exception is reraised.
- This package implements a WSGI Middleware filter which intercepts
- "retryable" exceptions and retries the WSGI request a configurable number
- of times.
+Installation
+------------
- Installation
+Install using setuptools, e.g. (within a virtualenv)::
- The simple way::
+ $ easy_install repoze.retry
- $ bin/easy_install --find-links=http://dist.repoze.org/ repoze.retry
+Configuration via Python
+------------------------
- Configuraiton
-
- By default, the retryable exception is 'ZODB.POSException.ConflictError';
- the 'tries' count defaults to 3 times.
+Wire up the middleware in your application::
+
+ from repoze.retry import Retry
+ mw = Retry(app, tries=3, retryable=(ValueError, IndexError))
- If you want to use the default configuration, you can just include the
- filter in your application's pipeline. Note that the filter should come
- before (to the "left") of the 'repoze.tm' filter, your pipeline includes
- it, so that retried requests are first aborted and then restarted in a
- new transaction::
+By default, the retryable exception is ``repoze.retry.ConflictError``
+(or if ZODB is installed, it's ``ZODB.POSException.ConflictError``);
+the ``tries`` count defaults to 3 times.
+
+Configuration via Paste
+-----------------------
+
+If you want to use the default configuration, you can just include the
+filter in your application's pipeline. Note that the filter should
+come before (to the "left") of the ``repoze.tm`` filter, your pipeline
+includes it, so that retried requests are first aborted and then
+restarted in a new transaction::
[pipeline:main]
pipeline = egg:Paste#cgitb
@@ -31,19 +42,26 @@
egg:repoze.vhm#vhm_xheaders
zope2
- If you want to override the defaults, e.g. to change the number of retries,
- or the exceptions which will be retried, you need to make a separate section
- for the filter::
+If you want to override the defaults, e.g. to change the number of retries,
+or the exceptions which will be retried, you need to make a separate section
+for the filter::
[filter:retry]
use = egg:repoze.retry
tries = 2
retryable = egg:mypackage.exceptions:SomeRetryableException
- and then use it in the pipeline::
+and then use it in the pipeline::
[pipeline:main]
pipeline = egg:Paste#cgitb
egg:Paste#httpexceptions
retry
myapp
+
+Reporting Bugs / Development Versions
+-------------------------------------
+
+Visit http://bugs.repoze.org to report bugs. Visit
+http://svn.repoze.org to download development or tagged versions.
+
Modified: repoze.retry/trunk/repoze/retry/__init__.py
==============================================================================
--- repoze.retry/trunk/repoze/retry/__init__.py (original)
+++ repoze.retry/trunk/repoze/retry/__init__.py Sun Jun 15 23:53:55 2008
@@ -1,5 +1,6 @@
# repoze retry-on-conflict-error behavior
import traceback
+import itertools
try:
from ZODB.POSException import ConflictError
@@ -20,7 +21,6 @@
"""
self.application = application
self.tries = tries
- self.start_response_result = None
if retryable is None:
retryable = ConflictError
@@ -30,22 +30,18 @@
self.retryable = tuple(retryable)
- def buffer_start_response(self, *arg, **kw):
- # we can't successfully retry if a downstream application has already
- # called start_response, so we buffer the result and call the
- # original start_response if we don't
- self.start_response_result = (arg, kw)
-
- def call_start_response(self, start_response):
- if self.start_response_result is not None:
- arg, kw = self.start_response_result
- start_response(*arg, **kw)
-
def __call__(self, environ, start_response):
+ catch_response = []
+ written = []
+
+ def replace_start_response(status, headers, exc_info=None):
+ catch_response[:] = [status, headers, exc_info]
+ return written.append
+
i = 0
while 1:
try:
- result = self.application(environ, self.buffer_start_response)
+ app_iter = self.application(environ, replace_start_response)
except self.retryable, e:
i += 1
if environ.get('wsgi.errors'):
@@ -54,12 +50,13 @@
traceback.print_exc(environ['wsgi.errors'])
if i < self.tries:
continue
- self.call_start_response(start_response)
+ if catch_response:
+ start_response(*catch_response)
raise
else:
- self.call_start_response(start_response)
- return result
-
+ if catch_response:
+ start_response(*catch_response)
+ return itertools.chain(written, app_iter)
def make_retry(app, global_conf, **local_conf):
from pkg_resources import EntryPoint
Modified: repoze.retry/trunk/repoze/retry/tests.py
==============================================================================
--- repoze.retry/trunk/repoze/retry/tests.py (original)
+++ repoze.retry/trunk/repoze/retry/tests.py Sun Jun 15 23:53:55 2008
@@ -10,7 +10,7 @@
_MINIMAL_HEADERS = [('Content-Type', 'text/plain')]
-def _faux_start_response(result, headers):
+def _faux_start_response(result, headers, exc_info=None):
pass
class RetryTests(unittest.TestCase, CEBase):
@@ -39,8 +39,9 @@
application = DummyApplication(conflicts=5)
retry = self._makeOne(application, tries=4,
retryable=(self.ConflictError,))
+ env = self._makeEnv()
self.failUnlessRaises(self.ConflictError,
- retry, self._makeEnv(), _faux_start_response)
+ retry, env, _faux_start_response)
self.assertEqual(application.called, 4)
def _dummy_start_response(self, *arg):
@@ -54,7 +55,7 @@
self._dummy_start_response)
self.assertEqual(application.called, 4)
self.assertEqual(self._dummy_start_response_result,
- ('200 OK', _MINIMAL_HEADERS))
+ ('200 OK', _MINIMAL_HEADERS, None))
def test_conflict_not_raised_start_response_called(self):
application = DummyApplication(conflicts=1, call_start_response=True)
@@ -63,7 +64,7 @@
result = retry(self._makeEnv(), self._dummy_start_response)
self.assertEqual(application.called, 1)
self.assertEqual(self._dummy_start_response_result,
- ('200 OK', _MINIMAL_HEADERS))
+ ('200 OK', _MINIMAL_HEADERS, None))
self.assertEqual(list(result), ['hello'])
def test_alternate_retryble_exception(self):
Modified: repoze.retry/trunk/setup.py
==============================================================================
--- repoze.retry/trunk/setup.py (original)
+++ repoze.retry/trunk/setup.py Sun Jun 15 23:53:55 2008
@@ -1,15 +1,16 @@
-__version__ = '0.8dev'
+__version__ = '0.9'
import os
from setuptools import setup, find_packages
here = os.path.abspath(os.path.dirname(__file__))
README = open(os.path.join(here, 'README.txt')).read()
+CHANGES = open(os.path.join(here, 'CHANGES.txt')).read()
setup(name='repoze.retry',
version=__version__,
description='Middleware which implements a retryable exceptions',
- long_description=README,
+ long_description=README + '\n\n' + CHANGES,
classifiers=[
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
@@ -18,7 +19,7 @@
"Topic :: Internet :: WWW/HTTP :: WSGI",
"Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware",
],
- keywords='web application server wsgi zope',
+ keywords='wsgi middleware retry',
author="Agendaless Consulting",
author_email="repoze-dev at lists.repoze.org",
url="http://www.repoze.org",
More information about the Repoze-checkins
mailing list