From c7feaa1a6a6f00387474528028ad926207a4cd1a Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Fri, 31 Jan 2025 16:35:40 -0800 Subject: [PATCH 1/2] fix: fix thread cleanup when destroying Watch instance --- google/cloud/firestore_v1/watch.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/google/cloud/firestore_v1/watch.py b/google/cloud/firestore_v1/watch.py index 62b53ef4a..79933aeca 100644 --- a/google/cloud/firestore_v1/watch.py +++ b/google/cloud/firestore_v1/watch.py @@ -440,6 +440,9 @@ def on_snapshot(self, proto): proto(`google.cloud.firestore_v1.types.ListenResponse`): Callback method that receives a object to """ + if self._closing.locked(): + # don't process on_snapshot responses while spinning down, to prevent deadlock + return if proto is None: self.close() return From 809330fd3d1936558f0d2d3eaecb5dcfb046203e Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Fri, 21 Feb 2025 10:58:36 -0800 Subject: [PATCH 2/2] added test for on_snapshot while closing --- tests/unit/v1/test_watch.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/unit/v1/test_watch.py b/tests/unit/v1/test_watch.py index 094248e93..6d8c12abc 100644 --- a/tests/unit/v1/test_watch.py +++ b/tests/unit/v1/test_watch.py @@ -400,6 +400,15 @@ def test_watch_on_snapshot_target_w_none(): assert inst._rpc is None +def test_watch_on_snapshot_while_closing(): + inst = _make_watch() + inst.close = mock.Mock() + with inst._closing: + inst.on_snapshot(mock.Mock()) + # close should not be called again when already closing + inst.close.assert_not_called() + + def test_watch_on_snapshot_target_no_change_no_target_ids_not_current(): inst = _make_watch() proto = _make_listen_response()