def read(self): """Return an item.""" if self._run: raise Abort('testing', {}) self._run = True return 1
async def _retry(app, message, exc): """Retry the message. An exception that is included as a retryable type will result in the message being retried so long as the threshold and timeout haven't been reached. Args: app (henson.base.Application): The current application. message (dict): The message to be retried. exc (Exception): The exception that caused processing the message to fail. Raises: Abort: If the message is scheduled to be retried. """ if not isinstance(exc, app.settings['RETRY_EXCEPTIONS']): # If the exception raised isn't retryable, return control so the # next error callback can be called. return settings = _get_settings(app, exc) retry_info = _retry_info(message) threshold = settings['RETRY_THRESHOLD'] if _exceeded_threshold(retry_info['count'], threshold): # If we've exceeded the number of times to retry the message, # don't retry it again. return timeout = settings['RETRY_TIMEOUT'] if _exceeded_timeout(retry_info['start_time'], timeout): # If we've gone past the time to stop retrying, don't retry it # again. return if settings['RETRY_DELAY']: # If a delay has been specified, calculate the actual delay # based on any backoff and then sleep for that long. Add the # delay time to the retry information so that it can be used # to gain insight into the full history of a retried message. retry_info['delay'] = _calculate_delay( delay=settings['RETRY_DELAY'], backoff=settings['RETRY_BACKOFF'], number_of_retries=retry_info['count'], ) await asyncio.sleep(retry_info['delay']) # Update the retry information and retry the message. retry_info['count'] += 1 message['_retry'] = retry_info await settings['RETRY_CALLBACK'](app, message) # If the exception was retryable, none of the other callbacks should # execute. raise Abort('message.retried', message)
async def read(self): nonlocal consumer_called consumer_called = True raise Abort('reason', 'message')
'RETRY_BACKOFF', None) == backoff assert test_app.settings['RETRY_OVERRIDES'][exception].get( 'RETRY_CALLBACK', None) == callback_arg assert test_app.settings['RETRY_OVERRIDES'][exception].get( 'RETRY_DELAY', None) == delay assert test_app.settings['RETRY_OVERRIDES'][exception].get( 'RETRY_THRESHOLD', None) == threshold assert test_app.settings['RETRY_OVERRIDES'][exception].get( 'RETRY_TIMEOUT', None) == timeout @pytest.mark.parametrize( 'exc, expected, excs', ( (KeyError('test KeyError'), 1.1, (OSError, KeyError, Abort)), (Abort('test', {}), 1.1, (OSError, Abort)), # Confirm we can handle a single exception and not a tuple (OSError('test OSError'), 1.05, OSError), # Test that inheritance is working properly (TestRetryChildAException(), 2.05, TestRetryParentException), (TestRetryGrandchildException(), 2.05, TestRetryParentException), (TestRetryChildBException(), 3.05, TestRetryParentException), (TestRetryRedHerringException(), 1.1, TestRetryParentException))) @pytest.mark.asyncio async def test_get_settings(test_app: Application, coroutine: Coroutine, exc: Exception, excs, expected: bool): """Test that _get_settings is grabbing the proper settings working.""" test_app.settings['RETRY_CALLBACK'] = coroutine test_app.settings['RETRY_BACKOFF'] = 1.1