When issuing an unsubscribe() on an existing watch, an exception is emitted. While python continues to function and any new on_snapshot queries work, it's not ideal to have these exceptions.
https://firebase.google.com/docs/firestore/query-data/listen#detach_a_listener
pip show google-<service> or pip freezeExpected behavior is no exception.
import time
from google.cloud import firestore
def on_snapshot(collection_snapshot, changes, read_time):
print("on_snapshot()")
client = firestore.Client()
collection_ref = client.collection("localaccts-testing")
watch = collection_ref.on_snapshot(on_snapshot)
while True:
time.sleep(30)
watch.unsubscribe()
watch = collection_ref.on_snapshot(on_snapshot)
on_snapshot()
Thread-ConsumeBidirectionalStream caught unexpected exception <_Rendezvous of RPC that terminated with:
status = StatusCode.CANCELLED
details = "Locally cancelled by application!"
debug_error_string = "None"
> and will exit.
Traceback (most recent call last):
File "/home/rmceoin/testwatch/env/lib64/python3.6/site-packages/google/api_core/bidi.py", line 543, in _thread_main
response = self._bidi_rpc.recv()
File "/home/rmceoin/testwatch/env/lib64/python3.6/site-packages/google/api_core/bidi.py", line 454, in recv
return self._recoverable(self._recv)
File "/home/rmceoin/testwatch/env/lib64/python3.6/site-packages/google/api_core/bidi.py", line 413, in _recoverable
raise exc
File "/home/rmceoin/testwatch/env/lib64/python3.6/site-packages/google/api_core/bidi.py", line 403, in _recoverable
return method(*args, **kwargs)
File "/home/rmceoin/testwatch/env/lib64/python3.6/site-packages/google/api_core/bidi.py", line 451, in _recv
return next(call)
File "/home/rmceoin/testwatch/env/lib64/python3.6/site-packages/grpc/_channel.py", line 363, in __next__
return self._next()
File "/home/rmceoin/testwatch/env/lib64/python3.6/site-packages/grpc/_channel.py", line 357, in _next
raise self
grpc._channel._Rendezvous: <_Rendezvous of RPC that terminated with:
status = StatusCode.CANCELLED
details = "Locally cancelled by application!"
debug_error_string = "None"
>
on_snapshot()
We're seeing this too. The errors are logged from a background thread, so they can't be caught/silenced and end up polluting our logs. We see it locally, e.g. when running with:
google-api-core==1.10.0
google-api-python-client==1.7.8
google-cloud-core==0.29.1
google-cloud-error-reporting==0.30.1
google-cloud-firestore==1.0.0
googleapis-common-protos==1.5.10
greenlet==0.4.15
grpc-google-iam-v1==0.11.4
grpcio==1.20.1
as well as when running in a GC Cloud Function Python3.7 environment that just requires the latest google-cloud-firestore. So, I'm pretty sure it's not terribly version/env dependent.
Let us know if more diagnostic data is useful, but this should be trivial to replicate. Thanks!
@crwilcox ISTM that this should be fixed in google.api_core.bidi: the CANCELLED error should just cause the BIDI stream to shut down gracefully.
Because the google.api_core.bidi module remains carefully agnostic of specific gRPC status codes (it doesn't even import anything from 'grpc'), I believe the best approach here is to add another argument, should_terminate, to the ResumableBidiRpc class,. Like should_resume. it would take a future / error and return a boolean (true if the stream should terminate). By default, no errors would return true.
Firestore (and maybe Pub/sub) could then customize the set of response codes used to signal "clean" shutdown of the BiDi thread.
Most helpful comment
We're seeing this too. The errors are logged from a background thread, so they can't be caught/silenced and end up polluting our logs. We see it locally, e.g. when running with:
as well as when running in a GC Cloud Function Python3.7 environment that just requires the latest google-cloud-firestore. So, I'm pretty sure it's not terribly version/env dependent.
Let us know if more diagnostic data is useful, but this should be trivial to replicate. Thanks!