-
Notifications
You must be signed in to change notification settings - Fork 7.6k
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
OperatorMerge - RxRingBuffer throws IllegalStateException again #2604
Comments
Did this happen with version 1.0.5?
|
yes 1.0.5 |
I've updated this issue. No error is occuring in upstream. The only error occuring is the IllegalStateException. |
sigh I had hoped we'd fixed this issue in 1.0.5. |
not sure what fixes went through for that. i see that #1963 was closed but didn't notice record of the resolution (like a PR number). |
The only fix would be not to throw but just exit. We can't distinguish between an upstream ignoring unsubscription and an upstream pushing just after an unsubscription happened. |
So in my case, I wouldn't expect what you describe because the operators should be consuming all of the input stream. None of the observables should be interrupted by unsubscription before completion. Do you have an alternative theory? |
Something is unsubscribing because otherwise the queue wouldn't be null. |
righto, I'll have a close look tomorrow |
Got it. I think its an @Test(timeout = 3000)
public void testMergeEagerUnsubscribeFromUpstream() {
Func0<Object> resourceFactory = new Func0<Object>() {
@Override
public Object call() {
return new Object();
}
};
Func1<Object, Observable<Integer>> observableFactory = new Func1<Object, Observable<Integer>>() {
@Override
public Observable<Integer> call(Object o) {
return Observable.range(1, 1000000);
}
};
Action1<Object> disposeAction = new Action1<Object>() {
@Override
public void call(Object t) {
// do nothing
}
};
Observable.using(resourceFactory, observableFactory, disposeAction)
.toList()
.flatMap(new Func1<List<Integer>, Observable<Integer>>() {
@Override
public Observable<Integer> call(List<Integer> list) {
return Observable.from(list).subscribeOn(
Schedulers.computation());
}
}).count().toBlocking().single();
} |
Thanks. This is a nasty one. return new Subscriber<T>(child) { .. } should become something like this: class InnerSubscriber<T> extends Subscriber<T> {
void requestMore(long n) {
request(n);
}
// ...
}
InnerSubscriber<T> s = new InnerSubscriber<T>();
child.setProducer(s::requestMore);
child.add(s);
return s; |
|
I've rewritten public final class OnSubscribeUsing2<T, Resource> implements OnSubscribe<T> {
private final Func0<Resource> resourceFactory;
private final Func1<? super Resource, ? extends Observable<? extends T>> observableFactory;
private final Action1<? super Resource> dispose;
private final boolean disposeEagerly;
public OnSubscribeUsing2(
Func0<Resource> resourceFactory,
Func1<? super Resource, ? extends Observable<? extends T>> observableFactory,
Action1<? super Resource> dispose, boolean disposeEagerly) {
this.resourceFactory = resourceFactory;
this.observableFactory = observableFactory;
this.dispose = dispose;
this.disposeEagerly = disposeEagerly;
}
@Override
public void call(Subscriber<? super T> subscriber) {
try {
// create the resource
final Resource resource = resourceFactory.call();
// create an action that disposes only once
final Action0 disposeOnceOnly = createOnceOnlyDisposeAction(resource);
// dispose on unsubscription
subscriber.add(Subscriptions.create(disposeOnceOnly));
// create the observable
final Observable<? extends T> source = observableFactory
// create the observable
.call(resource);
final Observable<? extends T> observable;
// supplement with on termination disposal if requested
if (disposeEagerly)
observable = source
// dispose on completion or error
.doOnTerminate(disposeOnceOnly);
else
observable = source;
try {
// start
observable.unsafeSubscribe(subscriber);
} catch (Throwable e) {
Throwable disposeError = disposeEagerlyIfRequested(disposeOnceOnly);
if (disposeError != null)
subscriber.onError(new CompositeException(Arrays.asList(e,
disposeError)));
else
// propagate error
subscriber.onError(e);
}
} catch (Throwable e) {
// then propagate error
subscriber.onError(e);
}
}
private Throwable disposeEagerlyIfRequested(final Action0 disposeOnceOnly) {
if (disposeEagerly)
try {
disposeOnceOnly.call();
return null;
} catch (Throwable e) {
return e;
}
else
return null;
}
private Action0 createOnceOnlyDisposeAction(final Resource resource) {
return new Action0() {
final AtomicBoolean disposed = new AtomicBoolean(false);
@Override
public void call() {
// only want dispose called once
if (disposed.compareAndSet(false, true))
dispose.call(resource);
}
};
}
} |
I'm closing this as the related PR has been merged some days ago. |
With 1.0.5, I'm getting an
IllegalStateException
fromOperatorMerge
. This is repeatable for me but involves a big input data set being processed in chunks using flatMap/onSubscribe so I can't give you a quick test case yet. Hopefully just this description is enough otherwise I'll try and distill a test. I think it is happening close to completion.The text was updated successfully, but these errors were encountered: