Hacker News new | ask | show | jobs
by masklinn 3100 days ago
Nothing precludes a similar approach in Python:

    def backoff(wait=5, exponent=1.5):
        while True:
            yield
            sleep(wait)
            wait = wait ** exponent

    for backoff():
        connect_to_a_thing()
Here's the question: do you need exponential backoff in more than one place? Because if you don't, bundling all of that doesn't buy you anything and the original works just fine.

> This is trivially composable with any other control flow you might want to write in Ruby.

And it is actually trivially composable with other Python control flow, it's just a backoff iterator, you can drive it however you want, or compose it with other iterators (e.g. enumerate() to know which instance you're on, islice to stop after a certain number of tries, …)

1 comments

Your solution is much cleaner to me, except (not really knowing Python) it looks like it might have a bug, in that the `while True` will never terminate.
> the `while True` will never terminate

The iterator is infinite on purpose (it has no reason to be finite).

You'd terminate it from outside, either when the operation succeeds, so the example loop should more properly be something along the lines of:

    for _ in backoff():
        try:
            c = connect_to_a_thing()
            break
        except ConnectionError:
            pass # retry
or you'd use composition to e.g. stop after a set number of tries:

    for _ in itertools.islice(backoff(), 5):
        # do stuff
most likely a combination of both.
I think you can break the for loop after the function call and it'll end after the wait is successful. Bit of a hack though