code: public static void retry(Predicate<Integer> action, String label, int times, long delay) throws TooManyRetriesException {
          if (times < 1) {
              throw new IllegalArgumentException("Retry block must try at least 1 time");
          }
  
          if (delay < 1) {
              throw new IllegalArgumentException("Must have at least 1 ms delay");
          }
  
          label = label == null ? "retry block" : label;
  
          int tries = 0;
  
          for (; times > tries; ++tries) {
              try {
                  if (action.test(tries)) return;
              } catch (Exception e) {
                  LOGGER.warn("Attempted to perform {}, but got exception", label, e);
              }
  
              try {
                  Thread.sleep(delay);
              } catch (InterruptedException e) {
                  LOGGER.warn("Couldn't sleep while testing {}", label, e);
              }
          }
  
          throw new TooManyRetriesException(String.format("Retried too many times (%d of %d): %s", tries, times, label));
      }
docs: Simple retry logic with constant delay period, which retries until {@link Predicate} returns true. If you require
  a backoff instead of static delay, it should be very easy to implement.
  
  @param action {@link Predicate<Integer>} defining the action to perform, taking the attempt number as input
  @param label  a user-defined {@link String} describing the action
  @param times  the number of times to try
  @param delay  the period, in milliseconds, to wait between tries
  @throws TooManyRetriesException when all tries have been performed