Skip to main content

Delta Streaming

A Python library for building Spark Structured Streaming pipelines using Delta Lake Change Data Feed (CDF).

The library separates:

  • CDF source
  • transformations
  • filters
  • Delta MERGE sink
  • pipeline orchestration

The architecture follows SOLID principles.

Requirements

  • Python 3.10+
  • Apache Spark 3.5+
  • Delta Lake
  • A running lakehouse stack with Spark Connect, Hive Metastore, and MinIO

The Python client uses PySpark and Delta Lake. MinIO support is provided on the Spark Connect server by Hadoop S3A (hadoop-aws and the matching AWS SDK), not by a Python MinIO package. The repository's Spark image includes these JARs and configures s3a:// access to the warehouse bucket.

Installation

Create and activate the Conda environment used by the example notebook:

conda env create -f environment.yml
conda activate local-lakehouse

For an existing environment, install the same dependencies with:

pip install -e .

In VS Code, select the local-lakehouse Python kernel for src/delta_streaming/example.ipynb. Start the repository stack from its root with docker compose up -d --build. The notebook connects to sc://localhost:15002; S3A credentials and Java dependencies are configured server-side.

Data flow and checkpointing

The pipeline reads Delta Change Data Feed (CDF) records, applies the transformation and change-type filter, then passes each micro-batch to the Delta MERGE sink:

Delta source table (CDF)
    -> DeltaCDFSource.read()
    -> transformer
    -> change filter
    -> DeltaCDFMergeSink.foreachBatch()
    -> MERGE into target Delta table

DeltaCDFMergeSink sets Spark's checkpointLocation from StreamConfig.checkpoint_location.

In the example, that is an s3a:// location under MinIO's warehouse bucket. Spark writes its streaming offset, commit, and state metadata beneath that path; the checkpoint is separate from the source Delta table's _delta_log and CDF data. The bucket must exist and the Spark Connect server must have S3A configured. Spark creates the checkpoint directory itself.

The latest committed source offset in this checkpoint is the resume position. When the same source and checkpoint are used again, Spark resumes after that offset and ignores startingVersion or startingTimestamp. Those options choose the initial CDF position only when starting with a new checkpoint. If neither is set for a new stream, Delta CDF starts from the latest table version and streams subsequent changes. To replay from an earlier version, use a new checkpoint location and set starting_version (or starting_timestamp). Keep the checkpoint when restarting a failed stream; use a new one only for an intentional fresh run or replay.

CDF's durable progress is a Delta source offset (table version), not a Spark event-time watermark. The notebook prints each run's startOffset and endOffset from StreamingQuery.lastProgress, labels the last completed endOffset as the checkpoint resume watermark, and displays the target table after each run. The checkpoint itself remains the durable source of truth.

Data flow diagram

flowchart LR
    SRC[("Source Delta table<br/>_delta_log + CDF")]
    CDF["DeltaCDFSource.read()<br/>readChangeFeed=true"]
    TR[Transformer]
    FLT[ChangeTypeFilter]
    SINK["DeltaCDFMergeSink<br/>foreachBatch"]
    TGT[("Target Delta table")]
    CKPT[("Checkpoint on MinIO<br/>s3a://warehouse/...<br/>offsets / commits")]

    SRC --> CDF --> TR --> FLT --> SINK -->|MERGE| TGT
    CDF -. "reads startOffset on restart" .-> CKPT
    SINK -. "commits endOffset after batch" .-> CKPT

Checkpoint lifecycle (per run)

sequenceDiagram
    participant S as Spark streaming query
    participant C as Checkpoint (offsets/, commits/)
    participant D as Source Delta table (CDF)
    participant T as Target Delta table

    S->>C: Load last committed offset
    alt checkpoint exists
        C-->>S: Resume after last endOffset (reservoirVersion)
    else new checkpoint
        S->>D: Use starting_version / starting_timestamp (or latest)
    end
    S->>D: Read CDF changes up to latest version
    S->>C: Write planned offset (offsets/N)
    S->>T: foreachBatch: MERGE changes
    S->>C: Write commit marker (commits/N)
    Note over C: endOffset = resume watermark for next run

Spark example

from pyspark.sql import SparkSession

from delta_streaming import (
    CDFStreamingPipeline,
    ChangeTypeFilter,
    DeltaCDFMergeSink,
    DeltaCDFSource,
    IdentityTransformer,
    StreamConfig,
)


spark = (
    SparkSession.builder
    .appName("customer-cdf-stream")
    .getOrCreate()
)

config = StreamConfig(
    source_table="catalog.schema.customer_source",
    target_table="catalog.schema.customer_target",
    checkpoint_location="s3a://warehouse/checkpoints/customer-cdf",
    query_name="customer-cdf",
    starting_version=0,
)




source = DeltaCDFSource(config)

sink = DeltaCDFMergeSink(
    spark=spark,
    merge_condition="""
        target.customer_id = source.customer_id
    """,
)

pipeline = CDFStreamingPipeline(
    source=source,
    transformer=IdentityTransformer(),
    change_filter=ChangeTypeFilter(
        [
            "insert",
            "update_postimage",
            "delete",
        ]
    ),
    sink=sink,
)


query = pipeline.start(
    spark=spark,
    config=config,
)

# The sink uses availableNow=True, so this run processes available changes and exits.
query.awaitTermination()

Metadata

Release files for delta-streaming 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for delta-streaming 0.2.0
File Size Uploaded
delta_streaming-0.2.0.tar.gz 13.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for delta-streaming 0.2.0
File Interpreter ABI Platform
delta_streaming-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 28.5 kB

Release files / delta_streaming-0.2.0.tar.gz

Download URL delta_streaming-0.2.0.tar.gz
Size 13.3 kB
Tags Source
SHA-256 checksum
How to use checksums
44d7e7a78dc4236fdaf2cc79d4ec5534c1fafcf48f7e92788e5faeb1d001b2a7
BLAKE2b-256 checksum
How to use checksums
db994528c23ec83c7609da420328cc36521045efc04677ee1a3c878882b7847d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.16

Release files / delta_streaming-0.2.0-py3-none-any.whl

Download URL delta_streaming-0.2.0-py3-none-any.whl
Size 15.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9291140fadc708bb6b449d0455fda70a0bdfa6ac27280646ff51354781685dce
BLAKE2b-256 checksum
How to use checksums
fbc5367ea6e2faf02150738f98fb692508cc6abcc507aaed4cbdefedad781896
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.16

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page