Valve for making sure only one request is active

时间:2019-03-17 22:49:20

标签: java rx-java2

I have a RxJava2 Flowable chain which includes some heavy computation. I want to make sure that the whole chain is only called one per request and that there is at most one active request at any given time.

Here's an example timeline:

-R-------R--R-R----R-------
--C....E--C....E----C....E-

In the above, - is idle time, R are input requests and C are computations that happen (starting with C, processing denoted by . and computation end denoted by E).

As you can see:

  • The first request fires the first computation
  • The second request fires the second computation
  • Requests 3 and 4 are ignored as they happen while the second computation is running
  • Request 5 triggers the third computation

This is what I got so far:

System.out.println("start");

CountDownLatch countDownLatch = new CountDownLatch(1);

AtomicBoolean valve = new AtomicBoolean(true);

Flowable.interval(100, TimeUnit.MILLISECONDS)
   .take(30)
   .filter(e -> valve.get())
   .observeOn(Schedulers.computation())
   .map(e -> {
      valve.set(false);

      System.out.println("map " + e);
      Thread.sleep(550);
      return e;
   })
   .observeOn(Schedulers.single())
   .subscribe(
      e -> {
         System.out.println("subscribe " + e);
         valve.set(true);
      },
      e -> {
         System.out.println("error " + e);
         valve.set(true);
      },
      () -> {
         System.out.println("complete");
         valve.set(true);
         countDownLatch.countDown();
      });

countDownLatch.await();

System.out.println("end");

So I have the flow that:

  • Emits 30 integers with 100ms interval between them
  • I observe that on the computation scheduler
  • I set the valve to false, so that no new requests are coming in
  • I map this with simulated computation time of 550ms
  • I observe the results on the single scheduler
  • I set the valve to true, so new requests can be processed

This seems to be working fine, but I was wondering whether there's a RxJava2-only solution that could be put instead of making use the outside of AtomicBoolean. I'm looking for that for two reasons:

  • I will probably need this in a few places, so I don't want to duplicate the same code if RxJava2 already supports something out of the box
  • I'm not sure if there are any consequences in terms of concurrency that would cause this not to work. E.g. I assume valve should be set to false just after the filter method, since observeOn would switch to another thread and map might run too late in case requests come in quickly one after another

Note CountDownLatch above is just for testing - I'm running this from my main method, and because there's an observeOn, the flow is executed on another thread, so main finishes before the flow executes. In real app, this won't be the case.

The real use case is an app which has a button which triggers some calculation that takes a few seconds. I don't want this to be triggered multiple times if the user clicks multiple times while the previous calculation is still in progress.

I'm fine with changing the flow if there are better solutions to this particular use case in RxJava.

0 个答案:

没有答案