On Tue, Jan 24, 2012 at 1:01 PM, Chris Rebert
On 24 Jan 2012, at 14:06, Nick Coghlan
wrote: On Tue, Jan 24, 2012 at 9:36 PM, Paul Moore
wrote: [ sees value in a RetryStrategy construct of some sort]
You just need to move the pause inside the iterator:
def backoff(attempts, first_delay, scale=2): delay = first_delay for attempt in range(1, attempts+1): yield attempt time.sleep(delay) delay *= 2
for __ in backoff(MAX_ATTEMPTS, 5): try: response = urllib2.urlopen(url) except urllib2.HTTPError as e: if e.code == 503: # Service Unavailable. continue raise break
On Tue, Jan 24, 2012 at 7:21 AM, Jakob Bowyer
wrote: Would this not be better expressed as a context manager?
with backoff(maxattempts, 5): # do stuff
It can't be.
It really should be, though. What do to on a fixable or temporary failure is pretty clearly an execution context.
The `with` statement always executes its block exactly once; the context manager(s) have no say in the matter (unless perhaps you count raising an exception prior to the block's execution).
with RetryStrategy() as keepgoing: while keepgoing(): ... The catch is that keepgoing() is usually either simple enough to inline (even without the with statement) or sufficiently complicated that it needs to modify something the rest of the suite sees. Passing an object just to hold these changes adds its own code smell. -jJ