我正在努力理解在RxJava中为PublishSubject实现强大解决方案所需的正确行为。我已经在各种地方读过onError ...是正确的解决方案,但我没有在哪里放置代码来处理它。请参阅简化示例作为JUnit测试的一部分。突出显示问题的测试是 shouldHandleExceptionsForMultipleSubsSuccessfulOnesContinuing 和 shouldHandleErrorSuccessfulCallForRetryVersionWithSuccessfulOnesContinuing ,这表明在遇到异常后公交的所有处理都会停止。
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.client.RestClientException;
import rx.Observable;
import rx.Subscriber;
import rx.subjects.PublishSubject;
import rx.subjects.SerializedSubject;
import rx.subjects.Subject;
@RunWith(MockitoJUnitRunner.class)
public class TestSubPubRobustness {
private static final Integer INTEGER_VALUE_OF_14 = Integer.valueOf(14);
private static final Integer INTEGER_VALUE_OF_12 = Integer.valueOf(12);
@Mock
private ValidatoryInterface mockInterface;
private static final Logger logger = LoggerFactory.getLogger(TestSubPubRobustness.class);
PublishSubject<Integer> subject;
Subject<Integer, Integer> inboundMessageBus;
@Before
public void setUp() throws Exception {
subject = PublishSubject.create();
inboundMessageBus = new SerializedSubject<>(subject);
}
@Test
public void shouldHandleSimplySuccessfulCall() {
final TestEventHandler eventHandler = new TestEventHandler(mockInterface);
inboundMessageBus.subscribe(eventHandler);
inboundMessageBus.onNext(INTEGER_VALUE_OF_12);
verify(mockInterface).haveBeenCalled(INTEGER_VALUE_OF_12);
verifyNoMoreInteractions(mockInterface);
}
@Test
public void shouldHandleMultipleSuccessfulCall() {
final TestEventHandler eventHandler = new TestEventHandler(mockInterface);
inboundMessageBus.subscribe(eventHandler);
inboundMessageBus.onNext(INTEGER_VALUE_OF_12);
inboundMessageBus.onNext(INTEGER_VALUE_OF_14);
verify(mockInterface).haveBeenCalled(INTEGER_VALUE_OF_12);
verify(mockInterface).haveBeenCalled(INTEGER_VALUE_OF_14);
verifyNoMoreInteractions(mockInterface);
}
@Test
public void shouldHandleSimplySuccessfulCallForRetryVersion() {
final TestEventHandler eventHandler = new TestEventHandler(mockInterface);
inboundMessageBus.retry().subscribe(eventHandler);
inboundMessageBus.onNext(INTEGER_VALUE_OF_12);
verify(mockInterface).haveBeenCalled(INTEGER_VALUE_OF_12);
verifyNoMoreInteractions(mockInterface);
}
@Test
public void shouldHandleErrorSuccessfulCallForRetryVersion() {
final TestEventHandler eventHandler = new TestEventHandler(mockInterface);
inboundMessageBus.retry().subscribe(eventHandler);
doThrow(new RuntimeException()).when(mockInterface).haveBeenCalled(INTEGER_VALUE_OF_12);
inboundMessageBus.onNext(INTEGER_VALUE_OF_12);
verify(mockInterface).haveBeenCalled(INTEGER_VALUE_OF_12);
verifyNoMoreInteractions(mockInterface);
}
@Test
public void shouldHandleErrorSuccessfulCallForRetryVersionWithSuccessfulOnesContinuing() {
final TestEventHandler eventHandler = new TestEventHandler(mockInterface);
inboundMessageBus.onExceptionResumeNext(Observable.empty())
.subscribe(eventHandler);
doThrow(new RestClientException("error")).when(mockInterface)
.haveBeenCalled(INTEGER_VALUE_OF_12);
inboundMessageBus.onNext(INTEGER_VALUE_OF_12);
inboundMessageBus.onNext(INTEGER_VALUE_OF_14);
verify(mockInterface).haveBeenCalled(INTEGER_VALUE_OF_12);
verify(mockInterface).haveBeenCalled(INTEGER_VALUE_OF_14);
verifyNoMoreInteractions(mockInterface);
}
@Test
public void shouldHandleMultipleSubsSuccessfulOnesContinuing() {
final TestEventHandler eventHandler = new TestEventHandler(mockInterface);
final TestEventHandler additionalEventHandler = new TestEventHandler(mockInterface);
inboundMessageBus.retry().subscribe(eventHandler);
inboundMessageBus.retry().subscribe(additionalEventHandler);
inboundMessageBus.onNext(INTEGER_VALUE_OF_12);
inboundMessageBus.onNext(INTEGER_VALUE_OF_14);
verify(mockInterface, times(2)).haveBeenCalled(INTEGER_VALUE_OF_12);
verify(mockInterface, times(2)).haveBeenCalled(INTEGER_VALUE_OF_14);
verifyNoMoreInteractions(mockInterface);
}
@Test
public void shouldHandleExceptionsForMultipleSubsSuccessfulOnesContinuing() {
final TestEventHandler eventHandler = new TestEventHandler(mockInterface);
final TestEventHandler additionalEventHandler = new TestEventHandler(mockInterface);
inboundMessageBus.asObservable()
.onErrorReturn(error -> Integer.MAX_VALUE)
.retry()
.subscribe(eventHandler);
inboundMessageBus.asObservable()
.onErrorReturn(error -> Integer.MAX_VALUE)
.retry()
.subscribe(additionalEventHandler);
doThrow(new RuntimeException()).when(mockInterface).haveBeenCalled(INTEGER_VALUE_OF_12);
inboundMessageBus.onNext(INTEGER_VALUE_OF_12);
inboundMessageBus.onNext(INTEGER_VALUE_OF_14);
verify(mockInterface, times(2)).haveBeenCalled(INTEGER_VALUE_OF_12);
verify(mockInterface, times(2)).haveBeenCalled(INTEGER_VALUE_OF_14);
verifyNoMoreInteractions(mockInterface);
}
private final class TestEventHandler extends Subscriber<Integer> {
private final ValidatoryInterface validatoryInterface;
public TestEventHandler(final ValidatoryInterface validatoryInterface) {
this.validatoryInterface = validatoryInterface;
}
@Override
public void onCompleted() {
logger.debug("Completed");
}
@Override
public void onError(final Throwable e) {
logger.error("Argggggggg", e);
}
@Override
public void onNext(final Integer t) {
logger.debug("Next", t);
validatoryInterface.haveBeenCalled(t);
}
}
private interface ValidatoryInterface {
void haveBeenCalled(Integer testNumber);
}
}
答案 0 :(得分:1)
AFAIK您无法在错误状态下恢复一次Observable。曾经有一个运算符:onErrorFlatMap
。但它在issue 1465中被弃用了。你可以在那里阅读更全面的解释,但基本上逻辑是,一旦Observable处于错误状态,它应该永远不会再发出任何东西。消耗了它。这与只发送一次且仅一次的onError的合同有关。你可以&#34;重启&#34;通过重新连接到源,但&#34;恢复&#34;是被禁止的。
因此,Observable不会像消息总线那样:它会在发出错误后停止传递消息。错误处理操作员永远不会恢复流,而是在错误发生后重新启动它或切换到其他流。
在您的示例中,您说onErrorReturn(e -> MAX_VALUE)
,一旦源流中发生错误,它将使用仅包含MAX_VALUE的流替换流,如果遇到错误,则有效地以MAX_VALUE结束。然后你说retry()
,这意味着如果发生错误,应重新启动流。 AFAIK这两者相互矛盾。
就建议而言,我只建议将您的流视为易失性。在票证中提到了一些像materialize
这样的解决方法,但我通常处理它的方法是创建新的流。例如,在http服务器中,我为每个请求创建一个流,而不是一个处理所有请求的流。这种方式将异常与单个请求隔离开来。
我很高兴听到benjchristensen有问题,因为该问题已经写好了。