Skip to content

Make defer() wait until request > 0 before calling Func0 #3816

Closed
@JakeWharton

Description

@JakeWharton

Currently the defer operator calls its supplied Func0 immediately upon subscription as documented. Because this operator is usually used to delay work of some kind, this can prematurely trigger that work before the downstream consumer actually requests a non-zero amount.

A failing test, to illustrate:

AtomicBoolean b = new AtomicBoolean();
Observable<Boolean> bo = Observable.defer(() -> Observable.just(b.get()));

TestSubscriber s = new TestSubscriber(0);
bo.subscribe(s);
s.assertNoValues();

b.set(true);
s.requestMore(1);
s.assertValues(true);

In this test, the "work" (aka b.get()) ran before the downstream consumer actually wanted a value produced. If you think of b.get() as, say, an HTTP request or something based on time, etc. the problem becomes more clear.

I haven't looked, but I would guess that defer's behavior was implemented prior to the backpressure concept being introduced.

I'll leave it up to the library maintainers to determine the risk of changing the behavior, but I want to again note one thing which started this conversation (from comments in #3780): there currently doesn't exist an easy, sane, stable API for deferring work that is backpressure aware as described above. So if it's determined to be too risky to alter defer, fast-tracking fromCallable to stable and things like SyncOnSubscribe would be useful. This is of great concern to library developers, not so much application developers, where only stable APIs can safely be used.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions