RxJava:为什么重试当/重复什么时候不起作用?

时间:2017-03-07 19:10:09

标签: java rx-java

我一直坚持这一天。受到Dan Lew great post的启发,我尝试为repeatWhen()和retryWhen()创建一个简单的测试用例:

public class ObsTest {

   private static final Logger LOG = LoggerFactory.getLogger(ObsTest.class);

   @Test
   public void test1() throws InterruptedException {

  Observable<Integer> obs = rx.Observable.<Integer> create(observer -> {
     LOG.info("onSubscribe");
     Integer data = RandomUtils.nextInt(0, 1000);
     if (data % 2 != 0) {
        observer.onError(new RuntimeException("Odd number " + data));
     } else {
        observer.onNext(data);
     }
     observer.onCompleted();
  }, BackpressureMode.BUFFER);

  obs.repeatWhen(completed -> completed.delay(1, TimeUnit.MILLISECONDS))
        .retryWhen(error -> error.delay(1, TimeUnit.MILLISECONDS))
  .subscribe(i -> LOG.info("value={}", i), e -> LOG.info("Exception = {}", e.getMessage()));

}

我的想法是这应该永远运行,将偶数作为“正确”结果发出,将奇数作为“错误”发出。 相反,它运行一个或两个循环然后停止。也就是说,当延迟为1毫秒时,在较长的时间段内(即1秒),它会运行一次,只发出一个奇数或偶数。 我确定我做错了什么,但我找不到它是什么。

2 个答案:

答案 0 :(得分:2)

默认情况下,当您调用使用delay的{​​{1}}时,您会引入异步。一旦活动开始在后台线程中发生,您的测试就会完成,并且可能会退出您的过程。您需要使用Schedulers.computation()或在结尾放置一个较长的blockingSubscribe

答案 1 :(得分:0)

正如Dave Moten所述,delay默认使用Schedulers.computation(),但是您可以改为通过您选择的scheduler-为了进行测试,您可以使用TestScheduler和“控制时间”。下面的代码显示了如何使用它-如您所见,该订阅将在30天后不再终止,这基本上是永远的;)

public class ObsTest {

    @Test
    public void test1() {

        Observable<Integer> obs = rx.Observable.create(observer -> {
            Integer data = RandomUtils.nextInt(0, 1000);
            if (data % 2 != 0) {
                observer.onError(new RuntimeException("Odd number " + data));
            } else {
                observer.onNext(data);
            }
            observer.onCompleted();
        }, Emitter.BackpressureMode.BUFFER);

        TestScheduler scheduler = Schedulers.<Integer>test();

        AssertableSubscriber subscriber = obs.repeatWhen(completed -> completed.delay(1,    TimeUnit.MILLISECONDS, scheduler))
            .retryWhen(error -> error.delay(1, TimeUnit.MILLISECONDS, scheduler))
            .subscribeOn(scheduler)
            .test();

        subscriber.assertNoValues();

        scheduler.advanceTimeBy(30, TimeUnit.SECONDS);
        subscriber.assertNoTerminalEvent();

        scheduler.advanceTimeBy(30, TimeUnit.DAYS);
        subscriber.assertNoTerminalEvent();
    }
}