def test_exponential_growth(self, base, rate): growth = exponential_growth(base, rate) growth_seq = list(islice(growth, 10)) self.assertThat(growth_seq, HasLength(10)) self.assertThat(growth_seq, AllMatch(IsInstance(float))) self.assertEqual(growth_seq, sorted(growth_seq)) self.assertEqual((base * rate), growth_seq[0]) self.assertEqual((base * (rate ** 10)), growth_seq[-1])
def gen_retry_intervals(base=0.01, rate=2.5, maximum=10.0): """Generate retry intervals based on an exponential series. Once any interval exceeds `maximum` the interval generated will forever be `maximum`; this effectively disconnects from the exponential series. All intervals will be subject to "jitter" as a final step. The defaults seem like reasonable coefficients for a capped, full-jitter, exponential back-off series, and were derived by experimentation at the command-line. Real-world experience may teach us better values. """ # An exponentially growing series... intervals = exponential_growth(base, rate) # from which we stop pulling one we've hit a maximum... intervals = takewhile((lambda i: i < maximum), intervals) # and thereafter return the maximum value indefinitely... intervals = chain(intervals, repeat(maximum)) # and to which we add some randomness. return full_jitter(intervals)