def open(self, callback, on_callback_error): """Begin consuming messages. Args: callback (Callable[None, google.cloud.pubsub_v1.message.Message]): A callback that will be called for each message received on the stream. on_callback_error (Callable[Exception]): A callable that will be called if an exception is raised in the provided `callback`. """ if self.is_active: raise ValueError("This manager is already open.") if self._closed: raise ValueError("This manager has been closed and can not be re-used.") self._callback = functools.partial( _wrap_callback_errors, callback, on_callback_error ) # Create the RPC stream_ack_deadline_seconds = self.ack_histogram.percentile(99) get_initial_request = functools.partial( self._get_initial_request, stream_ack_deadline_seconds ) self._rpc = bidi.ResumableBidiRpc( start_rpc=self._client.api.streaming_pull, initial_request=get_initial_request, should_recover=self._should_recover, should_terminate=self._should_terminate, throttle_reopen=True, ) self._rpc.add_done_callback(self._on_rpc_done) _LOGGER.debug( "Creating a stream, default ACK deadline set to {} seconds.".format( stream_ack_deadline_seconds ) ) # Create references to threads self._dispatcher = dispatcher.Dispatcher(self, self._scheduler.queue) self._consumer = bidi.BackgroundConsumer(self._rpc, self._on_response) self._leaser = leaser.Leaser(self) self._heartbeater = heartbeater.Heartbeater(self) # Start the thread to pass the requests. self._dispatcher.start() # Start consuming messages. self._consumer.start() # Start the lease maintainer thread. self._leaser.start() # Start the stream heartbeater thread. self._heartbeater.start()
def test_heartbeat_once(): manager = mock.create_autospec(streaming_pull_manager.StreamingPullManager, instance=True) heartbeater_ = heartbeater.Heartbeater(manager) make_sleep_mark_event_as_done(heartbeater_) heartbeater_.heartbeat() manager.heartbeat.assert_called_once()
def test_start_already_started(thread): manager = mock.create_autospec(streaming_pull_manager.StreamingPullManager, instance=True) heartbeater_ = heartbeater.Heartbeater(manager) heartbeater_._thread = mock.sentinel.thread with pytest.raises(ValueError): heartbeater_.start() thread.assert_not_called()
def test_heartbeat_stopped(caplog): caplog.set_level(logging.INFO) manager = mock.create_autospec( streaming_pull_manager.StreamingPullManager, instance=True) heartbeater_ = heartbeater.Heartbeater(manager) heartbeater_.stop() heartbeater_.heartbeat() assert 'exiting' in caplog.text
def test_stop(): manager = mock.create_autospec(streaming_pull_manager.StreamingPullManager, instance=True) heartbeater_ = heartbeater.Heartbeater(manager) thread = mock.create_autospec(threading.Thread, instance=True) heartbeater_._thread = thread heartbeater_.stop() assert heartbeater_._stop_event.is_set() thread.join.assert_called_once() assert heartbeater_._thread is None
def test_heartbeat_inactive(caplog): caplog.set_level(logging.INFO) manager = mock.create_autospec( streaming_pull_manager.StreamingPullManager, instance=True ) manager.is_active = False heartbeater_ = heartbeater.Heartbeater(manager) heartbeater_.heartbeat() assert "exiting" in caplog.text
def test_start(thread): manager = mock.create_autospec(streaming_pull_manager.StreamingPullManager, instance=True) heartbeater_ = heartbeater.Heartbeater(manager) heartbeater_.start() thread.assert_called_once_with(name=heartbeater._HEARTBEAT_WORKER_NAME, target=heartbeater_.heartbeat) thread.return_value.start.assert_called_once() assert heartbeater_._thread is not None
def test_heartbeat_inactive_manager_inactive_rpc(caplog): caplog.set_level(logging.DEBUG) manager = mock.create_autospec(streaming_pull_manager.StreamingPullManager, instance=True) manager.is_active = False manager.heartbeat.return_value = False # because of inactive rpc heartbeater_ = heartbeater.Heartbeater(manager) make_sleep_mark_event_as_done(heartbeater_) heartbeater_.heartbeat() assert "Sent heartbeat" not in caplog.text assert "exiting" in caplog.text
def open(self, callback): """Begin consuming messages. Args: callback (Callable[None, google.cloud.pubsub_v1.message.Messages]): A callback that will be called for each message received on the stream. """ if self.is_active: raise ValueError('This manager is already open.') if self._closed: raise ValueError( 'This manager has been closed and can not be re-used.') self._callback = functools.partial(_wrap_callback_errors, callback) # Create the RPC self._rpc = bidi.ResumableBidiRpc( start_rpc=self._client.api.streaming_pull, initial_request=self._get_initial_request, should_recover=self._should_recover) self._rpc.add_done_callback(self._on_rpc_done) # Create references to threads self._dispatcher = dispatcher.Dispatcher(self, self._scheduler.queue) self._consumer = bidi.BackgroundConsumer( self._rpc, self._on_response) self._leaser = leaser.Leaser(self) self._heartbeater = heartbeater.Heartbeater(self) # Start the thread to pass the requests. self._dispatcher.start() # Start consuming messages. self._consumer.start() # Start the lease maintainer thread. self._leaser.start() # Start the stream heartbeater thread. self._heartbeater.start()
def test_stop_no_join(): heartbeater_ = heartbeater.Heartbeater(mock.sentinel.manager) heartbeater_.stop()
def open(self, callback, on_callback_error): """Begin consuming messages. Args: callback (Callable[None, google.cloud.pubsub_v1.message.Message]): A callback that will be called for each message received on the stream. on_callback_error (Callable[Exception]): A callable that will be called if an exception is raised in the provided `callback`. """ if self.is_active: raise ValueError("This manager is already open.") if self._closed: raise ValueError( "This manager has been closed and can not be re-used.") self._callback = functools.partial(_wrap_callback_errors, callback, on_callback_error) # Create the RPC # We must use a fixed value for the ACK deadline, as we cannot read it # from the subscription. The latter would require `pubsub.subscriptions.get` # permission, which is not granted to the default subscriber role # `roles/pubsub.subscriber`. # See also https://github.com/googleapis/google-cloud-python/issues/9339 # # When dynamic lease management is enabled for the "on hold" messages, # the default stream ACK deadline should again be set based on the # historic ACK timing data, i.e. `self.ack_histogram.percentile(99)`. stream_ack_deadline_seconds = _DEFAULT_STREAM_ACK_DEADLINE get_initial_request = functools.partial(self._get_initial_request, stream_ack_deadline_seconds) self._rpc = bidi.ResumableBidiRpc( start_rpc=self._client.api.streaming_pull, initial_request=get_initial_request, should_recover=self._should_recover, should_terminate=self._should_terminate, throttle_reopen=True, ) self._rpc.add_done_callback(self._on_rpc_done) _LOGGER.debug( "Creating a stream, default ACK deadline set to {} seconds.". format(stream_ack_deadline_seconds)) # Create references to threads self._dispatcher = dispatcher.Dispatcher(self, self._scheduler.queue) self._consumer = bidi.BackgroundConsumer(self._rpc, self._on_response) self._leaser = leaser.Leaser(self) self._heartbeater = heartbeater.Heartbeater(self) # Start the thread to pass the requests. self._dispatcher.start() # Start consuming messages. self._consumer.start() # Start the lease maintainer thread. self._leaser.start() # Start the stream heartbeater thread. self._heartbeater.start()