Seems very similar to the riprova library. I've found it very useful for asyncio web scrapers.<p><a href="http://riprova.readthedocs.io/en/latest/" rel="nofollow">http://riprova.readthedocs.io/en/latest/</a>
<a href="https://github.com/h2non/riprova" rel="nofollow">https://github.com/h2non/riprova</a>
Cool. If I were maintaining build/deploy nonsense written using Python, this could be quite helpful. A lot of the build/deploy stuff I maintain is -alas- written as Groovy scripts for Jenkins, and I've hand-rolled a similar, simpler wrapper construct. It started up being used to place, and now it's probably used in a dozen places throughout various build, test and deploy scripts.<p>Usage:<p><pre><code> retry_unreliable(3){
sh "essential_but_unreliable_thing --failure-probability 0.01"
}
</code></pre>
Definition:<p><pre><code> def retry_unreliable(int max_attempts, Closure func) {
def error = null
assert max_attempts > 0
def delay_initial = 8.0f
def delay_multiplier = 2.0f
def delay = delay_initial
for (attempt = 0; attempt < max_attempts; attempt++) {
if (error) {
sleep(delay)
delay = delay_multiplier * delay
}
try {
func.call()
error = null
break
} catch (e) {
error = e
println("Unreliable operation failed during attempt ${attempt+1}/${max_attempts}:")
println(e.toString());
}
}
if (error) {
println("Unreliable operation failed repeatedly for ${max_attempts}/${max_attempts} attempts. Gave up")
throw error
}
}
</code></pre>
Sometimes doing something like this isn't necessarily the right course of action -- e.g. if an external service you depend on is struggling to reply to your requests because of load, hammering it with additional requests when it starts to fail isn't the right solution. But quite a lot of time ladling on stupid retry logic turns an irritating rare failure case into a non-issue.