code: static function runWithRetry($maxRetries, $action)
      {
          Checker::argNat("maxRetries", $maxRetries);
  
          $retryDelay = 1;
          $numRetries = 0;
          while (true) {
              try {
                  return $action();
              }
              // These exception types are the ones we think are possibly transient errors.
              catch (Exception_NetworkIO $ex) {
                  $savedEx = $ex;
              }
              catch (Exception_ServerError $ex) {
                  $savedEx = $ex;
              }
              catch (Exception_RetryLater $ex) {
                  $savedEx = $ex;
              }
  
              // We maxed out our retries.  Propagate the last exception we got.
              if ($numRetries >= $maxRetries) throw $savedEx;
  
              $numRetries++;
              sleep($retryDelay);
              $retryDelay *= 2;  // Exponential back-off.
          }
          throw new \RuntimeException("unreachable");
      }
docs: @param int $maxRetries
  The number of times to retry it the action if it fails with one of the transient
  API errors.  A value of 1 means we'll try the action once and if it fails, we
  will retry once.
  
  @param callable $action
  The the action you want to retry.
  
  @return mixed
  Whatever is returned by the $action callable.