Skip to content

Commit

Permalink
Merge pull request #85 from zagy/main
Browse files Browse the repository at this point in the history
Fix retrying transaction when a datamanger marks an exception as retryable
  • Loading branch information
mmerickel authored Nov 14, 2024
2 parents 1475400 + 499803e commit 7826d5e
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 7 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ Unreleased (2024-11-14)

- rename "master" to "main"

- Fix retrying transactions with `pyramid_retry` when using veto and a datamanger
marks the exception as retryable.

2.5 (2022-03-12)
^^^^^^^^^^^^^^^^

Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,4 @@ Contributors
- Sean Hammond, 2019/09/27
- Jon Betts, 2021/04/19
- Jonathan Vanasco, 2022/11/14
- Christian Zagrodnick, 2024/11/04
15 changes: 8 additions & 7 deletions src/pyramid_tm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,14 @@ def tm_tween(request):
if commit_veto is not None:
if commit_veto(request, response):
raise AbortWithResponse(response)
else:
# check for a squashed exception and handle it
# this would happen if an exception view was invoked and
# rendered an error response
exc_info = getattr(request, 'exc_info', None)
if exc_info is not None:
maybe_tag_retryable(request, exc_info)

# check for a squashed exception and handle it
# this would happen if an exception view was invoked and
# rendered an error response
exc_info = getattr(request, 'exc_info', None)
if exc_info is not None:
maybe_tag_retryable(request, exc_info)
if commit_veto is None:
raise AbortWithResponse(response)

return _finish(request, manager.commit, response)
Expand Down
44 changes: 44 additions & 0 deletions tests/test_it.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,50 @@ def view(request):
self.assertEqual(calls, ['fail', 'ok'])
self.assertEqual(result.body, b'ok')

@skip_if_missing('pyramid_retry')
def test_error_is_retried_with_commit_veto_and_error_view_and_retry_data_manager(
self,
):
class Conflict(Exception):
"""This is not a Transient error."""

class RetryDataManager(DummyDataManager):
"""The datamanager wants the Conflict to be retried."""

def should_retry(self, exception):
return isinstance(exception, Conflict)

def exc_view(request):
return 'failure'

config = self.config
config.add_settings(
{
'retry.attempts': 2,
'tm.commit_veto': lambda request, response: False,
}
)
config.include('pyramid_retry')
config.add_view(exc_view, context=Exception, renderer='string')

calls = []

def view(request):
print(calls)
dm = RetryDataManager()
dm.bind(request.tm)
if len(calls) < 1:
calls.append('fail')
raise Conflict
calls.append('ok')
return 'ok'

config.add_view(view, renderer='string')
app = self._makeApp()
result = app.get('/')
self.assertEqual(calls, ['fail', 'ok'])
self.assertEqual(result.body, b'ok')

def test_unhandled_error_aborts(self):
config = self.config
dm = DummyDataManager()
Expand Down

0 comments on commit 7826d5e

Please sign in to comment.