Architecture and Plugin Roadmap¶
Project Purpose¶
unistream is an abstraction layer for stream system producers and consumers. It lets developers use a single, unified interface to interact with any streaming backend — Kafka, AWS Kinesis, AWS CloudWatch Logs, Pulsar, or even local files — while the library handles batching, fault tolerance, retries, and exactly-once consumption behind the scenes.
The core library (unistream) ships only in-memory and local-file implementations. Vendor-specific integrations (AWS, Kafka, etc.) are released as separate plugin packages.
The “Core + Plugin” Pattern¶
The codebase follows a strict layered design:
Layer 1 — Abstract (ABC) abstraction.py
Defines the protocol: what methods must exist.
Layer 2 — Base class producer.py, consumer.py, checkpoint.py, ...
Implements shared logic (retry, checkpoint state machine, etc.)
using only the ABC interface.
Layer 3 — Concrete implementation producers/simple.py, checkpoints/simple.py, ...
Plugs into a specific backend (local file, Kinesis, DynamoDB, ...).
Rules:
The core
unistreampackage contains Layers 1 + 2 and a set of “battery-included” Layer 3 implementations using local files.Each plugin package (e.g.
unistream-aws-kinesis) contains only Layer 3 implementations for a specific vendor. It depends onunistreambut never on other plugins.Plugins communicate with the core exclusively through the five ABCs. The ABC method signatures are frozen once a major version is released.
Two Audiences for Extensibility¶
The layered design serves two distinct audiences:
Plugin / Backend Developers (Layer 3) — They implement backend-specific methods: transport (
send,get_records), persistence (dump*,load*), and buffer operations. They do not touch business logic.End Users / Application Developers — They implement business logic (
process_record,process_failed_record) and call ready-to-use API methods (put,process_batch,run). They use pre-built Layer 3 plugins and only need to understand the end-user API.
Five Core Abstractions¶
These five abstract classes define the entire protocol of the library. User-facing documentation covers them in depth — here we summarize only the role and key contract of each.
Record¶
AbcRecord — the atomic data unit flowing through the system.
Must have
id: strandcreate_at: str(ISO 8601, timezone-aware).Must implement
serialize() -> stranddeserialize(data) -> AbcRecord.The library ships
DataClassRecord(frozen dataclass + JSON) as the default implementation.
See About This Project for the full discussion.
Buffer¶
AbcBuffer — batches records and persists them via a Write-Ahead Log (WAL) to survive crashes.
put(record)— append to WAL and in-memory queue.should_i_emit()— returnsTruewhen the batch is full (by count or bytes).emit()— returns the oldest batch of records (FIFO).commit()— deletes the WAL file after downstream confirms receipt.
The library ships FileBuffer (local WAL files).
See Buffer for the full discussion.
Producer¶
AbcProducer — the user-facing entry point for sending data.
Users call put(record); the producer internally manages the buffer, decides when to emit, and calls the subclass-provided send(records) with exponential-backoff retries. The retry is non-blocking: shall_we_retry() checks elapsed time instead of sleeping.
BaseProducer implements the full put() event loop. Subclasses only need to implement send().
See Producer for the full discussion.
Checkpoint¶
AbcCheckPoint — the most complex component, responsible for:
Stream pointer persistence —
start_pointer,next_pointertrack where to resume after restart.Per-record status tracking — each record gets a
Trackerwith status (pending / in_progress / failed / exhausted / succeeded / ignored), attempt count, and error details.Concurrency locking — UUID-based lock with expiration prevents double-processing.
Batch data backup —
dump_records()saves the raw records so they can be recovered even if the stream pointer expires.
BaseCheckPoint implements the state machine. Subclasses implement the persistence backend (dump, load, dump_records, load_records, dump_as_*).
See Checkpoint for the full discussion.
Consumer¶
AbcConsumer — continuously pulls batches from a stream and processes them.
BaseConsumer implements the full consumption loop:
get_records()— pull a batch (subclass implements).process_record(record)— process one record (subclass implements), wrapped with tenacity retry.process_failed_record(record)— DLQ hook for exhausted records (subclass can override).commit()— advancestart_pointerafter the batch is done.
See Consumer for the full discussion.
Planned Plugin Implementations¶
The following vendor-specific implementations existed in unistream v0.1.x as built-in modules. They have been removed from the core and are planned to be re-released as independent plugin packages.
unistream-aws-kinesis¶
Scope: Everything needed to produce to and consume from AWS Kinesis Data Streams.
This plugin will contain three components:
KinesisRecord — extends
DataClassRecordwithto_put_record_data()andfrom_get_record_data()for Kinesis binary encoding. Exposes apartition_keyproperty (defaults torecord.id; users override for custom partitioning).KinesisProducer — extends
BaseProducer. Implementssend()viakinesis_client.put_records(). Requiresboto_session_manager.BotoSesManagerand astream_name.KinesisConsumer — extends
BaseConsumer. Implementsget_records()via shard iteration. Handles shard discovery, iterator management, andGetRecordspagination.
Dependencies: unistream, boto3, boto_session_manager.
unistream-aws-cloudwatch¶
Scope: Produce log events to AWS CloudWatch Logs.
This plugin will contain:
CloudWatchLogsProducer — extends
BaseProducer. Implementssend()vialogs_client.put_log_events(). RequiresBotoSesManager,log_group_name, andlog_stream_name.
Dependencies: unistream, boto3, boto_session_manager.
unistream-aws-dynamodb¶
Scope: Checkpoint persistence using DynamoDB (metadata) + S3 (batch record backup).
This plugin will contain:
DynamoDBS3CheckPoint — extends
BaseCheckPoint. Implementsdump/loadvia DynamoDBput_item/get_item, anddump_records/load_recordsvia S3put_object/get_object. RequiresBotoSesManager, a DynamoDB table name (partition key = checkpoint ID), and an S3 bucket name.
This plugin is not tied to Kinesis — any consumer (Kafka, Pulsar, etc.) can use DynamoDB+S3 as its checkpoint backend.
Dependencies: unistream, boto3, boto_session_manager.