rxjava将2个调用与错误处理结合在一起,以延迟方式失败
用例是, 数据有两个来源:rxjava将2个调用与错误处理结合在一起,以延迟方式失败,java,rx-java,rx-java3,Java,Rx Java,Rx Java3,用例是, 数据有两个来源: 服务1-从源1获取 服务2-从源2获取 应用程序应至少从source-1返回数据。如果source-2一切正常-数据将“增强”,比如乘以100 服务1调用服务2 如果所有成功的用户都从服务1和服务2获取数据 如果服务2上存在错误,则用户仅从服务1获取数据(至少) 如果服务1上有错误-用户将收到错误 有一个hello world bench代码,模拟此场景: import io.reactivex.rxjava3.core.Observable; import java
import io.reactivex.rxjava3.core.Observable;
import java.util.concurrent.TimeUnit;
class Response {
public Integer value;
public String warning;
public Response(Integer value) {
this.value = value;
}
@Override
public String toString() {
return "Response{" +
"value=" + value +
", warning='" + warning + '\'' +
'}';
}
}
class Service1 {
public Observable<Response> call(int arg) {
return Observable
.just(
new Response(1),
new Response(2),
new Response(3),
new Response(4))
.delay(100, TimeUnit.MILLISECONDS);
}
}
class Service2 {
public Observable<Response> call(int arg) {
if ( arg % 2 == 0) {
System.out.println("service 2: " + arg);
return Observable
.just(new Response(100 * arg)) // service 2 multiplies x 100 on the result it gets from the service 1
.delay(10, TimeUnit.MILLISECONDS);
} else {
System.out.println("service 2: " + arg);
return Observable.error(new RuntimeException("service 2 error"));
}
}
}
public class Step1 {
static Service1 service1 = new Service1();
static Service2 service2 = new Service2();
public static void main(String[] args) throws InterruptedException {
var oo1 = service1.call(1);
var oo3 = oo1.switchMapDelayError(x -> {
final Observable<Response> oo2 = service2.call(x.value);
return oo2
.onErrorReturn((ex) -> {
//System.out.println("Error handling..." + ex.getMessage() + " " + x);
x.warning = ex.getMessage();
return x; // returns at least service1 result
});
});
oo3.subscribe(x -> {
System.out.println(x);
});
Thread.sleep(100000);
}
}
问题是:没有预期值:value=200
2*100
但是,如果我在service2.call()//.delay(10,TimeUnit.millides)处注释延迟,则它将得到预期的结果:
service 2: 1
Response{value=1, warning='service 2 error'}
service 2: 2
Response{value=200, warning='null'}
service 2: 3
Response{value=3, warning='service 2 error'}
service 2: 4
Response{value=400, warning='null'}
问题是:为什么在service2.call()上使用.delay(10,TimeUnit.millises)时无法生成值=200?这个解决方案有什么问题,我错过了什么
谢谢。您的问题是switchMapDelayError
操作员。您应该使用concatMap或flatMap
我冒昧地为您的用例编写了一个测试。请注意,始终使用重载来提供计划程序
,以便为测试提供测试计划程序
switchMap做什么?
在每个上游发射开关上,映射订阅给定的内部流。当一个新值从上游发出时,旧的内部流将被取消订阅,并再次调用switchMap的lambda以订阅新的内部流
问题可能在于以下代码:
return Observable
.just(
new Response(1),
new Response(2),
new Response(3),
new Response(4))
.delay(100, TimeUnit.MILLISECONDS);
它几乎立即一个接一个地在堆栈上发出响应1到4,并且每个发出在另一个线程上延迟。因此,响应1到4几乎会立即发出。它们不会像100毫秒时的响应(1)和200毫秒时的响应(2)那样发出
让我们看看输出是为了什么
Observable.just(
new Response(1), //
new Response(2),
new Response(3),
new Response(4))
.delay(100, TimeUnit.MILLISECONDS)
.subscribe(r -> {
System.out.println("received value at " + Schedulers.io().now(TimeUnit.MILLISECONDS));
});
输出
received value at 1607432032768
received value at 1607432032769
received value at 1607432032769
received value at 1607432032769
因此,所有值几乎立即发出,并用switchMap相互覆盖。以前发出的值几乎立即被新值抵消
解决方案
使用concatMap或flatMap或更改测试设置以100ms的间隔发出每个值
flatMap只订阅每个值,默认情况下最大为128个内部流。当内部流完成时,ConcatMap将只订阅下一个值
试验
公共类So65193002{
@试验
作废so(){
TestScheduler TestScheduler=新的TestScheduler();
Service1 Service1=新Service1(testScheduler);
Service2 Service2=新的Service2(testScheduler);
可观察服务1呼叫=服务1呼叫(1);
可观测组合=
service1Call.concatmapperDelayError(
x->{
返回服务2
.调用(x.value)
A.报税表(
(ex)->{
x、 警告=例如getMessage();
return x;//至少返回service1结果
});
},
正确的);
TestObserver test=组合的.test();
testScheduler.advanceTimeBy(1,时间单位为小时);
测试.资产价值计数(4)
.资产价值(
0,
r->{
资产(r.价值)。isEqualTo(1);
断言(r.warning).isNotEmpty();
返回true;
})
.资产价值(
1.
r->{
资产(r.价值)。isEqualTo(200);
assertThat(r.warning).isNull();
返回true;
})
.资产价值(
3.
r->{
资产(r.价值)。isEqualTo(400);
assertThat(r.warning).isNull();
返回true;
});
}
}
领域
class Response {
public Integer value;
public String warning;
public Response(Integer value) {
this.value = value;
}
@Override
public String toString() {
return "Response{" + "value=" + value + ", warning='" + warning + '\'' + '}';
}
}
class Service1 {
private final Scheduler scheduler;
Service1(Scheduler scheduler) {
this.scheduler = scheduler;
}
public Observable<Response> call(int arg) {
return Observable.just(
new Response(1), //
new Response(2),
new Response(3),
new Response(4))
.delay(100, TimeUnit.MILLISECONDS, scheduler);
}
}
class Service2 {
private final Scheduler scheduler;
Service2(Scheduler scheduler) {
this.scheduler = scheduler;
}
public Observable<Response> call(int arg) {
if (arg % 2 == 0) {
return Observable.just(new Response(100 * arg)).delay(10, TimeUnit.MILLISECONDS, scheduler);
} else {
return Observable.error(new RuntimeException("service 2 error"));
}
}
}
类响应{
公共整数值;
公共字符串警告;
公共响应(整数值){
这个值=值;
}
@凌驾
公共字符串toString(){
返回“Response{“+”value=“+value+”,warning=''+warning+'\''+'}”;
}
}
类别服务1{
专用最终调度器;
服务1(调度程序){
this.scheduler=调度程序;
}
公共可观察呼叫(int arg){
返回可观察的(
新的答复(1)//
新的答复(2),
新的答复(3),
新的答复(4))
.延迟(100,TimeUnit.ms,调度程序);
}
}
类别服务2{
专用最终调度器;
服务2(调度程序){
this.scheduler=调度程序;
}
公共可观察呼叫(int arg){
如果(参数%2==0){
返回可观察的.just(新响应(100*arg)).delay(10,TimeUnit.ms,调度程序);
}否则{
返回可观察的.error(新的运行时异常(“服务2错误”);
}
}
}
注
不要使用可变对象。始终确保发出的值是不可变的,否则您会遇到麻烦。是的。我明白了,在现实生活中,如果两个项目来自同一个来源,那么它们不应该在同一时刻发出。但在我的情况下,我似乎不需要取消任何开关,即使它提供适当的发射时间工作。i、 我不需要开关~
public class So65193002 {
@Test
void so() {
TestScheduler testScheduler = new TestScheduler();
Service1 service1 = new Service1(testScheduler);
Service2 service2 = new Service2(testScheduler);
Observable<Response> service1Call = service1.call(1);
Observable<Response> combined =
service1Call.concatMapEagerDelayError(
x -> {
return service2
.call(x.value)
.onErrorReturn(
(ex) -> {
x.warning = ex.getMessage();
return x; // returns at least service1 result
});
},
true);
TestObserver<Response> test = combined.test();
testScheduler.advanceTimeBy(1, TimeUnit.HOURS);
test.assertValueCount(4)
.assertValueAt(
0,
r -> {
assertThat(r.value).isEqualTo(1);
assertThat(r.warning).isNotEmpty();
return true;
})
.assertValueAt(
1,
r -> {
assertThat(r.value).isEqualTo(200);
assertThat(r.warning).isNull();
return true;
})
.assertValueAt(
3,
r -> {
assertThat(r.value).isEqualTo(400);
assertThat(r.warning).isNull();
return true;
});
}
}
class Response {
public Integer value;
public String warning;
public Response(Integer value) {
this.value = value;
}
@Override
public String toString() {
return "Response{" + "value=" + value + ", warning='" + warning + '\'' + '}';
}
}
class Service1 {
private final Scheduler scheduler;
Service1(Scheduler scheduler) {
this.scheduler = scheduler;
}
public Observable<Response> call(int arg) {
return Observable.just(
new Response(1), //
new Response(2),
new Response(3),
new Response(4))
.delay(100, TimeUnit.MILLISECONDS, scheduler);
}
}
class Service2 {
private final Scheduler scheduler;
Service2(Scheduler scheduler) {
this.scheduler = scheduler;
}
public Observable<Response> call(int arg) {
if (arg % 2 == 0) {
return Observable.just(new Response(100 * arg)).delay(10, TimeUnit.MILLISECONDS, scheduler);
} else {
return Observable.error(new RuntimeException("service 2 error"));
}
}
}