在RxJava中,如何在Observable之外反映/提取失败?

时间:2015-03-23 14:24:45

标签: java reactive-programming rx-java

我们有一个StoreService调用更新(密钥,内容)方法,该方法使用couchbase客户端进行get - > change_content - > replace。

作为该过程的一部分,我们使用Observable retryWhen来处理异常。如果重试超过最大重试次数,它只会传递异常,然后触发观察者的onError方法。

如果无法处理错误,我们想要做的是将更新(密钥,内容)方法中的异常抛出到调用它的StoreService,但我们没有这样做。

到目前为止,我们尝试了以下方法但没有成功:

  1. 从onError方法抛出异常,但它不会被抛出Observable。
  2. 抛出一个RuntimeException,但它也没有用。
  3. 使用其中包含boolean isFailed成员的DTO:我们在Observable之外创建DTO,如果出现错误,我们会转到订阅者的onError,我们将DTO的isFailed设置为true。在Observable完成之后,我们检查DTO是否失败,如果是,我们抛出异常。那也没办法 - onError中发生的变化没有传播到Observable之外(为什么?)
  4. 这是伪代码:

     public void update(String key, ConversationDto updateConversationDto) {
    
        ObservableExecution observableExecution = new ObservableExecution();
    
        Observable
                .defer(... get the document from couchbase ...) 
                .map(... handle JSON conversion and update the document ...)
                .flatMap(documentUpdate -> {
                    return couchbaseClient.getAsyncBucket().replace(documentUpdate);
                })
                .retryWhen(new RetryWithDelay(3, 200))
                .subscribe(
                        n -> logger.debug("on next update document -> " + n.content()),
                        e -> {
                            //logger.error("failed to insert a document",e);
                            observableExecution.setFailure(e);
                        },
                        () -> logger.debug("on complete update document")
    
                );
        // this is never true
        if (observableExecution.isFailed()) {
            final Throwable e = observableExecution.getFailure();
            throw new DalRuntimeException(e.getMessage(), e);
        }
    }
    

    这是重试时代码:

    public Observable<?> call(Observable<? extends Throwable> attempts) {
        return attempts
                .flatMap(new Func1<Throwable, Observable<?>>() {
                    @Override
                    public Observable<?> call(Throwable errorNotification) {
                        if (++retryCount < maxRetries) {
                            // When this Observable calls onNext, the original
                            // Observable will be retried (i.e. re-subscribed).
                            logger.debug(errorNotification + " retry no. " + retryCount);
                            return Observable.timer(retryDelayMillis,
                                    TimeUnit.MILLISECONDS);
                        }
    
                        // Max retries hit. Just pass the error along.
                        logger.debug(errorNotification + " exceeded max retries " + maxRetries);
                        return Observable.error(errorNotification);
                    }
                });
    }
    

    非常感谢你的帮助!

2 个答案:

答案 0 :(得分:1)

订阅运行异步,因此isFailed()检查将始终在e -> setFailure(e)代码运行之前立即运行。

执行此操作的正确方法是从Observable方法返回update()并在StoreService中订阅该方法。这样,您就会有兴趣处理它们的成功和失败的通知。

答案 1 :(得分:0)

我同意@Ross:概念性Observable应该由update()返回。 我可以提出的唯一简化是使用本地可变变量而不是ObservableExecution DTO:

public void update(String key, ConversationDto updateConversationDto) {
    final Throwable[] errorHolder = new Throwable[1];

    Observable
        .defer(... get the document from couchbase ...) 
        .map(... handle JSON conversion and update the document ...)
        .flatMap(documentUpdate -> {
            return couchbaseClient.getAsyncBucket().replace(documentUpdate);
        })
        .retryWhen(new RetryWithDelay(3, 200))
        .subscribe(
                n -> logger.debug("on next update document -> " + n.content()),
                e -> {
                    //logger.error("failed to insert a document",e);
                    errorHolder[0] = e;
                },
                () -> logger.debug("on complete update document")

        );

    if (errorHolder[0] != null) {
        final Throwable e = errorHolder[0];
        throw new DalRuntimeException(e.getMessage(), e);
    }
}