You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I’m observing behavior that seems strange to me when I use an Observable constructed in the following way.
I’m using Observable.using to create an observable based on some resource. In Observable.using, I pass a function as sourceSupplier, which returns an observable created using Observable.create.
Then I apply the takeUntil operator to the observable created by Observable.using to combine it with another observable — stopSubject, which in this example is a BehaviorSubject.
I expect that when the callback passed to Observable.create is invoked, the resource created by Observable.using has not yet been disposed, and the emitter passed to the callback is not yet disposed either. I verify this in the tests of the attached TakeUntilTest class.
These expectations hold true if I emit a value into stopSubject after subscribing to the observable under test (see the test otherObservableEmitsValueAfterSubscription).
However, if I emit a value into stopSubject before subscribing to the observable under test, the following happens:
The callback passed to Observable.create is invoked, but by that time the resource has already been disposed, and the emitter passed to the callback is already in the disposed state. This is verified in the test otherObservableHasValueInAdvance.
I looked into the RxJava implementation, and I believe the reason for this behavior is as follows:
ObservableTakeUntil class in its subscribeActual method first subscribes to the other observable and only afterwards subscribes to the source observable:
In my test, stopSubject acts as the other observable, and since it already has a value in advance, subscribing to it immediately triggers the TakeUntilMainObserver.otherComplete method, which writes a special DISPOSED value into the TakeUntilMainObserver.upstream field (using the helper method DisposableHelper.dispose):
The subsequent subscription to the source observable in ObservableTakeUntil.subscribeActual calls subscribeActual on ObservableCreate, which first calls onSubscribe on the passed observer, and only then invokes the source callback:
The call to observer.onSubscribe inside ObservableCreate ends up calling TakeUntilMainObserver. onSubscribe, which tries to set the passed disposable into the upstream field using the helper method DisposableHelper.setOnce:
But since the upstream field already contains the special DISPOSED value, the assignment doesn’t happen, and instead DisposableHelper.setOnce calls dispose on the passed disposable. In this case, the disposable is an instance of ObservableUsing$UsingObserver, which proceeds to dispose the resource:
Therefore, when control returns back to ObservableCreate.subscribeActual after onSubscribe is called, and the source callback is finally invoked, the resource has already been disposed, and the emitter passed to the callback (CreateEmitter) is already in disposed state.
I believe this current behavior is incorrect, and in the test otherObservableHasValueInAdvance, one of the following should happen:
• Either the callback passed to Observable.create should not be invoked at all,
• Or the callback should be invoked before the resource is disposed and the emitter is transitioned to the disposed state.
The text was updated successfully, but these errors were encountered:
Either the callback passed to Observable.create should not be invoked at all
Some callback may want to still run when the resource is disposed. You may need to check the disposed state within the callback since in the general case, dispose can happen asynchronously to the execution of the body.
Or the callback should be invoked before the resource is disposed and the emitter is transitioned to the disposed state.
Not possible, because the callback may be something blocking thus the control may never return to the subscribeActual. Simple example: a callback which sleep-waits in a loop to detect disposing the emitter, which would deadlock.
I’m observing behavior that seems strange to me when I use an Observable constructed in the following way.
I’m using
Observable.using
to create an observable based on some resource. InObservable.using
, I pass a function assourceSupplier
, which returns an observable created usingObservable.create
.Then I apply the
takeUntil
operator to the observable created byObservable.using
to combine it with another observable —stopSubject
, which in this example is a BehaviorSubject.I expect that when the callback passed to
Observable.create
is invoked, the resource created byObservable.using
has not yet been disposed, and theemitter
passed to the callback is not yet disposed either. I verify this in the tests of the attached TakeUntilTest class.TakeUntilTest.java.zip
These expectations hold true if I emit a value into stopSubject after subscribing to the observable under test (see the test
otherObservableEmitsValueAfterSubscription
).However, if I emit a value into
stopSubject
before subscribing to the observable under test, the following happens:The callback passed to
Observable.create
is invoked, but by that time the resource has already been disposed, and theemitter
passed to the callback is already in the disposed state. This is verified in the testotherObservableHasValueInAdvance
.I looked into the RxJava implementation, and I believe the reason for this behavior is as follows:
ObservableTakeUntil
class in itssubscribeActual
method first subscribes to theother
observable and only afterwards subscribes to thesource
observable:In my test,
stopSubject
acts as theother
observable, and since it already has a value in advance, subscribing to it immediately triggers theTakeUntilMainObserver.otherComplete
method, which writes a specialDISPOSED
value into theTakeUntilMainObserver.upstream
field (using the helper methodDisposableHelper.dispose
):The subsequent subscription to the
source
observable inObservableTakeUntil.subscribeActual
callssubscribeActual
onObservableCreate
, which first callsonSubscribe
on the passedobserver
, and only then invokes thesource
callback:The call to
observer.onSubscribe
insideObservableCreate
ends up callingTakeUntilMainObserver. onSubscribe
, which tries to set the passed disposable into theupstream
field using the helper methodDisposableHelper.setOnce
:But since the
upstream
field already contains the specialDISPOSED
value, the assignment doesn’t happen, and insteadDisposableHelper.setOnce
callsdispose
on the passeddisposable
. In this case, thedisposable
is an instance ofObservableUsing$UsingObserver
, which proceeds to dispose the resource:Therefore, when control returns back to
ObservableCreate.subscribeActual
afteronSubscribe
is called, and thesource
callback is finally invoked, theresource
has already been disposed, and theemitter
passed to the callback (CreateEmitter) is already in disposed state.I believe this current behavior is incorrect, and in the test
otherObservableHasValueInAdvance
, one of the following should happen:• Either the callback passed to
Observable.create
should not be invoked at all,• Or the callback should be invoked before the
resource
is disposed and theemitter
is transitioned to the disposed state.The text was updated successfully, but these errors were encountered: