Skip to content

Commit 4b35387

Browse files
chore: rename get_last_seq_newer_than to latest_sequence_from
1 parent 0e317e8 commit 4b35387

2 files changed

Lines changed: 41 additions & 46 deletions

File tree

‎ibmcloudant/features/changes_follower.py‎

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -487,39 +487,34 @@ def stop(self) -> None:
487487
"""
488488
self._iter.stop()
489489

490-
def get_last_seq_newer_than(self, last_persisted_seq: str) -> str:
490+
def latest_sequence_from(self, checkpoint_sequence_id: str) -> str:
491491
"""
492-
Return the newest sequence ID that is safe to use as a checkpoint
493-
after the given persisted sequence ID.
494-
495-
Use this after fully processing a ``ChangesResultItem`` to determine
496-
whether this ``ChangesFollower`` has observed a later safe checkpoint.
497-
This is useful for filtered or sparse changes feeds, where the feed
498-
can advance across pages even when no additional user-processable
499-
change rows are returned.
500-
501-
The supplied sequence ID must be the ``seq`` of a
502-
``ChangesResultItem`` that your application has fully processed and
503-
already persisted. This method returns a newer sequence only when
504-
doing so does not advance past later change rows that might not yet
505-
have been processed by your application.
506-
507-
:param str last_persisted_seq: The ``seq`` of the last
508-
``ChangesResultItem`` that your application has fully processed
509-
and persisted.
510-
:raises ValueError: If the provided sequence ID is null or empty.
511-
:return: The newest safe sequence ID to persist as
512-
``PostChangesParams.since``. Returns the supplied ID unchanged
513-
if no newer safe checkpoint is available, the feed has not
514-
started yet, or the supplied ID is not present in this
515-
``ChangesFollower`` instance's retained sequence history.
492+
Returns the most recent sequence ID that is safe to use as a
493+
checkpoint, advancing beyond the supplied checkpoint sequence ID
494+
where possible.
495+
496+
With highly filtered changes feeds, multiple pages can pass through
497+
the follower without returning any changes. Using only the ``seq``
498+
of the last processed ``ChangesResultItem`` in those cases causes a
499+
long changes feed rewind on the next run. To avoid this, call this
500+
method after fully processing each ``ChangesResultItem`` with a
501+
non-``None`` ``seq`` and persist the returned value to use as the
502+
``since`` parameter for the next run.
503+
504+
:param str checkpoint_sequence_id: The last checkpoint sequence ID
505+
— either the non-``None`` ``seq`` of the last ``ChangesResultItem``
506+
fully processed, or a value previously returned by this method.
507+
:return: The most recent safe sequence ID to use as a checkpoint,
508+
or the supplied value if no newer sequence is available.
516509
:rtype: str
510+
511+
Throws ValueError if ``checkpoint_sequence_id`` is ``None`` or empty.
517512
"""
518-
if not last_persisted_seq:
519-
raise ValueError('The provided sequence ID cannot be null or empty.')
513+
if not checkpoint_sequence_id:
514+
raise ValueError('Provided sequence ID must be a non-empty string.')
520515
if self._iter is None:
521-
return last_persisted_seq
522-
return self._iter.last_seq_since(last_persisted_seq)
516+
return checkpoint_sequence_id
517+
return self._iter.last_seq_since(checkpoint_sequence_id)
523518

524519
def _run(self, mode: _Mode):
525520
if self._iter is not None:

‎test/unit/features/test_changes_follower.py‎

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -940,40 +940,40 @@ def test_last_seq_since_none_last_seq_advances_beyond(self):
940940

941941

942942
# ---------------------------------------------------------------------------
943-
# TestGetLastSeqNewerThan — unit tests for ChangesFollower.get_last_seq_newer_than
943+
# TestLatestSequenceFrom — unit tests for ChangesFollower.latest_sequence_from
944944
# ---------------------------------------------------------------------------
945945

946-
class TestGetLastSeqNewerThan(ChangesFollowerBaseCase):
946+
class TestLatestSequenceFrom(ChangesFollowerBaseCase):
947947

948-
def test_get_last_seq_newer_than_with_none(self):
948+
def test_latest_sequence_from_with_none(self):
949949
"""Raises ValueError when passed None."""
950950
follower = ChangesFollower(self.client, db='db')
951-
with self.assertRaisesRegex(ValueError, 'The provided sequence ID cannot be null or empty'):
952-
follower.get_last_seq_newer_than(None)
951+
with self.assertRaisesRegex(ValueError, 'Provided sequence ID must be a non-empty string'):
952+
follower.latest_sequence_from(None)
953953

954-
def test_get_last_seq_newer_than_with_empty_string(self):
954+
def test_latest_sequence_from_with_empty_string(self):
955955
"""Raises ValueError when passed an empty string."""
956956
follower = ChangesFollower(self.client, db='db')
957-
with self.assertRaisesRegex(ValueError, 'The provided sequence ID cannot be null or empty'):
958-
follower.get_last_seq_newer_than('')
957+
with self.assertRaisesRegex(ValueError, 'Provided sequence ID must be a non-empty string'):
958+
follower.latest_sequence_from('')
959959

960-
def test_get_last_seq_newer_than_before_feed_starts(self):
960+
def test_latest_sequence_from_before_feed_starts(self):
961961
"""Returns the input seq unchanged when the feed has not started yet."""
962962
follower = ChangesFollower(self.client, db='db')
963-
self.assertEqual(follower.get_last_seq_newer_than('seq-a'), 'seq-a')
963+
self.assertEqual(follower.latest_sequence_from('seq-a'), 'seq-a')
964964

965965
@responses.activate
966-
def test_get_last_seq_newer_than_unknown_seq(self):
966+
def test_latest_sequence_from_unknown_seq(self):
967967
"""Returns the input seq unchanged when it was never seen by this follower."""
968968
self.prepare_mock_changes(batches=1)
969969
follower = ChangesFollower(self.client, db='db')
970970
changes = follower.start_one_off()
971971
for _ in changes:
972972
pass
973-
self.assertEqual(follower.get_last_seq_newer_than('seq-unknown'), 'seq-unknown')
973+
self.assertEqual(follower.latest_sequence_from('seq-unknown'), 'seq-unknown')
974974

975975
@responses.activate
976-
def test_get_last_seq_newer_than_middle_of_batch(self):
976+
def test_latest_sequence_from_middle_of_batch(self):
977977
"""
978978
Returns the input seq unchanged when querying with a seq from the
979979
middle of a batch — only the last item's seq is stored in seq_markers.
@@ -985,18 +985,18 @@ def test_get_last_seq_newer_than_middle_of_batch(self):
985985
# seq-a and seq-b are middle items — not stored in seq_markers
986986
seq_a = items[0].seq
987987
seq_b = items[1].seq
988-
self.assertEqual(follower.get_last_seq_newer_than(seq_a), seq_a)
989-
self.assertEqual(follower.get_last_seq_newer_than(seq_b), seq_b)
988+
self.assertEqual(follower.latest_sequence_from(seq_a), seq_a)
989+
self.assertEqual(follower.latest_sequence_from(seq_b), seq_b)
990990

991991
@responses.activate
992-
def test_get_last_seq_newer_than_end_to_end(self):
992+
def test_latest_sequence_from_end_to_end(self):
993993
"""Returns the correct last_seq through a completed stream."""
994994
self.prepare_mock_changes(batches=1)
995995
follower = ChangesFollower(self.client, db='db')
996996
changes = follower.start_one_off()
997997
items = list(changes)
998998
# Last item's seq should map to the page's last_seq
999999
last_item_seq = items[-1].seq
1000-
result = follower.get_last_seq_newer_than(last_item_seq)
1000+
result = follower.latest_sequence_from(last_item_seq)
10011001
# The last item seq IS the last_seq for a normal page (type 1 equivalent)
10021002
self.assertEqual(result, last_item_seq)

0 commit comments

Comments
 (0)