How to Track Checkpoint Offset After Batch Commit in Python

A batch processor that tracks the last successfully committed offset after processing records in batches, advancing the checkpoint only when each batch commits successfully.

Easy Python 3.9+ Aug 9, 2026 Data pipelines & processing 12 views 0 copies

Python code

35 lines
Python 3.9+
import json
from typing import Any


class BatchProcessor:
    """Tracks checkpoint offset after committing batches."""

    def __init__(self, batch_size: int = 3):
        self.batch_size = batch_size
        self.offset = 0  # last successfully committed offset (exclusive)
        self.total_committed = 0

    def process_and_commit(self, records: list[Any]) -> int:
        """Process records in batches, advancing checkpoint only on full commit."""
        for i in range(0, len(records), self.batch_size):
            batch = records[i:i + self.batch_size]
            # Simulate successful commit
            self.total_committed += len(batch)
            self.offset = i + len(batch)  # checkpoint = end of this batch
        return self.offset

    def get_state(self) -> dict:
        return {
            "last_checkpoint_offset": self.offset,
            "total_committed": self.total_committed,
            "pending": False,
        }


if __name__ == "__main__":
    processor = BatchProcessor(batch_size=3)
    events = ["evt_1", "evt_2", "evt_3", "evt_4", "evt_5", "evt_6", "evt_7"]
    final_offset = processor.process_and_commit(events)
    print(json.dumps(processor.get_state(), indent=2))
    print(f"Final checkpoint offset: {final_offset}")

Output

stdout
{
  "last_checkpoint_offset": 7,
  "total_committed": 7,
  "pending": false
}
Final checkpoint offset: 7

How it works

The process_and_commit method iterates over records in fixed-size chunks using Python's range with a step. For each batch, it simulates a successful commit by incrementing total_committed and updating offset to the exclusive end index of the current batch. After all batches are processed, the offset equals the total number of records, and get_state returns a serializable dict suitable for persisting the checkpoint. This pattern is what stream processing systems use internally to track progress and resume from where they last committed.

Common mistakes

  • Updating the offset before the commit actually succeeds, risking data loss or reprocessing.
  • Forgetting that the offset is exclusive, so setting it to `i` instead of `i + len(batch)` leaves the last record unprocessed.
  • Storing the offset as a simple counter rather than a dictionary when you need multiple checkpoint fields.

Variations

  1. Use `enumerate(records)` with a modulo check to build batches inside a single loop.
  2. Persist `get_state()` to a file or external store (e.g., Redis) after each commit for crash recovery.

Real-world use cases

  • Kafka consumers committing partition offsets after processing each batch of messages.
  • ETL pipelines that checkpoint progress into a database so a restarted job skips already-processed rows.
  • Event ingestion services that resume from the last acknowledged record after a worker crash.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Data pipelines & processing

Related tutorials and quizzes for this topic.