RxJava重试当运算符未按预期工作时

时间:2016-10-06 07:39:11

标签: java rx-java

假设我有List<CharSequence> observableList,其中包含长度为1到10的随机CharSequence

我有Observable

Observable.from(observableList)
        .flatMap(new Func1<CharSequence, Observable<CharSequence>>() {
            @Override
            public Observable<CharSequence> call(CharSequence charSequence) {
                if (charSequence.length() == 1) {
                    return Observable.error(new RuntimeException("Too short"));
                } else {
                    return Observable.just(charSequence);
                }
            }
}).retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() {
    @Override
    public Observable<?> call(final Observable<? extends Throwable> observable) {
        return observable.flatMap(new Func1<Throwable, Observable<?>>() {
            @Override
            public Observable<?> call(Throwable throwable) {
                if (backoffStrategy.isApplicable(throwable)) {
                    Log.d(MainActivity.class.getSimpleName(), "Appropriate throwable is thrown!");
                    return backoffStrategy.call(observable);
                }
                return observable;
            }
        });
    }
})

当序列长度为1时,observable抛出异常。在retryWhen&#39; s Func1内我想检查错误类型(RuntimeException只是一个例子)并且选择适当的重试策略。

这是退避策略:

public class BaseBackoffStrategy implements BackoffStrategy {

    @Override
    public Observable<?> call(Observable<? extends Throwable> attempts) {
        return attempts.zipWith(Observable.range(1, 3 + 1), new ObservableUtils.RxPair<Throwable, Integer>())
                .flatMap(new Func1<Pair<Throwable, Integer>, Observable<?>>() {
                    @Override
                    public Observable<?> call(Pair<Throwable, Integer> ti) {
                        if (ti.second <= 3) {
                            System.out.println(new Date().toGMTString() + " : " + ti.second + " retry");
                            return Observable.timer((long) Math.pow(2, ti.second), TimeUnit.SECONDS);
                        } else {
                            return Observable.error(ti.first);
                        }
                    }
                });
    }

    @Override
    public boolean isApplicable(Throwable throwable) {
        return RuntimeException.class.isInstance(throwable);
    }
}

private interface BackoffStrategy extends Func1<Observable<? extends Throwable>, Observable<?>> {
    boolean isApplicable(Throwable throwable);

}

该函数只返回Pair个对象:

public class ObservableUtils {

    public static class RxPair<T1, T2> implements Func2<T1, T2, Pair<T1, T2>> {
        @Override
        public Pair<T1, T2> call(T1 t1, T2 t2) {
            return Pair.of(t1, t2);
        }
    }
}

来自控制台的输出是:

D/MainActivity: Appropriate throwable is thrown!
I/System.out: 6 Oct 2016 07:34:34 GMT : 1 retry
D/MainActivity: Appropriate throwable is thrown!
I/System.out: 6 Oct 2016 07:34:36 GMT : 1 retry
I/System.out: 6 Oct 2016 07:34:36 GMT : 2 retry
D/MainActivity: Appropriate throwable is thrown!
I/System.out: 6 Oct 2016 07:34:38 GMT : 1 retry
I/System.out: 6 Oct 2016 07:34:38 GMT : 3 retry
I/System.out: 6 Oct 2016 07:34:38 GMT : 2 retry
D/MainActivity: Appropriate throwable is thrown!
I/System.out: 6 Oct 2016 07:34:40 GMT : 1 retry
I/System.out: 6 Oct 2016 07:34:40 GMT : 3 retry
I/System.out: 6 Oct 2016 07:34:40 GMT : 2 retry
D/MainActivity: Appropriate throwable is thrown!
I/System.out: 6 Oct 2016 07:34:40 GMT : 1 retry
I/System.out: 6 Oct 2016 07:34:40 GMT : 3 retry
I/System.out: 6 Oct 2016 07:34:40 GMT : 2 retry
D/MainActivity: onError

但我希望Observable在指定时间后重试。抛出下一个异常时,时间应该变长。控制台的输出应如下所示:

D/MainActivity: Appropriate throwable is thrown!
I/System.out: 6 Oct 2016 07:34:34 GMT : 1 retry
D/MainActivity: Appropriate throwable is thrown!
I/System.out: 6 Oct 2016 07:34:36 GMT : 2 retry
D/MainActivity: Appropriate throwable is thrown!
I/System.out: 6 Oct 2016 07:34:38 GMT : 3 retry
D/MainActivity: Appropriate throwable is thrown!
D/MainActivity: onError
  

我的问题是:我在这里做错了什么?我可以从Func1致电其他Func1吗?

1 个答案:

答案 0 :(得分:2)

  1. 使用RxJava时,最好使用lamdas而不是内部类。您的代码变得更具可读性。

  2. 我认为你在这里犯了一个错误return backoffStrategy.call(observable);

  3. 每当retryWhen发出异常时,您都会重新创建zip +计时器。这就是为什么你有单,双,三等消息,如

    I/System.out: 6 Oct 2016 07:34:40 GMT : 1 retry

    1. 这是糟糕的设计

      private interface BackoffStrategy 
          extends Func1<Observable<? extends Throwable>, Observable<?>> {
      
    2. 为什么需要在只创建另一个序列的类中实现rx接口?

      我使用lambdas重写代码并将代码从BackoffStrategy.call移到序列

      BackoffStrategy backoffStrategy = new BaseBackoffStrategy();
      List<CharSequence> observableList = Arrays.asList("a");
      
      Observable.from(observableList)
              .flatMap(charSequence -> {
                  if (charSequence.length() == 1) {
                      return Observable.error(new RuntimeException("Too short"));
                  } else {
                      return Observable.just(charSequence);
                  }
              })
              .retryWhen(observable ->
                      observable
                              .filter(backoffStrategy::isApplicable)
                              .doOnNext(next -> System.out.println("Appropriate throwable is thrown!"))
                              .zipWith(Observable.range(1, 3 + 1), Tuple::new)
                              .flatMap(tuple -> {
                                  Integer attempts = tuple.getRight();
                                  if (attempts <= 3) {
                                      System.out.println(new Date().toGMTString() + " : " + attempts + " retry");
                                      return Observable.timer((long) Math.pow(2, attempts), TimeUnit.SECONDS);
                                  } else {
                                      return Observable.error(tuple.getLeft());
                                  }
                              })
              )
              .toBlocking()
              .subscribe(
                      next -> System.out.println("Next: " + next),
                      error -> System.out.println("Error: " + error),
                      () -> System.out.println("Completed")
              );
      

      输出

      Appropriate throwable is thrown!
      7 Oct 2016 12:24:24 GMT : 1 retry
      Appropriate throwable is thrown!
      7 Oct 2016 12:24:26 GMT : 2 retry
      Appropriate throwable is thrown!
      7 Oct 2016 12:24:30 GMT : 3 retry
      Appropriate throwable is thrown!
      Error: java.lang.RuntimeException: Too short
      

      Tuple

         private static class Tuple<T, V> {
              private final T left;
              private final V right;
      
              public Tuple(T left, V right) {
                  this.left = left;
                  this.right = right;
              }
      
              public T getLeft() {
                  return left;
              }
      
              public V getRight() {
                  return right;
              }
          }