Esempio n. 1
0
    def test_can_have_a_different_should_retry_function(self):
        """
        The ``should_retry`` function does not have to be a
        :obj:`ShouldDelayAndRetry`.
        """
        expected = Retry(effect=Effect(1), should_retry=ANY)
        actual = Retry(effect=Effect(1), should_retry=lambda _: False)

        seq = [
            retry_sequence(expected, [lambda _: raise_(Exception())])
        ]
        self.assertRaises(Exception,
                          perform_sequence, seq, Effect(actual))
Esempio n. 2
0
def lb_req(url, json_response, response):
    """
    Return a SequenceDispatcher two-tuple that matches a service request to a
    particular load balancer endpoint (using GET), and returns the given
    ``response`` as the content in an HTTP 200 ``StubResponse``.
    """
    if isinstance(response, Exception):
        def handler(i): raise response
        log_seq = []
    else:
        def handler(i): return (StubResponse(200, {}), response)
        log_seq = [(Log(mock.ANY, mock.ANY), lambda i: None)]
    return (
        Retry(
            effect=mock.ANY,
            should_retry=ShouldDelayAndRetry(
                can_retry=retry_times(5),
                next_interval=exponential_backoff_interval(2))
        ),
        nested_sequence([
            (service_request(
                ServiceType.CLOUD_LOAD_BALANCERS,
                'GET', url, json_response=json_response).intent,
             handler)
        ] + log_seq)
    )
Esempio n. 3
0
    def perform_retry_without_delay(actual_retry_intent):
        should_retry = actual_retry_intent.should_retry
        if isinstance(should_retry, ShouldDelayAndRetry):

            def should_retry(exc_info):
                exc_type, exc_value, exc_traceback = exc_info
                failure = Failure(exc_value, exc_type, exc_traceback)
                return Effect(
                    Constant(
                        actual_retry_intent.should_retry.can_retry(failure)))

        new_retry_effect = Effect(
            Retry(effect=actual_retry_intent.effect,
                  should_retry=should_retry))

        _dispatchers = [
            TypeDispatcher({Retry: perform_retry}), base_dispatcher
        ]
        if fallback_dispatcher is not None:
            _dispatchers.append(fallback_dispatcher)

        seq = [(expected_retry_intent.effect.intent, performer)
               for performer in performers]

        return perform_sequence(seq, new_retry_effect,
                                ComposedDispatcher(_dispatchers))
Esempio n. 4
0
    def test_do_not_have_to_expect_an_exact_can_retry(self):
        """
        The expected retry intent does not actually have to specify the
        exact ``can_retry`` function, since it might just be a lambda,
        which is hard to compare or hash.
        """
        expected = Retry(effect=Effect(1), should_retry=ANY)
        actual = Retry(effect=Effect(1), should_retry=ShouldDelayAndRetry(
            can_retry=lambda _: False,
            next_interval=repeating_interval(10)))

        seq = [
            retry_sequence(expected, [lambda _: raise_(Exception())])
        ]
        self.assertRaises(Exception,
                          perform_sequence, seq, Effect(actual))
Esempio n. 5
0
def node_feed_req(lb_id, node_id, response):
    """
    Return (intent, performer) sequence for getting clb node's feed that
    wrapped with retry intent.

    :param lb_id: Lodbalancer ID
    :param node_id: LB node ID
    :param response: The response returned when getting CLB node feed. It is
        either string containing feed or Exception object that will be raised
        when getting the feed

    :return: (intent, performer) tuple
    """
    if isinstance(response, Exception):

        def handler(i):
            raise response
    else:

        def handler(i):
            return response

    return (Retry(effect=mock.ANY,
                  should_retry=ShouldDelayAndRetry(
                      can_retry=retry_times(5),
                      next_interval=exponential_backoff_interval(2))),
            nested_sequence([(("gcnf", lb_id, node_id), handler)]))
Esempio n. 6
0
    def _perform_add_event(self, response_sequence):
        """
        Given a sequence of functions that take an intent and returns a
        response (or raises an exception), perform :func:`add_event` and
        return the result.
        """
        log = object()
        eff = add_event(self.event, 'tid', 'ord', log)
        uid = '00000000-0000-0000-0000-000000000000'

        svrq = service_request(
            ServiceType.CLOUD_FEEDS,
            'POST',
            'autoscale/events',
            headers={'content-type': ['application/vnd.rackspace.atom+json']},
            data=self._get_request('INFO', uid, 'tid'),
            log=log,
            success_pred=has_code(201),
            json_response=False)

        seq = [
            (TenantScope(mock.ANY, 'tid'),
             nested_sequence([
                 retry_sequence(
                     Retry(effect=svrq,
                           should_retry=ShouldDelayAndRetry(
                               can_retry=mock.ANY,
                               next_interval=exponential_backoff_interval(2))),
                     response_sequence)
             ]))
        ]

        return perform_sequence(seq, eff)
