Java 8 - retry a method until a condition is fulfilled (in intervals)

て烟熏妆下的殇ゞ 提交于 2019-12-02 20:47:14

Yes, this can easily be done in Java 7 and even cleaner using Java 8.

The parameter to your method method should be a java.util.function.Supplier<T> and the parameter to your until method should be a java.util.function.Predicate<T>.

You can then use method references or lambda expressions to create you Poller like so:

myMethodPoller.poll(pollDurationInteger, intervalInMillisecond)
          .method(payment::getStatus)
          .until (paymentStatus -> paymentStatus.getValue().equals("COMPLETED"))
          .execute();

As a side note, if you're going to use Java 8, I'd recommend using java.time.Duration instead of an integer to represent the poll duration and the interval.

I'd also recommend looking into https://github.com/rholder/guava-retrying which is a library that you could perhaps use. If not, it could be a good inspiration for your API as it features a nice fluent API.

EDIT: Following the update to the question, here is a simple implementation. I've left some parts for you to complete as TODOs.

import java.time.Duration;
import java.util.function.Predicate;
import java.util.function.Supplier;

public class MethodPoller<T> {

    Duration pollDurationSec;
    int pollIntervalMillis;

    private Supplier<T> pollMethod = null;
    private Predicate<T> pollResultPredicate = null;

    public MethodPoller() {
    }

    public MethodPoller<T> poll(Duration pollDurationSec, int pollIntervalMillis) {
        this.pollDurationSec = pollDurationSec;
        this.pollIntervalMillis = pollIntervalMillis;
        return this;
    }

    public MethodPoller<T> method(Supplier<T> supplier) {
        pollMethod = supplier;
        return this;
    }

    public MethodPoller<T> until(Predicate<T> predicate) {
        pollResultPredicate = predicate;
        return this;
    }

    public T execute()
    {
        // TODO: Validate that poll, method and until have been called.

        T result = null;
        boolean pollSucceeded = false;
        // TODO: Add check on poll duration
        // TODO: Use poll interval
        while (!pollSucceeded) {
            result = pollMethod.get();
            pollSucceeded = pollResultPredicate.test(result);
        }

        return result;
    }
}

Sample use:

import static org.junit.Assert.assertTrue;
import java.util.UUID;
import org.junit.Test;

public class MethodPollerTest
{

    @Test
    public void test()
    {
        MethodPoller<String> poller = new MethodPoller<>();
        String uuidThatStartsWithOneTwoThree = poller.method(() -> UUID.randomUUID().toString())
                                                     .until(s -> s.startsWith("123"))
                                                     .execute();
        assertTrue(uuidThatStartsWithOneTwoThree.startsWith("123"));
        System.out.println(uuidThatStartsWithOneTwoThree);
    }
}

Instead of writing this yourself, could you use Awaitility?

await()
    .atMost(3, SECONDS)
    .until(dog::bark, equalTo("woof"));

Here's a solution using Failsafe:

RetryPolicy retryPolicy = new RetryPolicy()
  .retryIf(bark -> bark.equals("Woof"))
  .withMaxDuration(pollDurationSec, TimeUnit.SECONDS);
  .withDelay(pollIntervalMillis, TimeUnit.MILLISECONDS);

Failsafe.with(retryPolicy).get(() -> dog.bark());

Pretty straightforward as you can see, and handles your exact scenario.

You can use RxJava

  Observable.interval(3, TimeUnit.SECONDS, Schedulers.io())
                .map(tick -> dog)
                .takeWhile( dog-> { return ! dog.bark().equals("Woof"); })
                .subscribe(dog ->dog.bark());


        try {
            Thread.sleep(10000);
        }catch(Exception e){}

http://blog.freeside.co/2015/01/29/simple-background-polling-with-rxjava/

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!