def retry_call(run, fail_cb=None):
  last_retcode = None
  cmd = ' '.join(run)
  for i in range(0, cfg.download_attempts):
    logging.info('Attempt %s at running %s', i + 1, cmd)
    # Let STDOUT trickle down to the log file
    proc = subprocess.Popen(run, stderr=subprocess.PIPE)
    _, stderr = proc.communicate()
    last_retcode = proc.returncode
    if last_retcode:
      msg = 'Attempt {0} at {1} failed ({2}): {3}'.format(i + 1, repr(cmd),
                                                          last_retcode,
                                                          stderr)
      logging.warn(msg)
      if fail_cb is not None:
        fail_cb(msg)
      time.sleep(cfg.poll_delay_secs)
    else:
      # Done!
      return
  # All attempts failed
  raise subprocess.CalledProcessError(last_retcode, run[0])

# Data structure
If rollback fails, L{ConnectionPool.runInteraction} raises the
dataset/ETHPy150Open GoogleCloudPlatform/compute-hadoop-java-python/util.py/retry_call--crossover with--dataset/ETHPy150Open kuri65536/python-for-android/python-modules/twisted/twisted/test/test_adbapi.py/ConnectionPoolTestCase.test_runWithInteractionRaiseOriginalError