Skip to content

Confusion when using Backpressure operators #3751

Closed
@troinine

Description

@troinine

Hey,

We have a use case in which a consumer might not be able to process items fast enough than what is emitted from a source observable. I understood that in this case, a backpressure with either onBackPressureBuffer() or onBackPressureDrop() might be useful. In case of overflow / drop, we would like to store items to a local storage and try processing them later when the consumer in this case is again able to handle the input rate. Our consumer is actually a remote REST call which might timeout or not be available in which case we retry.

Anyways, I tried alternative ways to address the problem but I can't find a suitable way to solve it. To illustrate my testings, here is some code:

package io.reactivex;

import org.junit.Test;
import rx.Observable;
import rx.Subscriber;
import rx.schedulers.Schedulers;

public class BackPressureTest {
    @Test
    public void testOnBackPressureDrop() throws InterruptedException {
        Observable<Integer> emitter = toObservable()
                .subscribeOn(Schedulers.newThread());

        emitter.onBackpressureDrop(i -> System.out.println("Dropped " + i))
                .observeOn(Schedulers.computation())
                .map(this::doWork)
                .doOnNext(i -> System.out.println("Output " + i))
                .toBlocking()
                .subscribe(new SingleItemSubscriber<>());
    }

    @Test
    public void testOnBackPressureBuffer() throws InterruptedException {
        Observable<Integer> emitter = toObservable()
                .subscribeOn(Schedulers.newThread());

        emitter.onBackpressureBuffer(2, () -> System.out.println("Overflow"))
                .observeOn(Schedulers.computation())
                .map(this::doWork)
                .doOnNext(i -> System.out.println("Output " + i))
                .toBlocking()
                .subscribe(i -> System.out.println("Subscriber received " + i));
    }

    private Observable<Integer> toObservable() {
        return Observable.create(subscriber -> {
            for (int i = 0; i < 10; i++) {
                System.out.println("Emitting " + i);

                subscriber.onNext(i);

                try {
                    Thread.sleep(250);
                } catch (InterruptedException e) {
                    subscriber.onError(e);
                }
            }

            subscriber.onCompleted();
        });
    }

    private int doWork(int integer) {
        System.out.println("Consuming " + integer);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return integer;
    }

    private static class SingleItemSubscriber<T> extends Subscriber<T> {
        @Override
        public void onStart() {
            request(1);
        }

        @Override
        public void onCompleted() {

        }

        @Override
        public void onError(Throwable e) {

        }

        @Override
        public void onNext(T t) {
            System.out.println("Subscriber received " + t);
            request(1);
        }
    }
}

In testOnBackPressureDrop() I would assume that after the emitter has queued some items, it would start dropping them. However, it seems that the backpressure operation subscription gets a receive size of 128 items. 128 items in memory in this case is far too much for us and we would like to control the size of the request items.

In testOnBackPressureBuffer() I would assume that the emitter would overflow after emitting more than two items into the buffer.

However, in neither of the cases, I don't experience an oveflow or dropped items. Also I realized that when using onBackPressureBuffer() it seems that in overflow, the observable emits onError(). To me that wouldn't be an option since I want the emitter to continue and I wan't to deal with the problem myself.

Could you please instruct me that what we are missing here or are we trying to do something that is not yet even possible, e.g. is the API missing an operator like onBackPressureBufferAndDrop(int capacity, Action1 onDrop)?

I wrote my tests based on the documentation in https://github.com/ReactiveX/RxJava/wiki/Backpressure

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions