Java retryWhen运算符从不重试

Java retryWhen运算符从不重试,java,rx-java,Java,Rx Java,我正在实施一种带有重试的DB更新方法。。遵循此处解释的retryWhen()运算符的常见模式: …但我的重试逻辑从未执行。我正在调试它,可以看到断点出现在下面显示的位置3,但它永远不会返回到位置2的重试逻辑。在第3位之后,它总是转到第4位,这是一个onComplete处理程序 (代码正在使用Java 8 lambdas) 我已经通过删除retryWhen()块应用了一种变通方法 现在从subscribe的>onError()块递归调用updateWithRetrials()。这是可行的,但我不喜

我正在实施一种带有重试的DB更新方法。。遵循此处解释的retryWhen()运算符的常见模式:

…但我的重试逻辑从未执行。我正在调试它,可以看到断点出现在下面显示的位置3,但它永远不会返回到位置2的重试逻辑。在第3位之后,它总是转到第4位,这是一个onComplete处理程序

代码正在使用Java 8 lambdas

我已经通过删除retryWhen()块应用了一种变通方法 现在从subscribe的>onError()块递归调用updateWithRetrials()。这是可行的,但我不喜欢这种方法

当我使用retryWhen()运算符时,有人能指出什么是错误的吗

private void updateWithRetrials(some input x)

{

   AtomicBoolean retryingUpdate = new AtomicBoolean(false);

   ...  

   // 1- Start from here
   Observable.<JsonDocument> just(x).map(x1 -> {

       if (retryingUpdate.get())
       {
          //2. retry logic
       }

       //doing sth with x1 here
       ...
       return <some observable>;

   })
   .retryWhen(attempts -> attempts.flatMap(n -> {

       Throwable cause = n.getThrowable();

       if (cause instanceof <errors of interest>)
       {
          // 3 - break-point hits here

          // retry update in 1 sec again
          retryingUpdate.set(true);
          return Observable.timer(1, TimeUnit.SECONDS);
       }

       // fail in all other cases...
       return Observable.error(n.getThrowable());
   }))
   .subscribe(
          doc -> {
                    //.. update was successful   
                 },

          onError -> {
                    //for unhandled errors in retryWhen() block
                  },

              {
                // 4. onComplete block

                 Sysout("Update() call completed.");
              }

     ); //subscribe ends here

}
private void updateWithRetrials(一些输入x)
{
AtomicBoolean retryingUpdate=新的AtomicBoolean(false);
...  
//1-从这里开始
可观测的.刚好(x).map(x1->{
if(retryingUpdate.get())
{
//2.重试逻辑
}
//在这里做某事
...
返回;
})
.retryWhen(尝试->尝试.flatMap(n->{
可丢弃的原因=n.getThrowable();
如果(原因实例)
{
//3-突破点点击这里
//请在1秒后重试更新
retryingUpdate.set(true);
返回可观察计时器(1,时间单位秒);
}
//在所有其他情况下失败。。。
返回Observable.error(n.getThrowable());
}))
.订阅(
文档->{
//…更新成功
},
onError->{
//用于retryWhen()块中未处理的错误
},
{
//4.未完成区块
Sysout(“Update()调用已完成”);
}
);//订阅到此结束
}

我认为错误发生在
map
中,因为它不能只发生在
中。这不是
retryWhen
的工作方式

使用
create
实现您的可观察性,并确保
map
中没有错误。如果在创建块中抛出任何错误,将调用
retryWhen
,并根据重试逻辑重试工作单元

    Observable.create(subscriber -> {
        // code that may throw exceptions
    }).map(item -> { 
        // code that will not throw any exceptions
    }).retryWhen(...)
      ...

您的问题是由于使用Observable.just()进行了一些性能优化

此操作员在显示项目后,不会检查订阅是否未取消,并在所有情况下发送onComplete

Observable.retryWhen(并重试)在出错时重新订阅,但在源发送onComplete时终止

因此,即使重试操作员重新订阅,它也会从以前的订阅中获得完成并停止

您可能会看到,下面的代码失败(与您的代码一样):

但如果您“别忘了”检查订阅,它会起作用

@Test
public void testCustomJust() throws Exception {
    AtomicBoolean throwException = new AtomicBoolean(true);
    int value = Observable.create((Subscriber<? super Integer> s) -> {
                s.onNext(1);
                if (!s.isUnsubscribed()) {
                    s.onCompleted();
                }
            }
    ).map(v -> {
        if (throwException.compareAndSet(true, false)) {
            throw new RuntimeException();
        }
        return v;
    }).retry(1).toBlocking().single();

    Assert.assertEquals(1, value);
}
@测试
public void testCustomJust()引发异常{
AtomicBoolean ThroweException=新的AtomicBoolean(真);

int value=Observable.create((SubscriberThis是retryWhen的一个bug。我已经发布了一个修复PR:接受这个答案。当使用“create”方法时,我能够看到重试。但是我观察到,如果我在“retryWhen”的结果中添加一个“subscriber”,则即使在“create”中采取的操作已成功完成,也不会对该订阅服务器调用onNext和onComlpete重试后。虽然我的问题与“retryWhen”有关,但这看起来是一个很好的方法。无论如何,感谢您这么好的解释。该问题同时影响函数-retry和retryWhen;我使用了retrysimplicity@MarekHawrylczak谢谢你的解释。没错!正如你所说,用just()做retryWhen()是没有办法的。
@Test
public void testCustomJust() throws Exception {
    AtomicBoolean throwException = new AtomicBoolean(true);
    int value = Observable.create((Subscriber<? super Integer> s) -> {
                s.onNext(1);
                if (!s.isUnsubscribed()) {
                    s.onCompleted();
                }
            }
    ).map(v -> {
        if (throwException.compareAndSet(true, false)) {
            throw new RuntimeException();
        }
        return v;
    }).retry(1).toBlocking().single();

    Assert.assertEquals(1, value);
}