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.
Python code
35 linesimport 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
{
"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
- Use `enumerate(records)` with a modulo check to build batches inside a single loop.
- 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
More from Data pipelines & processing
- Add a UUID Surrogate Key to Each Row in a CSV with Python easy
- Attach Source File Metadata to Records in Python easy
- Build a Python Utility That Detects Duplicate Records Across Multiple Excel Sheets medium
- Check Null Rate Threshold in PySpark DataFrame medium
- Count Records Processed per Category in Python easy
- Create Data Helper Functions in Python for Beginners easy
Keep learning
Related tutorials and quizzes for this topic.