如何检查所有需要的订阅者是否完成了他们的工作?

时间:2016-09-13 12:43:50

标签: java spring rx-java reactive-programming

使用rx实体时,我有以下方案:

    Observerable1
        |
------------------
|       |         |   
S1(*)  S2(*)     S3 (onCompleted() starts another observable)
                  |
              Observable2
                  |
                 S4(*)

我需要知道*的所有订阅者何时完成工作(S1,S2,S4)。由于它们可以在不同的线程中执行,我需要一些同步机制,或者rx-java有一些开箱即用的解决方案?

用于说明当前设计的一些示例代码:

@Component
public class BatchReader {
    @Autowired List<Subscriber<List<Integer>>> subscribers;

    public void start() {
        ConnectableObservable<List<Integer>> observable1 = createObservable();
        subscribers.forEach(observable1::subscribe);
        observable1.connect();
    }

    private ConnectableObservable<List<Integer>> createObservable() {
        return Observable.create((Subscriber<? super List<Integer>> subscriber) -> {
            try {    
                subscriber.onStart();

                while (someCondition) {
                    List<Integer> numbers = ...;
                    subscriber.onNext(numbers);
                }

                subscriber.onCompleted();
            } catch (Exception ex) {
                subscriber.onError(ex);
            }
        }).observeOn(Schedulers.newThread()).publish();
    }
}

在S3中,我有以下逻辑:

@Component
public class S3 extends Subscriber<List<Integer>> {
    @Autowired AnotherBatchReader anotherBatchReader;
    ....
    @Override
    public void onCompleted() {
        anotherBatchReader.start();
    }
    ...
}

S4订阅了AnotherBatchReader:

@Component
public class AnotherBatchReader {
    @Autowired S4<List<Foo>> subscriber4;

    public void start() {
        Observable<List<Foo>> observable2 = createObservable();
        observable2.subscribe(subscriber4);
    }

    private Observable<List<Foo>> createObservable() {
        return Observable.create(subscriber -> {
            try {
                    subscriber.onStart();
                    while (someConditionBar) {
                        List<Foo> foo = ...;
                        subscriber.onNext(foo);
                    }
                    subscriber.onCompleted();
                }
            } catch (RuntimeException ex) {
                subscriber.onError(ex);
            }
        });
    }
}

当我感兴趣的所有订阅者都有兴趣完成他们的工作时,有没有办法得到适当的通知? rx支持它吗?或者也许有更好的设计可以支持它?

修改 我有单独的订阅者,因为每个订阅者都有不同的行为。最后,*(S1,S2,S3)的订阅者将其数据写入xml文件。但是

  • S1接收onNext()中的数据,做一些工作,并将结果直接写入文件
  • S2接收onNext()中的数据,做一些工作,在字段中累积结果,然后用onCompleted
  • 写入
  • S3接收onNext中的数据,做一些工作,将结果写入DB并在调用onCompleted后启动另一个observable,它开始从db获取数据并将其推送到S4
  • S4接收onNext()中的数据,做一些工作并写入文件

我需要在S3中将数据写入数据库的原因是因为onNext()中接收到的数据生成的结果必须是唯一的,但是我正在从{{{{}}批量获取数据1}}我无法保证这种独特性,所以DB会照顾它。

当然在Observable1中,我不能像在S3中那样做(将所有结果累积在内存中),因为S3中存在的结果的乘法与S2。

1 个答案:

答案 0 :(得分:1)

感谢您的澄清。在我看来,明智地应用现有的运营商将最大限度地减少您的代码。现在,我没有所有细节,但你所做的事情感觉很像这样:

Observable<T> observable1 = ...
        .share();

Observable<?> S1 = S1(observable1);
Observable<?> S2 = S2(observable1);
Observable<?> S3 = S3(observable1);
Observable<?> S4 = defer(() -> readFromDatabase()).compose(S4::generate);

Observable.merge(S1,S2,S3.ignoreElements().switchIfEmpty(S4))
    .ignoreElements()
    .onComplete(...)
    .subscribe();

当然,细节会有所不同,具体取决于原始观察结果是热还是冷,以及S[1-4]的详细信息。

另外,不要试图自己开车Subscribers,让框架为你做这件事,你会从中获得更多 - f.e。:

S4 = Observable.create(SyncOnSubscribe.generateStateless(
       observer -> observer.onNext(<get List<Foo>>)
   ))
   .takeWhile(list -> someConditionBar);

编辑:这是XY问题的一个案例 - 我们都经历过......