Cancelling a Watch causes RuntimeException
Closed this issue · 3 comments
We're now using Watch in a bunch of places, but trying to cancel the Watch results in a RuntimeException (not very friendly). @sjamesr @spetrovic77
10-15 20:45:02.867 20580-20925/io.v.android.apps.syncslides E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-1282
Process: io.v.android.apps.syncslides, PID: 20580
java.lang.RuntimeException: Error retrieving next stream element.
at io.v.v23.syncbase.nosql.DatabaseImpl$WatchChangeStreamImpl$1.computeNext(DatabaseImpl.java:286)
at io.v.v23.syncbase.nosql.DatabaseImpl$WatchChangeStreamImpl$1.computeNext(DatabaseImpl.java:271)
at com.google.common.collect.AbstractIterator.tryToComputeNext(AbstractIterator.java:143)
at com.google.common.collect.AbstractIterator.hasNext(AbstractIterator.java:138)
at io.v.android.apps.syncslides.db.CurrentSlideWatcher.watchCurrentSlide(CurrentSlideWatcher.java:112)
at io.v.android.apps.syncslides.db.CurrentSlideWatcher.access$000(CurrentSlideWatcher.java:27)
at io.v.android.apps.syncslides.db.CurrentSlideWatcher$1.run(CurrentSlideWatcher.java:51)
at java.lang.Thread.run(Thread.java:818)
Caused by: io.v.v23.verror.VException: gojni:<rpc.Client>"/@6@wsh@127.0.0.1:52895@@505fcf7050bf9010a02f4f0f60bf4fcf@s@dev.v.io/u/ken.vanadium@gmail.com/android/io.v.android.apps.syncslides@@/syncslides/syncslides".WatchGlob: Canceled: [remote=@6@wsh@127.0.0.1:52895@@505fcf7050bf9010a02f4f0f60bf4fcf@s@dev.v.io/u/ken.vanadium@gmail.com/android/io.v.android.apps.syncslides@@: gojni:<rpc.Client>"/@6@wsh@127.0.0.1:52895@@505fcf7050bf9010a02f4f0f60bf4fcf@s@dev.v.io/u/ken.vanadium@gmail.com/android/io.v.android.apps.syncslides@@/syncslides/syncslides".WatchGlob: Bad protocol or type: failed to decode response: EOF]
at io.v.v23.verror.VExceptionVdlConverter.nativeFromVdlValue(VExceptionVdlConverter.java:70)
at io.v.v23.verror.VExceptionVdlConverter.nativeFromVdlValue(VExceptionVdlConverter.java:22)
at io.v.v23.vom.BinaryDecoder.readValue(BinaryDecoder.java:190)
at io.v.v23.vom.BinaryDecoder.readValueMessage(BinaryDecoder.java:118)
at io.v.v23.vom.BinaryDecoder.decodeValue(BinaryDecoder.java:85)
at io.v.v23.vom.VomUtil.decode(VomUtil.java:110)
at io.v.impl.google.rpc.StreamImpl.nativeRecv(Native Method)
at io.v.impl.google.rpc.StreamImpl.recv(StreamImpl.java:32)
at io.v.impl.google.rpc.ClientCallImpl.recv(ClientCallImpl.java:89)
at io.v.v23.services.watch.GlobWatcherClientImpl$2.recv(GlobWatcherClientImpl.java:67)
at io.v.v23.services.watch.GlobWatcherClientImpl$2.recv(GlobWatcherClientImpl.java:58)
at io.v.v23.syncbase.nosql.DatabaseImpl$WatchChangeStreamImpl$1.computeNext(DatabaseImpl.java:279)
at io.v.v23.syncbase.nosql.DatabaseImpl$WatchChangeStreamImpl$1.computeNext(DatabaseImpl.java:271)
at com.google.common.collect.AbstractIterator.tryToComputeNext(AbstractIterator.java:143)
at com.google.common.collect.AbstractIterator.hasNext(AbstractIterator.java:138)
at io.v.android.apps.syncslides.db.CurrentSlideWatcher.watchCurrentSlide(CurrentSlideWatcher.java:112)
at io.v.android.apps.syncslides.db.CurrentSlideWatcher.access$000(CurrentSlideWatcher.java:27)
at io.v.android.apps.syncslides.db.CurrentSlideWatcher$1.run(CurrentSlideWatcher.java:51)
at java.lang.Thread.run(Thread.java:818)
Can you link to the code that cancels the watch?
public void removeListener(DB.CurrentSlideListener listener) {
mListeners.remove(listener);
if (!hasListeners()) {
mVContext.cancel();
mThread.interrupt();
mThread = null;
mHandler.removeCallbacksAndMessages(null);
}
}
I think a workaround for now would be to call cancel
on the stream that you get at line 110 rather than on the VContext. Refactoring the code to do this without races might be a bit tricky.
It's weird to have two ways to cancel the stream. We should make both work or remove one. If we wanted to leave the API as is, we need to change StreamImpl to recognize a VException representing a context cancel
as endOfData()
and not rethrow.