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:
- Created 5 years ago
- Comments:12 (5 by maintainers)
PublishSubject
s are not thread safe and you callonXXX
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 ofdoOnNext()
s at various places to see where events disappear.Yeah I was aware of that and ensure I use the io scheduler for any potentially blocking operations but I will review my code