3

We have Micro services architecture, where we make inter-service calls over a network. We are using RxJava in top level service, which is resulting in creation of large no of parallel requests to bottom service. Because of this i am getting "No Route to Host error" or "connection error". For that purpose i want to slow down emission from RxJava Observable, so that earlier connection will get closed before creating new one. Below is the sample code:

    package com.demo.rxjava.rxjaxa.creation;
    import rx.Observable;
    import rx.Subscriber;
    import rx.schedulers.Schedulers;

    public class Delay {

        public static void main(String[] args) throws InterruptedException {
            Observable.just(1, 2, 3, 4, 5).subscribeOn(Schedulers.io())
                    .flatMap(integer -> {
                        return function1(integer);
                    }).observeOn(Schedulers.io())
                    .subscribe(new Subscriber<String>() {
                        @Override
                        public void onNext(String item) {
                            System.out.println("Next: " + item);
                        }

                        @Override
                        public void onError(Throwable error) {
                            System.err.println("Error: " + error.getMessage());
                        }

                        @Override
                        public void onCompleted() {
                            System.out.println("Sequence complete.");
                        }
                    });
        }

     public Observable<String> function1(String id) {
                // This is where we make network call
                Observable<Response> response = Rx.newClient(RxObservableInvoker.class)
                        .target("http://example.com/resource")
                        .request()
                        .queryParam("id", id)
                        .rx()
                        .get();
                response.obserOn(Schedulers.from(threadExecutor)).flatMap(response->{
                    return response.extractResponse();
                });
   }
}

2 Answers2

0

In order to delay a particular step you can use zip and combine that every item emitted in your first Observable.from go with an interval of X time.

   /**
 * If we want to delay the every single item emitted in the pipeline we will need a hack,
 * one possible hack is use zip operator and combine every item emitted with an interval so every item emitted has to wait until interval emit the item.
 */
@Test
public void delay() {
    long start = System.currentTimeMillis();
    Subscription subscription = Observable.zip(Observable.from(Arrays.asList(1, 2, 3)), Observable.interval(200, TimeUnit.MILLISECONDS), (i, t) -> i)
                                          .subscribe(n -> System.out.println("time:" + (System.currentTimeMillis() - start)));
    new TestSubscriber((Observer) subscription).awaitTerminalEvent(3000, TimeUnit.MILLISECONDS);
}

This will print

   time:537
   time:738
   time:936

More practicle examples here https://github.com/politrons/reactive

paul
  • 12,873
  • 23
  • 91
  • 153
0

Rather than delaying your requests you should have the requests to the bottom service occur on a Scheduler that limits parallel activity. For example:

 int maxParallel = 4;
 Scheduler scheduler = Schedulers.from(
     Executors.newFixedThreadPool(maxParallel));
 ...
 observable
   .flatMap(x -> 
       submitToBottomService(x)
         .subscribeOn(scheduler))
   .subscribe(subscriber);

By the way you mention closing a connection. The Observable.using operator is designed for closing resources in a reactive context (it closes resources on termination and unsubscription). If you are not using it yet then give it a look.

Dave Moten
  • 11,957
  • 2
  • 40
  • 47