-
Notifications
You must be signed in to change notification settings - Fork 7.6k
BehaviorSubject concurrent subscription and sending is broken #1184
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Thanks for the test case. I'm currently improving the BehaviorSubject and the new code passes this test. |
@andrask This has been merged to master if you can validate against that prior to release? |
The tests in https://gist.github.com/andrask/fc06abfd70daa6f91edb#file-behaviorsubjectsubscribeandsendconcurrently-java are passing for me. Closing this out as it looks fixed. Please re-open if it's not and can be demonstrated. I'd still appreciate confirmation if you can. |
@benjchristensen thank you for the notice. I wanted to try today but got overwhelmed by other stuff. I cloned the repo and started installing with Sadly, I use hystrix as well which makes it hard to apply the new RxJava version even if it comes out some time in the near future. |
Thanks @andrask. Hystrix 1.3.16+ and Hystrix 1.4.+ should both be fully compatible with the current set of changes, as both of those support RxJava 0.18+. Since I work on both projects I'm keeping Hystrix moving forward. Is there anything specific about Hystrix + Rx that isn't working well that I can solve? |
I confirm that the new version works. The combo works well. I'll check again why I wasn't able to upgrade the last time. I think I only upgraded RX and this is why it failed. |
Thanks for confirming. Yes, Hystrix had to be upgraded to work. It is no longer using any deprecated Rx code so should be safe as we're nearing the end of changes and almost to 1.0. |
I'm still seeing some concurrency issue between the subscription and the emission of the first object. |
This is expected behavior. If you you write to the subject from multiple threads and need consistency of Javadoc of /**
* Wraps a {@link Subject} so that it is safe to call its various {@code on} methods from different threads.
* <p>
* When you use an ordinary {@link Subject} as a {@link Subscriber}, you must take care not to call its
* {@link Subscriber#onNext} method (or its other {@code on} methods) from multiple threads, as this could
* lead to non-serialized calls, which violates
* <a href="http://reactivex.io/documentation/contract.html">the Observable contract</a> and creates an
* ambiguity in the resulting Subject.
* <p>
* To protect a {@code Subject} from this danger, you can convert it into a {@code SerializedSubject} with
* code like the following:
* <p><pre>{@code
* mySafeSubject = myUnsafeSubject.toSerialized();
* }</pre>
*
* @return SerializedSubject wrapping the current Subject
*/ |
Subscription is not an on* method and therefore this is not expected. On Tue, May 24, 2016 at 7:38 PM Artem Zinnatullin [email protected]
|
Well, it's hard to divide What I see at the moment:
And now I'm not sure that @sregg as temporary solution you can try to create Probably we need to define this behavior better either in javadoc or even change current impementation to emit @akarnokd will be great to get your comment here! |
I'm sorry, when I said "initial" value I wanted to say "first" value (first |
Oh, that's better, then But the problem still remains: we need to define serialized behavior for initial value passed to @akarnokd /other contributors: maybe create separate issue for that if you think it worth it? |
also, I'm using |
but I thought |
That doesn't change anything significant, it simply hides actual type of the |
Can you demonstrate this with an unit test? Currently, there is a bug with int n = 100000;
Scheduler.Worker w = Schedulers.computation().createWorker();
try {
for (int i = 0; i < n; i++) {
if ((i % 100) == 0) {
System.out.println("Round " + i);
}
AtomicInteger cdl = new AtomicInteger(2);
AtomicBoolean done = new AtomicBoolean();
BehaviorSubject<Integer> bs = BehaviorSubject.create();
TestSubscriber<Integer> ts = new TestSubscriber<>();
w.schedule(() -> {
cdl.decrementAndGet();
while (cdl.get() != 0) ;
bs.onNext(1);
done.set(true);
});
cdl.decrementAndGet();
while (cdl.get() != 0) ;
bs.subscribe(ts);
while (!done.get()) ;
int c = ts.getOnNextEvents().size();
if (c == 0) {
Assert.fail("The TestSubscriber didn't receive any values");
}
}
} finally {
w.unsubscribe();
} Note that if a |
Right, that's probably what's happening. I'm calling Here's my setup:
The problem is that the async action can be so quick to execute, it will call the callback right away, and some times, before or during the subscription of the Observable. I managed to fix this by delaying the call of the
Is there a better way to do so? |
If you have only one value to relay, use |
Good to know. But would that fix my concurrency issue? |
Seems that my idea of delaying the action in |
BehaviorSubject should ensure that the last notification always reaches the subscriber. When the subscription and sending happens concurrently, there is a high probability that this property gets broken.
Test has been prepared that easily reproduces the error.
https://gist.github.com/andrask/fc06abfd70daa6f91edb#file-behaviorsubjectsubscribeandsendconcurrently-java
The test involves two threads: 1) trying to subscribe 2) trying to send next. These are carefully coordinated to allow real concurrent execution. The test is that the subscriber must receive the sent value. The issue almost certainly happens in a few hundred retries.
Note that with a
Thread.sleep(1)
the issue goes away.Note that the test is something I distilled from what I saw in my production code. There may be little issues with it but the concurrency problem certainly exists as it is reproducibly just by stepping through the code.
The text was updated successfully, but these errors were encountered: