def __init__(self):
        retry_policy = RetryPolicy(allowed_retries=4)

        self.failsafe = Failsafe(retry_policy=retry_policy,
                                 circuit_breaker=CircuitBreaker(maximum_failures=8))

        self.failsafe_fallback = Failsafe(retry_policy=retry_policy,
                                          circuit_breaker=CircuitBreaker(maximum_failures=8))
示例#2
0
    def test_retry_on_custom_exception(self):
        failing_operation = create_failing_operation()
        retries = 3
        policy = RetryPolicy(retries, [SomeRetriableException])
        failsafe = Failsafe(retry_policy=policy)

        assert failing_operation.called == 0

        with pytest.raises(RetriesExhausted):
            loop.run_until_complete(failsafe.run(failing_operation))

        assert failing_operation.called == retries + 1
示例#3
0
    def test_retry_four_times(self):
        failing_operation = create_failing_operation()
        expected_attempts = 5
        retries = 4
        policy = RetryPolicy(retries)
        failsafe = Failsafe(retry_policy=policy)

        assert failing_operation.called == 0

        with pytest.raises(RetriesExhausted):
            loop.run_until_complete(failsafe.run(failing_operation))

        assert failing_operation.called == expected_attempts
示例#4
0
 def test_backoff(self):
     failing_operation = create_failing_operation()
     retries = 3
     backoff = Backoff(timedelta(seconds=0.2), timedelta(seconds=1))
     policy = RetryPolicy(retries, [SomeRetriableException],
                          backoff=backoff)
     Failsafe(retry_policy=policy)
     with pytest.raises(RetriesExhausted):
         loop.run_until_complete(
             Failsafe(retry_policy=policy).run(failing_operation))
     assert asyncio.sleep.mock_calls == [
         call(0.2),
         call(0.4),
         call(0.8),
     ]
示例#5
0
 def test_basic_retry(self):
     succeeding_operation = create_succeeding_operation()
     policy = RetryPolicy()
     loop.run_until_complete(
         Failsafe(retry_policy=policy).run(succeeding_operation)
     )
     assert succeeding_operation.called == 1
 def __init__(self,
              url,
              auth=None,
              session=None,
              trailing_slash=False,
              retries=6,
              autopaginate=None):
     if auth is not None and not isinstance(auth, aiohttp.BasicAuth):
         auth = aiohttp.BasicAuth(*auth)
     super(GenericClient, self).__init__(url, auth, session, trailing_slash,
                                         autopaginate)
     max_failures = retries - 1
     circuit_breaker = CircuitBreaker(maximum_failures=max_failures)
     retry_policy = RetryPolicy(
         allowed_retries=retries,
         retriable_exceptions=[ClientConnectionError],
         abortable_exceptions=[
             exceptions.BadRequestError,
             exceptions.NotAuthenticatedError,
             exceptions.ResourceNotFound,
             exceptions.MultipleResourcesFound,
             exceptions.HTTPError,
             ValueError,
         ],
     )
     self.failsafe = Failsafe(circuit_breaker=circuit_breaker,
                              retry_policy=retry_policy)
示例#7
0
    def test_circuit_breaker_with_retries(self):
        failing_operation = create_failing_operation()

        with pytest.raises(CircuitOpen):
            policy = RetryPolicy(5, [SomeRetriableException])
            circuit_breaker = CircuitBreaker(maximum_failures=2)
            loop.run_until_complete(
                Failsafe(
                    retry_policy=policy,
                    circuit_breaker=circuit_breaker).run(failing_operation))
        assert failing_operation.called == 2
示例#8
0
    def test_failsafe_on_method_with_arguments(self):
        class Operation:
            async def task_with_arguments(self, x, y=0):
                result = x + y
                return "{0}_{1}".format(self.__class__.__name__, result)

        operation = Operation()
        obtained = loop.run_until_complete(
            Failsafe().run(operation.task_with_arguments, 41, y=1)
        )
        assert obtained == "{0}_42".format(Operation.__name__)
示例#9
0
 def test_circuit_breaker_circuitopener_raises_circuitopen_with_cause(self):
     original_exception = SomeRetriableException("My Error Message")
     failing_operation = create_failing_operation(original_exception)
     try:
         policy = RetryPolicy(5, [SomeRetriableException])
         circuit_breaker = CircuitBreaker(maximum_failures=2)
         loop.run_until_complete(
             Failsafe(
                 retry_policy=policy,
                 circuit_breaker=circuit_breaker).run(failing_operation))
         raise Exception("Expected CircuitOpen exception")
     except CircuitOpen as e:
         assert e.__cause__ is original_exception
示例#10
0
    def test_circuit_breaker_with_abort(self):
        aborting_operation = create_aborting_operation()

        policy = RetryPolicy(abortable_exceptions=[SomeAbortableException])
        circuit_breaker = CircuitBreaker(maximum_failures=2)

        circuit_breaker.record_failure = MagicMock()
        with pytest.raises(SomeAbortableException):
            loop.run_until_complete(
                Failsafe(
                    retry_policy=policy,
                    circuit_breaker=circuit_breaker).run(aborting_operation))
        circuit_breaker.record_failure.assert_not_called()

        assert aborting_operation.called == 1
示例#11
0
    def test_circuit_breaker_opened_circuit_has_no_cause(self):
        failing_operation = create_failing_operation()
        try:
            policy = RetryPolicy(5, [SomeRetriableException])
            circuit_breaker = CircuitBreaker(maximum_failures=2)
            circuit_breaker.open()

            loop.run_until_complete(
                Failsafe(
                    retry_policy=policy,
                    circuit_breaker=circuit_breaker).run(failing_operation))
            raise Exception("Expected CircuitOpen exception")
        except CircuitOpen as e:
            assert e.__cause__ is None
        assert failing_operation.called == 0
示例#12
0
 def __init__(self):
     self.failsafe = Failsafe(
         retry_policy=RetryPolicy(allowed_retries=4,
                                  abortable_exceptions=[NotFoundError]),
         circuit_breaker=CircuitBreaker(maximum_failures=8))
示例#13
0
from .utils import apply_filters, remove_script_tags, remove_meta_fragment_tag, is_yesish

logger = logging.getLogger(__name__)
executor = ThreadPoolExecutor(max_workers=cpu_count() * 5)

HTML_FILTERS: Tuple[Callable[[str], str]] = (remove_script_tags,
                                             remove_meta_fragment_tag)
ALLOWED_DOMAINS: Set = set(
    dm.strip() for dm in os.getenv('ALLOWED_DOMAINS', '').split(',')
    if dm.strip())
CACHE_LIVE_TIME: int = int(os.getenv('CACHE_LIVE_TIME', 3600))
SENTRY_DSN: Optional[str] = os.getenv('SENTRY_DSN')
_ENABLE_CB = is_yesish(os.getenv('ENABLE_CIRCUIT_BREAKER', '0'))
_CB_FAIL_MAX: int = int(os.getenv('CIRCUIT_BREAKER_FAIL_MAX', 5))
_CB_RESET_TIMEOUT: int = int(os.getenv('CIRCUIT_BREAKER_RESET_TIMEOUT', 60))
_BREAKERS = defaultdict(lambda: Failsafe(circuit_breaker=CircuitBreaker(
    maximum_failures=_CB_FAIL_MAX, reset_timeout_seconds=_CB_RESET_TIMEOUT)))

if SENTRY_DSN:
    sentry = raven.Client(
        SENTRY_DSN,
        transport=AioHttpTransport,
        release=raven.fetch_package_version('prerender'),
        site='Prerender',
    )
else:
    sentry = None


def _save_to_cache(key: str, data: bytes, format: str = 'html') -> None:
    try:
        cache.set(key, data, CACHE_LIVE_TIME, format)
示例#14
0
 def test_no_retry(self):
     succeeding_operation = create_succeeding_operation()
     loop.run_until_complete(Failsafe().run(succeeding_operation))
示例#15
0
 def _create_failsafe(option):
     return Failsafe(retry_policy=retry_policy_factory(option),
                     circuit_breaker=circuit_breaker_factory(option))
示例#16
0
import os

import aiohttp
from failsafe import CircuitBreaker, Failsafe, FailsafeError, RetryPolicy
from sanic import Sanic
from sanic.response import json, text
from sanic_prometheus import monitor

app = Sanic()
circuit = CircuitBreaker(
    maximum_failures=3, 
    reset_timeout_seconds=10
)

failsafe = Failsafe(
    circuit_breaker=circuit,
    retry_policy=RetryPolicy()
)


@app.route("/")
async def index(request):
    return text("Hello world!")


@app.route("/health")
async def health(request):
    if circuit.current_state == "open":
        return text("Unavailable", status=503)

    return text("OK")