question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

published GroupedObservable emitted from groupBy() only emits a single item

See original GitHub issue
PublishSubject<Triplet<Integer, Observable<String>, Observable<Integer>>> subject =
    PublishSubject.create();
Observable<Triplet<Integer, Observable<String>, Observable<Integer>>> grouped =
    subject.groupBy(Triplet::getValue0).flatMap(
        tripletsById -> tripletsById.publish(pub -> Observable.just(Triplet.create(
            tripletsById.getKey(),
            pub.flatMap(Triplet::getValue1),
            pub.flatMap(Triplet::getValue2)))));
grouped.subscribe(triplet -> System.out.println("New triplet: " + triplet.getValue0()));
subject.onNext(Triplet.create(1, Observable.just("A"), Observable.just(1)));
subject.onNext(Triplet.create(1, Observable.just("B"), Observable.just(3)));
subject.onNext(Triplet.create(2, Observable.just("A"), Observable.just(2)));

This code outputs:

New triplet: 1
New triplet: 1
New triplet: 2

If I change the definition of grouped so that tripletsById is not published, I get the expected behavior:

Observable<Triplet<Integer, Observable<String>, Observable<Integer>>> grouped =
    subject.groupBy(Triplet::getValue0).map(tripletsById -> Triplet.create(
        tripletsById.getKey(),
        tripletsById.flatMap(Triplet::getValue1),
        tripletsById.flatMap(Triplet::getValue2)))));

Output:

New triplet: 1
New triplet: 2

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Comments:6 (5 by maintainers)

github_iconTop GitHub Comments

6reactions
benjchristensencommented, Jun 23, 2015

Here is full code reproducing the issue:

import rx.Observable;
import rx.subjects.PublishSubject;

public class GroupByPublish {

    public static void main(String... args) {
        PublishSubject<Triplet<Integer, Observable<String>, Observable<Integer>>> subject =
                PublishSubject.create();

        Observable<Triplet<Integer, Observable<String>, Observable<Integer>>> grouped =
                subject.groupBy(Triplet::getValue0)
                        .flatMap(tripletsById -> {
                            System.out.println("Received new group: " + tripletsById.getKey());
                            return tripletsById
                                    .doOnCompleted(() -> System.out.println("*** completed publish"))
                                    .doOnUnsubscribe(() -> System.out.println("*** unsubscribing publish"))
                                    .publish(pub ->
                                    Observable.just(Triplet.<Integer, Observable<String>, Observable<Integer>> create(
                                            tripletsById.getKey(),
                                            pub.flatMap(Triplet::getValue1),
                                            pub.flatMap(Triplet::getValue2))
                                            ));
                        });

        grouped.subscribe(triplet -> System.out.println("New triplet: " + triplet.getValue0()));
        subject.onNext(Triplet.create(1, Observable.just("A"), Observable.just(1)));
        subject.onNext(Triplet.create(1, Observable.just("B"), Observable.just(3)));
        subject.onNext(Triplet.create(2, Observable.just("A"), Observable.just(2)));
    }

    public static class Triplet<S1, S2, S3> {

        S1 v0;
        S2 v1;
        S3 v2;

        Triplet(S1 v0, S2 v1, S3 v2) {
            this.v0 = v0;
            this.v1 = v1;
            this.v2 = v2;
        }

        public static <S1, S2, S3> Triplet<S1, S2, S3> create(S1 v0, S2 v1, S3 v2) {
            return new Triplet<S1, S2, S3>(v0, v1, v2);
        }

        public S1 getValue0() {
            return v0;
        }

        public S2 getValue1() {
            return v1;
        }

        public S3 getValue2() {
            return v2;
        }
    }
}

Output:

Received new group: 1
New triplet: 1
*** unsubscribing publish
Received new group: 1
New triplet: 1
*** unsubscribing publish
Received new group: 2
New triplet: 2
*** unsubscribing publish

It’s somewhat odd that we get the unsubscribe.

1reaction
benjchristensencommented, Jun 23, 2015

A GroupedObservable is a difficult and special beast coming out of groupBy in order to deal with “time gap” issues. (You can start in this issue to follow the many threads on that issue if you care: https://github.com/ReactiveX/RxJava/issues/844)

It is “hot”, yet must support back pressure, and must also support async consumers without losing data, despite being hot (because each group receives data from upstream, it does not control the source). For these reasons it must always be subscribed to by a single subscriber, and can buffer data. Thus it can only be subscribed to once, due to it’s hot nature within the lifecycle of the outer groupBy. You can however publish it to multicast it.

More on the specific issue with use of publish coming …

Read more comments on GitHub >

github_iconTop Results From Across the Web

groupBy operator, items from different groups interleaved
It seems that although I get the grouped observables one by one, their emissions are somehow interleaved. How does this happen? rx-java.
Read more >
Here is what I've learn about groupBy operator by reading ...
The groupBy operator emits Subject instances for each key, and then uses that Subject instance to immediately emit the individual values as well....
Read more >
GroupedObservable (RxJava Javadoc 1.3.8) - ReactiveX
An Observable that has been grouped by key, the value of which can be obtained with getKey() . Note: A GroupedObservable will cache...
Read more >
GroupedObservable - [ - K, +V - ] - extends Observable - Monix
Periodically gather items emitted by an observable into bundles and emit these bundles rather than emitting the items one at a time.
Read more >
Observable (RxJava Javadoc 1.3.7)
Given two Observables, mirrors the one that first either emits an item or sends ... Returns an Observable that emits only the very...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found