code: public static long retryCopy(
        final ByteSource byteSource,
        final ByteSink byteSink,
        final Predicate<Throwable> shouldRetry,
        final int maxAttempts
    )
    {
      try {
        return RetryUtils.retry(
            () -> {
              try (InputStream inputStream = byteSource.openStream()) {
                try (OutputStream outputStream = byteSink.openStream()) {
                  final long retval = ByteStreams.copy(inputStream, outputStream);
                  // Workarround for http://hg.openjdk.java.net/jdk8/jdk8/jdk/rev/759aa847dcaf
                  outputStream.flush();
                  return retval;
                }
              }
            },
            shouldRetry,
            maxAttempts
        );
      }
      catch (Exception e) {
        throw new RuntimeException(e);
      }
    }
docs: Retry copy attempts from input stream to output stream. Does *not* check to make sure data was intact during the transfer
  
  @param byteSource  Supplier for input streams to copy from. The stream is closed on every retry.
  @param byteSink    Supplier for output streams. The stream is closed on every retry.
  @param shouldRetry Predicate to determine if the throwable is recoverable for a retry
  @param maxAttempts Maximum number of retries before failing