A lightweight, single-node micro-batching engine designed for high-performance streaming analytics using pure PyArrow and DuckDB.
Project description
Rill Streaming Engine (rills)
Rill is a lightweight, single-node micro-batching engine designed for high-performance streaming analytics using pure PyArrow and zero-copy DuckDB.
By bypassing traditional Python data structures and the Global Interpreter Lock (GIL) where possible, Rill ingests continuous event streams directly into C++ contiguous memory (pyarrow.Table). It leverages a scheduled processing trigger to buffer, join, aggregate, and query incoming data efficiently without the overhead of event-by-event Python loops.
From raw data ingestion to complex multi-stream joins, aggregations, scheduled SQL pipelines, and structured alerting, every operation is strictly contained within C++ vectorized memory, making Rill the ideal zero-infrastructure solution for live data processing.
๐๏ธ Architecture & Data Flow
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ RILL ENGINE โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโ Micro-Batch Loop โโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Input Connectors โ (Trigger Interval) โ Table Registry โ โ
โ โ โ โ โ โ
โ โ โข Memory / JSON Stream โ โโโโโโโโโโโโโโโโโโโโโโโโ> โ โข Snapshot (PK Upsert)โ โ
โ โ โข WebSocket / Kafka โ โ โข Append-Only (TTL) โ โ
โ โ (Backpressure Buffer) โ โ (z_insert/z_update) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโฌโโโโโโโโโโโโ โ
โ โ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โผ โผ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Compute Transformations โ โ
โ โ โ โ
โ โ โข Zero-Copy DuckDB Scheduled SQL Pipelines (Live Tables In-Memory) โ โ
โ โ โข Multi-Stream Relational Joins & Aggregations โ โ
โ โ โข Vectorized TTL Pruning (Age / Row Count) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Persistent Metrics & Telemetry โ โ
โ โ โ โ
โ โ โข Dual-Connection Topology: Writes business metrics & engine telemetry โ โ
โ โ to an on-disk `rill_metrics.db` for isolated serving and dashboarding. โ โ
โ โ โข Structured Alerts Pipeline: Engine exceptions & user-pushed alerts โ โ
โ โ written to `rill_alerts` table for dashboard visibility. โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โจ Key Features & Governance
1. Table Processing Modes (snapshot vs append) & Mandatory TTL
- Snapshot Mode (
mode="snapshot"or"upsert"): Maintains unique state tables by atomically replacing matching rows whenprimary_keyis defined (pc.is_in/left antijoin). TTL (RetentionPolicy) is optional. - Append-Only Mode (
mode="append"): Every incoming micro-batch is appended strictly without overwriting previous rows, even if a primary key or ID column is present. - Mandatory TTL Governance: Because append-only event streams grow continuously with every event, Rill strictly enforces that a
RetentionPolicy(max_rowsormax_age_seconds) is provided for append-only tables (mode="append"), preventing unbounded streams from exhausting system RAM over time.
2. Automated System Metadata Columns (z_insert_ts, z_update_ts)
Every table inside Rill automatically maintains two system timestamps (pa.float64() unix seconds since epoch):
z_insert_ts: Recorded when a record first arrives. During primary-key upserts, existing records preserve their originalz_insert_tsvia zero-copy C++ lookup.z_update_ts: Automatically refreshed to the current timestamp on every modification.- Governed TTL: By default,
RetentionPolicy(max_age_seconds=...)usesz_insert_ts(time_column="z_insert_ts") to accurately evict aged rows during each micro-batch tick.
3. Schema Primary Key & Mode Embedding
Use rills.schema([fields], primary_key="user_id", mode="append") to embed governance properties directly inside PyArrow schema metadata (schema.metadata[b"primary_key"]). When a RillTable is initialized with an enriched schema, it automatically extracts its primary key and operating mode without manual boilerplate.
4. PyArrow Memory Budget Governance
Configure RillEngine(memory_budget_bytes=...) or memory_budget_mb=... along with an optional on_memory_warning callback. During every micro-batch iteration (step()), Rill monitors pa.total_allocated_bytes() across all C++ memory pools and emits a ResourceWarning if the memory threshold is crossed.
5. Multi-Stream Joins & Aggregations (TableJoinTask)
Continuously join two live stream tables (left_table, right_table) via C++ relational hash-joins (pc.is_in / Table.join) and calculate real-time aggregations (sum, count, avg, min, max) without exiting PyArrow memory.
6. Bounded Connector Backpressure
Input connectors (MemoryConnector, JSONStreamConnector) enforce configurable limits (max_buffer_records, max_buffer_bytes) paired with overflow strategies ("drop_oldest", "drop_newest", "error") that slice excess data cleanly across batch boundaries.
7. DuckDB Zero-Copy SQL Pipelines
Execute standard SQL queries across any live pyarrow.Table using zero-copy DuckDB (duckdb.query). Attach Scheduled SQL Tasks (ScheduledSQLTask) to continuously transform live data streams into new dynamic tables at precise intervals.
8. Quack Server & WebSocket Bridge (quack:0.0.0.0:9494)
Expose all internal Rill tables and real-time engine telemetry over native TCP/IP using the Quack Protocol. When enabled via engine.start(quack_port=9494, quack_token="secure_token"), Rill starts a background server thread that allows external tools, worker processes, and dashboards to securely query live PyArrow memory with zero-copy shared memory semantics.
9. Dynamic KPI Dashboards via Scheduled Queries
Define Scheduled SQL Tasks (engine.add_dashboard_scheduled_query(...)) to dynamically extract and aggregate domain KPIs (e.g., maximum order tickets, cumulative revenue) in real-time. The dashboard instantly renders these live views as business metrics and evaluates threshold alerts against them.
10. Structured Alerts & Observability Pipeline
Rill includes a full-stack alerts and observability pipeline that captures engine exceptions, user-pushed alerts, and threshold-based rule triggers into a persistent rill_alerts DuckDB table โ visible in real-time on the dashboard.
- Structured Logging: Every module uses
logging.getLogger(__name__)with proper Python logging. No silentexcept: passblocks โ all errors are logged and recorded. - Server-Side Alert Recording: All internal engine exceptions (connector failures, SQL task errors, memory budget warnings, business metric evaluation failures) are automatically recorded as structured alerts with severity (
error,warning,info), source component, and traceback detail. - User-Facing Alert API: Push custom alerts directly from application code:
# Primary method with full control engine.push_alert("Revenue dropped below threshold", severity="warning", detail="Current: $847") engine.push_alert("Payment gateway timeout", severity="error", detail=traceback.format_exc()) # Convenience methods engine.alert("Batch processed successfully") # severity="info" engine.warn("High latency detected on orders") # severity="warning" engine.error("Database connection failed") # severity="error"
- Dashboard Integration: All alerts (engine, user, and rule-based) appear in the Alert Logs view with severity badges (๐ด Error, ๐ก Warning, ๐ต Info), source badges (๐ค User, โ๏ธ Engine, โก Rule), filter toggles, and toast notifications.
- Automatic Retention: Alerts older than 1 hour are automatically pruned during each metrics flush cycle.
๐ Live Business Intelligence & Quack Dashboard
Rill includes a state-of-the-art, dark-themed Live Business Intelligence & System Monitoring Dashboard built with Node.js, WebSocket Quack Bridge (quack_worker.py), and Chart.js.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ NODE.JS / BROWSER DASHBOARD โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ ๐ Key Business Intelligence & Scheduled Queries (Live Streaming) โ โ
โ โ [ max_order_amount ($): $497.34 ] [ total_revenue ($): $13,025.21 ] โ โ
โ โ [ cancelled_ratio: 26.5% ] โ โ
โ โ ๐ Scheduled Line & Bar Charts evaluating Live SQL Data โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ๏ธ Engine Infrastructure & Resource Utilization โ โ
โ โ ๐ป CPU: 37.6% | ๐พ RAM: 3.6 GB | ๐น PyArrow: 12.47 MB | โก Latency: 17msโ โ
โ โ ๐ System Resource History (CPU / Memory Trend Graph) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฒโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ WebSocket JSON Stream
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ NODE.JS QUACK BRIDGE SERVER โ
โ (dashboard/server.js + quack_worker.py) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฒโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Native Quack Protocol (TCP Socket)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ RILL STREAMING ENGINE (`quack:9494`) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Dashboard Highlights:
- ๐ Multi-View Glassmorphic Navigation: Seamlessly switch between the Metrics Console, Custom Queries, Alert Rules & Settings, and Alert Logs right from the top bar.
- ๐ Business Intelligence Centerpiece: Highlights Custom Scheduled Queries mapped to Live Charts and extracts numeric results into business KPI metrics that trigger alerts instantaneously.
- ๐ Custom SQL Queries & Chart Mapping: Write, execute, and schedule ad-hoc SQL queries against the on-disk
rill_metricsdatabase. Map query results on the fly to Interactive Line, Bar, and Scatter Charts with zoom/pan capabilities powered bychartjs-plugin-zoom. - โ๏ธ Separated System Infrastructure: Cleanly separates host CPU, System Memory, PyArrow C++ pool allocations, DuckDB storage size (
LivevsMetricsDB), throughput (RPS), and step latency into a dedicated secondary monitoring section. - ๐ Unified Alert Logs: Displays engine-side exceptions, user-pushed alerts, and threshold rule triggers in a single unified view with severity badges (๐ด๐ก๐ต), source badges (๐ค User / โ๏ธ Engine / โก Rule), filter toggles (All / Errors / Warnings / User / Engine / Rules), and severity-colored toast notifications for real-time visibility.
- ๐ Browser-Native Sound Alerts: Real-time Web Audio API acoustic engine with selectable tones (
Classic Beep,Warning Siren,Gentle Chime,Urgent Buzzer), customizable duration sliders (1sโ30s), and instant sound preview. - โช Offline / Disconnected Grey Tabs: Multi-tab connection bar with automatic health tracking. If a remote Quack server drops connection or exits, its tab instantly turns grey with a grey status dot and hover failure details.
- ๐ Server-Side Webhook Relay (
POST /api/webhook/send): Bypasses browser CORS restrictions by routing real-time alert notifications directly to Slack Incoming Webhooks, Google Chat / Google Meet Cards, or Custom JSON endpoints. - โก Real-Time Threshold Rule Engine: Evaluates custom trigger rules (
>,>=,<,<=,==) on system and business metrics with cooldown protection. Rules and settings persist automatically inlocalStorage.
๐ Quickstart Guide
Installation
Install Rill locally or in editable mode with development & connector dependencies:
git clone https://github.com/lijose/rill.git
cd rill
python3 -m venv .env
source .env/bin/activate
pip install -e .
1. Running the Live Dashboard & Quack Demo
Step 1: Launch the Rill engine with live simulated orders and custom business metrics:
python3 examples/quack_dashboard_demo.py
(Note your quack:127.0.0.1:9494 address and auth token printed in the terminal).
Step 2: In a separate terminal, start the Node.js Dashboard Bridge:
cd dashboard
npm install
npm start
Step 3: Open your browser to http://localhost:3000, enter quack:127.0.0.1:9494 and your token, and click Connect Console!
2. Basic Micro-Batching & DuckDB SQL Pipeline
import time
import pyarrow as pa
import pyarrow.compute as pc
from rills import RillEngine, MemoryConnector, ScheduledSQLTask, RetentionPolicy, schema
# 1. Initialize Rill Engine with a 200ms micro-batch interval and 500 MB memory budget
engine = RillEngine(
trigger_interval_ms=200,
memory_budget_mb=500.0,
quack_address="quack:0.0.0.0:9494",
quack_token="secret_token"
)
# 2. Define schema with primary key and register table
orders_schema = schema([
("order_id", pa.int64()),
("user_tier", pa.string()),
("amount", pa.float64())
], primary_key="order_id", mode="snapshot")
engine.register_table("orders", schema=orders_schema)
# 3. Schedule a live dashboard query to compute business KPIs
engine.add_dashboard_scheduled_query(
name="Max Order Amount",
query="SELECT MAX(amount) as max_amount FROM orders",
interval_seconds=1.0,
chart_type="bar",
x_col="ts",
y_col="max_amount"
)
# 4. Attach memory connector to 'orders' table
connector = MemoryConnector(target_table="orders")
engine.add_connector(connector)
# 5. Add a Scheduled DuckDB SQL Query running every 1 second
sql_task = ScheduledSQLTask(
name="tier_revenue",
query="SELECT user_tier, SUM(amount) as total_revenue, COUNT(*) as order_count FROM orders GROUP BY user_tier",
output_table="revenue_by_tier",
interval_seconds=1.0
)
engine.add_sql_task(sql_task)
# 6. Start engine and Quack server (`quack:0.0.0.0:9494`)
engine.start()
# Push incoming events directly to connector
batch = pa.RecordBatch.from_pydict({
"order_id": [1, 2, 3],
"user_tier": ["Gold", "Silver", "Gold"],
"amount": [100.50, 45.00, 250.00]
}, schema=orders_schema)
connector.push(batch)
time.sleep(1.2)
# The live data is fully isolated to prevent locking issues.
# Telemetry, Scheduled Queries, and Alerts can be read safely via metrics_con:
alerts = engine.metrics_con.execute("SELECT * FROM rill_alerts LIMIT 5").df()
print("Recent System Alerts:\n", alerts)
engine.stop()
3. Alerts & Observability
from rills import RillEngine, MemoryConnector
import traceback
engine = RillEngine(
trigger_interval_ms=200,
quack_address="quack:0.0.0.0:9494"
)
engine.register_table("orders", primary_key="order_id")
connector = MemoryConnector(target_table="orders")
engine.add_connector(connector)
# Push custom alerts from your application code
engine.alert("Engine started successfully") # info severity
engine.warn("Order queue backlog exceeds threshold") # warning severity
try:
# Your business logic here
result = process_payment(order)
except Exception:
engine.error("Payment processing failed", detail=traceback.format_exc())
# Alerts with full control
engine.push_alert(
"Revenue dropped below $1,000",
severity="warning",
detail="Current daily revenue: $847.23. Threshold: $1,000."
)
engine.start()
# Engine exceptions (connector failures, SQL errors, memory warnings) are
# automatically recorded as alerts โ no extra code needed.
# All alerts appear in the dashboard Alert Logs view.
Alerts are stored in the rill_alerts DuckDB table and can also be queried directly:
results = engine.metrics_con.execute("""
SELECT ts, severity, source, message
FROM rill_alerts
WHERE severity = 'error'
ORDER BY ts DESC LIMIT 10
""").fetchall()
๐ Advanced Example: Multi-Stream Joins
See our complete end-to-end multi-stream demo inside examples/:
python3 examples/multi_stream_join_demo.py
This demo illustrates:
- Joining a live
user_profilestable with a continuousordersstream intoorders_enriched. - Calculating regional revenue aggregations via DuckDB SQL every second.
๐งช Running Tests
Rill is verified by a comprehensive test suite (pytest) covering schema enrichment, primary key extraction, table processing modes, mandatory TTL validation, memory governance warnings, backpressure slicing, zero-copy joins, alerts pipeline, bug regression tests, and connector edge cases:
pytest tests/ -v
Test coverage includes:
test_alerts_pipeline.pyโ Alert recording, DuckDB persistence, user API (push_alert,alert,warn,error), connector error alert generation, alert retentiontest_bug_fixes.pyโ Import sanity, connector edge cases (inconsistent rows, empty pushes, deque buffers), O(Nยฒ) buffer fix, streaming JSON export, resource cleanuptest_engine.pyโ Step execution, callbacks, start/stop lifecycletest_connectors.pyโ Memory, JSON stream, and file connectorstest_backpressure.pyโ Bounded buffer overflow strategiestest_duckdb_sql.pyโ Zero-copy queries, scheduled SQL taskstest_stream_joins.pyโ Multi-stream join tasks with and without aggregationtest_schema.pyโ Schema enrichment, primary key extraction, row size estimationtest_retention.pyโ Max rows and max age TTL pruningtest_table_modes.pyโ Snapshot vs append mode behaviortest_upsert.pyโ Single/composite primary key upserts, append modetest_metrics.pyโ System and business metrics trackingtest_memory_budget.pyโ Memory budget warnings and callbacks
๐ค Contributing
We welcome community contributions! Please review our CONTRIBUTING.md guide and CODE_OF_CONDUCT.md before opening pull requests or reporting issues.
๐ License
Rill is open-sourced under the MIT License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rills-0.1.0.tar.gz.
File metadata
- Download URL: rills-0.1.0.tar.gz
- Upload date:
- Size: 58.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1ee79da76cbe64e7157868191942e375894be3019f64e02e1ffa3a1a6e0c891c
|
|
| MD5 |
60e999d8b4e1d7d083ab7b7ec337e0c0
|
|
| BLAKE2b-256 |
c665b437b7ec8f4258655199f72d3d89c5c284d4e33ad256f35261d1177bb151
|
File details
Details for the file rills-0.1.0-py3-none-any.whl.
File metadata
- Download URL: rills-0.1.0-py3-none-any.whl
- Upload date:
- Size: 47.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c5f1606c36d037576f61453aae8ff717d961d69a18445e0a18d70443abaa1e7d
|
|
| MD5 |
b016e3273d72605e927bbd01ecd9bf05
|
|
| BLAKE2b-256 |
2a6c69ec36ad6deb45df4987599a8a22766b1792180a87d81b64a7034849504f
|