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.

PublishSubject/Processor are not delivering onNext calls

See original GitHub issue
  • Using library version 2.1.6

HI devs,

I am seeing a weird issue with PublishSubjects and PublishProcessors where elements are not being delivered to their observers. Ill try to explain my structure below. The abstractions are mainly because of the need to transform lower level objects to higher level abstractions. Its difficult to produce a test case as I think its concurrency related

I have a Java NIO loop that is listening on a socket This uses a Completable to do the looping and then uses a PublishSubject to deliver its messages downstream.

class MessageQueueLoop {

    private PublishSubject msgs = PublishSubject.create();

        void loop() {
            //When message arrives
            msgs.onNext(new Msg());
        }
    }
}

There are two downstream listeners on this stream of messages within a single class

class ServerEventLoop {
        messageRouter = new MessageQueueLoop();
        serverEventStream = PublishSubject.create()

        disposables.add(messageRouter.messageRouterEventStream()
                .observeOn(computationScheduler)
                .subscribe(
                        this::handleMessageQueueEvent,
                        error -> {
                            shutdownLoop();
                            serverEventStream.onError(error);
                        },
                        () -> {
                            shutdownLoop();
                            serverEventStream.onComplete();
                        }
                ));


        disposables.add(messageRouter.messageRouterEventStream()
                .observeOn(ioScheduler)
                .filter(messageQueueEvent -> messageQueueEvent.type().equals(MessageQueueEvent.Type.READY))
                .doOnSubscribe(disposable -> messageRouter.startMessageQueueLoop())
                .subscribe(
                        this::startListeningForClients, //Initialise server socket and accepts clients
                        this::handleMessageQueueError)); 

     void handleMessageQueueEvent(MessageQueueEvent messageQueueEvent){
        switch (messageQueueEvent.type()) {
            case CLIENT_REGISTERED:
                serverEventStream.onNext(ServerEvent.newClient());
                break;
            case CLIENT_REGISTRATION_FAILED:
                break;
            case CLIENT_UNREGISTERED:
                serverEventStream.onNext(ServerEvent.clientDisconnected());
                break;
            case MESSAGE:
                serverEventStream.onNext(ServerEvent.newMessage()));
                break;
            case READY:
                break;
            default:
               //Error, throw exception
        }

    }

Now the weirdness happens when the listener on the server event loop receives two messages from separate clients in very close succession. There is the following class which listens to the ServerEventLoop PublishSubject as per below

serverEventLoop = new ServerEventLoop(bindAddress, Schedulers.computation(), messageProvider);
// Serialise the subject here
serverEventsStream = PublishSubject.create().toSerialized();
        
serverEventLoop.getServerEventsStream()
                .observeOn(computation)
                .filter(serverEvent -> !serverEvent.isNewMessage())
                .subscribe(//Do stuff)


serverEventLoop.getServerEventsStream()
                .observeOn(computation)
                .filter(serverEvent -> {
                    boolean shouldDeliver = serverEvent.isNewMessage() && clients.containsKey(serverEvent.connectionId());
                    return shouldDeliver;
                })
                .subscribe(
                        event -> {
                            serverEventsStream.onNext(ServerEvent.newMessage(event.message(), event.connection()));
                        }
                );

The problem starts at the last line which filters for new messages and checks that clients still exists serverEventsStream.onNext(ServerEvent.newMessage());

This line gets called, but the messages do not get delivered even though there are observers. The observer for these messages do some filtering/mapping then passes it onto the main scheduler in Android for processing and rendering on views. If multiple clients send messages around the same time I can detect that

serverEventsStream.onNext(ServerEvent.newMessage());

is called but the messages are not delivered downstream. I have also verified that the observers exists and are listening and that the subjects are all valid (no errors or complete signal have been delivered). I wanted to see if this is a bug or if I am doing something wrong before I go about refactoring things a little.

Issue Analytics

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

github_iconTop GitHub Comments

1reaction
akarnokdcommented, Apr 12, 2018

PublishSubjects are not thread safe and you call onXXX methods on them on various threads. There could be a possibility of dataloss. Second, your filter definitions could be wrong and filtering out events. Third, place a couple of doOnNext()s at various places to see where events disappear.

0reactions
muzzahcommented, Apr 13, 2018

Yeah I was aware of that and ensure I use the io scheduler for any potentially blocking operations but I will review my code

Read more comments on GitHub >

github_iconTop Results From Across the Web

How interact between PublishSubject and PublishProcessor ...
How interact between PublishSubject and PublishProcessor to simulate deliveries? I have this problem: I have a list of Orders
Read more >
PublishSubject (RxJava Javadoc 3.0.1) - ReactiveX
Calling onNext(Object) , onError(Throwable) and onComplete() is required to be serialized (called from the same thread or called non-overlappingly from ...
Read more >
Forget RxJava: Kotlin Coroutines are all you need. Part 2/2
The series about RxJava — Coroutines replacement continues. Now we're considering more complex case than having a bunch network calls.
Read more >
Reactive log stream processing with RxJava - Part I
Until we subscribe to the Observable there is no output, there is nothing happening - the data is not flowing-. When someone subscribes,...
Read more >
Reactive Programming with Kotlin, Chapter 3: Subjects
If a tree falls and no one's there to hear it, does that make your illegal logging business a ... Call onNext sending...
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