Esempio n. 7
0
 def test_perform_retry(self):
     """
     When the specified effect is successful, its result is propagated.
     """
     retry = Retry(effect=Effect(Constant('foo')),
                   should_retry=lambda e: 1 / 0)
     result = sync_perform(self.dispatcher, Effect(retry))
     self.assertEqual(result, 'foo')
Esempio n. 8
0
def simple_intents():
    return [
        Authenticate(None, None, None),
        InvalidateToken(None, None),
        Request(method='GET', url='http://example.com/'),
        Retry(effect=Effect(Constant(None)), should_retry=lambda e: False),
        Delay(0),
        Constant(None),
        ReadReference(ref=Reference(None)),
    ]
Esempio n. 9
0
 def test_retry_effect(self):
     """
     :func:`retry_effect` takes an effect and returns an :obj:`Effect` of
     :obj:`Retry`, with a :obj:`ShouldDelayAndRetry` as the should_retry
     callable.
     """
     can_retry = lambda f: True
     next_interval = lambda f: 1
     eff = retry_effect(STUB, can_retry, next_interval)
     self.assertEqual(
         eff,
         Effect(
             Retry(effect=STUB,
                   should_retry=ShouldDelayAndRetry(
                       can_retry=can_retry, next_interval=next_interval))))
Esempio n. 10
0
 def test_retry_sequence_fails_if_mismatch_sequence(self):
     """
     Fail if the wrong number of performers are given.
     """
     r = Retry(
         effect=Effect(1),
         should_retry=ShouldDelayAndRetry(
             can_retry=retry_times(5),
             next_interval=repeating_interval(10)))
     seq = [
         retry_sequence(r, [lambda _: raise_(Exception()),
                            lambda _: raise_(Exception())])
     ]
     self.assertRaises(AssertionError,
                       perform_sequence, seq, Effect(r))
Esempio n. 11
0
 def test_retry_sequence_retries_without_delays(self):
     """
     Perform the wrapped effect with the performers given,
     without any delay even if the original intent had a delay.
     """
     r = Retry(
         effect=Effect(1),
         should_retry=ShouldDelayAndRetry(
             can_retry=retry_times(5),
             next_interval=repeating_interval(10)))
     seq = [
         retry_sequence(r, [lambda _: raise_(Exception()),
                            lambda _: raise_(Exception()),
                            lambda _: "yay done"])
     ]
     self.assertEqual(perform_sequence(seq, Effect(r)), "yay done")
Esempio n. 12
0
    def test_perform_retry_retries_on_error(self):
        """
        When the specified effect raises, it is retried when should_retry
        returns an Effect of True.
        """
        func = _repeated_effect_func(lambda: _raise(RuntimeError("foo")),
                                     lambda: "final")

        def should_retry(exc_info):
            if (exc_info[0] is RuntimeError and exc_info[1].message == "foo"):
                return Effect(Constant(True))
            else:
                return Effect(Constant(False))

        retry = Retry(effect=Effect(Func(func)), should_retry=should_retry)
        result = sync_perform(self.dispatcher, Effect(retry))
        self.assertEqual(result, "final")
Esempio n. 13
0
    def test_fallback(self):
        """
        Accept a ``fallback`` dispatcher that will be used if a performer
        returns an effect for an intent that is not covered by the base
        dispatcher.
        """
        def dispatch_2(intent):
            if intent == 2:
                return sync_performer(lambda d, i: "yay done")

        r = Retry(
            effect=Effect(1),
            should_retry=ShouldDelayAndRetry(
                can_retry=retry_times(5),
                next_interval=repeating_interval(10)))

        seq = [
            retry_sequence(r, [lambda _: Effect(2)],
                           fallback_dispatcher=ComposedDispatcher(
                               [dispatch_2, base_dispatcher]))
        ]
        self.assertEqual(perform_sequence(seq, Effect(r)), "yay done")