public static void retryWithBackoff(
      final int maxRetries,
      final int initialWaitMs,
      final int maxWaitMs,
      final Runnable runnable,
      final Class<?>... passThroughExceptions) {
    retryWithBackoff(
        maxRetries,
        initialWaitMs,
        maxWaitMs,
        runnable,
        () -> false,
        Arrays.stream(passThroughExceptions)
            .map(c -> (Predicate<Exception>) c::isInstance)
            .collect(Collectors.toList())
    );
  }
@Test
  public void shouldRespectStopRetrying() {
    doThrow(new RuntimeException("error")).when(runnable).run();
    int[] times = new int[1];
    boolean[] stopRetrying = new boolean[1];
    doAnswer(invocationOnMock -> {
      // Interrupts on the 2nd sleep
      if (times[0]++ == 1) {
        stopRetrying[0] = true;
      }
      return null;
    }).when(sleep).accept(any());
    assertThrows(RuntimeException.class,
        () -> RetryUtil.retryWithBackoff(3, 1, 100, runnable, sleep, () -> stopRetrying[0],
            Collections.emptyList()));
    verify(runnable, times(2)).run();
    final InOrder inOrder = Mockito.inOrder(sleep);
    inOrder.verify(sleep).accept((long) 1);
    inOrder.verify(sleep).accept((long) 2);
    inOrder.verifyNoMoreInteractions();
  }