[Repoze-checkins] r1101 - in repoze.retry/trunk: . repoze/retry

Chris McDonough chrism at agendaless.com
Wed Jun 18 12:35:30 EDT 2008


Author: Chris McDonough <chrism at agendaless.com>
Date: Wed Jun 18 12:35:29 2008
New Revision: 1101

Log:
Seek wsgi.input back to zero before retrying a request due to a
conflict error.



Modified:
   repoze.retry/trunk/CHANGES.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	Wed Jun 18 12:35:29 2008
@@ -1,3 +1,8 @@
+0.9.1 (2008-06-18)
+
+ Seek wsgi.input back to zero before retrying a request due to a
+ conflict error.
+
 0.9 (2008-06-15)
 
  Fixed concurrency bug whereby a response from one request might be

Modified: repoze.retry/trunk/repoze/retry/__init__.py
==============================================================================
--- repoze.retry/trunk/repoze/retry/__init__.py	(original)
+++ repoze.retry/trunk/repoze/retry/__init__.py	Wed Jun 18 12:35:29 2008
@@ -1,6 +1,8 @@
 # repoze retry-on-conflict-error behavior
-import traceback
 import itertools
+import os
+import traceback
+from tempfile import TemporaryFile
 
 try:
     from ZODB.POSException import ConflictError
@@ -33,6 +35,24 @@
     def __call__(self, environ, start_response):
         catch_response = []
         written = []
+        original_wsgi_input = environ.get('wsgi.input')
+        new_wsgi_input = None
+
+        if original_wsgi_input is not None:
+            cl = environ.get('CONTENT_LENGTH', '0')
+            cl = int(cl)
+            new_wsgi_input = environ['wsgi.input'] = TemporaryFile('w+b')
+            rest = cl
+            chunksize = 1<<20
+            while rest:
+                if rest <= chunksize:
+                    chunk = original_wsgi_input.read(rest)
+                    rest = 0
+                else:
+                    chunk = original_wsgi_input.read(chunksize)
+                    rest = rest - chunksize
+                new_wsgi_input.write(chunk)
+            new_wsgi_input.seek(0)
 
         def replace_start_response(status, headers, exc_info=None):
             catch_response[:] = [status, headers, exc_info]
@@ -49,6 +69,8 @@
                     errors.write('repoze.retry retrying, count = %s\n' % i)
                     traceback.print_exc(environ['wsgi.errors'])
                 if i < self.tries:
+                    if new_wsgi_input is not None:
+                        new_wsgi_input.seek(0)
                     continue
                 if catch_response:
                     start_response(*catch_response)

Modified: repoze.retry/trunk/repoze/retry/tests.py
==============================================================================
--- repoze.retry/trunk/repoze/retry/tests.py	(original)
+++ repoze.retry/trunk/repoze/retry/tests.py	Wed Jun 18 12:35:29 2008
@@ -90,6 +90,33 @@
         self.assertEqual(list(result), ['hello'])
         self.assertEqual(app2.called, 1)
 
+    def test_wsgi_input_seeked_to_zero_on_conflict_withcontentlen(self):
+        application = DummyApplication(conflicts=3, call_start_response=True)
+        retry = self._makeOne(application, tries=4,
+                              retryable=(self.ConflictError,))
+        env = self._makeEnv()
+        data = 'x' * 1000
+        env['CONTENT_LENGTH'] = str(len(data))
+        from StringIO import StringIO
+        env['wsgi.input'] = StringIO(data)
+        result = retry(env, self._dummy_start_response)
+        self.assertEqual(application.called, 3)
+        self.failIf(isinstance(env['wsgi.input'], StringIO))
+        self.assertEqual(application.wsgi_input, data)
+
+    def test_wsgi_input_seeked_to_zero_on_conflict_nocontentlen(self):
+        application = DummyApplication(conflicts=3, call_start_response=True)
+        retry = self._makeOne(application, tries=4,
+                              retryable=(self.ConflictError,))
+        env = self._makeEnv()
+        data = 'x' * 1000
+        from StringIO import StringIO
+        env['wsgi.input'] = StringIO(data)
+        result = retry(env, self._dummy_start_response)
+        self.assertEqual(application.called, 3)
+        self.failIf(isinstance(env['wsgi.input'], StringIO))
+        self.assertEqual(application.wsgi_input, '')
+
 class WSGIConformanceTests(RetryTests):
 
     def setUp(self):
@@ -183,6 +210,7 @@
         if exception is None:
             exception = self.ConflictError
         self.exception = exception
+        self.wsgi_input = ''
 
     def __call__(self, environ, start_response):
         if self.call_start_response:
@@ -190,6 +218,8 @@
         if self.called < self.conflicts:
             self.called += 1
             raise self.exception
+        if environ.get('wsgi.input'):
+            self.wsgi_input = environ['wsgi.input'].read()
         if self.call_start_response:
             return ['hello']
         # Dead chicken (see above)

Modified: repoze.retry/trunk/setup.py
==============================================================================
--- repoze.retry/trunk/setup.py	(original)
+++ repoze.retry/trunk/setup.py	Wed Jun 18 12:35:29 2008
@@ -1,4 +1,4 @@
-__version__ = '0.9'
+__version__ = '0.9.1'
 
 import os
 from setuptools import setup, find_packages


More information about the Repoze-checkins mailing list