Skip to main content

FastIngestor

License: MIT Rust Python Tests

High-throughput telemetry ingestion server with zero-copy Arrow FFI. Handles thousands of req/sec on a $5/month VPS. No Kafka. No Redis. No Elixir.


The Problem

Traditional Python backends struggle with high-volume telemetry:

  • FastAPI/Django: JSON parsing in Python is slow, GIL blocks concurrent CPU-bound work
  • Node.js: Single-threaded event loop blocks on CPU-bound tasks, GC pressure under load
  • Enterprise stacks: Kafka + Redis + workers = expensive infrastructure for small teams

Most teams end up with:

Client → FastAPI → Redis → Worker → PostgreSQL

         ↑              ↑
     (slow JSON)    (slow JSON)

FastIngestor collapses this into:

Client → Rust Server → Bounded Queue → Arrow FFI → Python (Polars) ↑ ↑ (fast serde_json) (zero-copy, no serialization)


Features

  • 🦀 Rust core: Tokio + Axum for high-performance HTTP
  • 🐍 Python bindings: PuyO3 for seamless integration with data tools
  • ⚡ Zero-copy FFI: Arrow C Data Interface to Polars/Pandas (no serialization overhead)
  • 🛡️ Built-in backpressure: Bounded queue + HTTP 503 when full (prevents OOM)
  • 🔒 Secure by default: Constant-time API key auth, body size limits, domain validation
  • 📦 Self-contained: No external services (Kafka, Redis, Elixir) required
  • 🎯 Clean architecture: Domain layer decoupled from infrastructure (easy to test and extend)

Quick Start

Installation

pip install fast-ingestor

Note: Pre-built wheels available for Linux, macOS, and Windows. Requires Python 3.9+.

Basic Usage

from fast_ingestor import FastIngestor

# Start the ingestion server on a background thread
ingestor = FastIngestor(
    api_key="your-secret-key",
    port=8080,
    capacity=100_000,   # Max buffered records before backpressure
    multi_tenant=False, # Set True to require tenant_id in payloads
)

# Server is now listening on http://0.0.0.0:8080
# Send data from any HTTP client:
#
#   curl -X POST http://localhost:8080/ingest \
#     -H "Content-Type: application/json" \
#     -H "X-API-Key: your-secret-key" \
#     -d '{"timestamp":1700000000000, "device_id":"s1", "metric_type":"temp", "value":23.7}'

# Drain buffered data as a Polars DataFrame (zero-copy via Arrow)
df = ingestor.drain_batch()
print(df)

Architecture

┌──────────────────────────────────────────────────────────────┐
│                      HTTP Request (JSON)                     │
└──────────────────────┬───────────────────────────────────────┘
                       ▼
┌──────────────────────────────────────────────────────────────┐
│  Axum HTTP Server (Rust + Tokio multi-threaded runtime)      │
│   • Body size limit (prevents DoS)                           │
│   • Constant-time API key auth (timing-attack resistant)     │
│   • Schema validation via serde                              │
└──────────────────────┬───────────────────────────────────────┘
                       ▼
┌──────────────────────────────────────────────────────────────┐
│  Domain Validation (pure Rust, zero I/O)                     │
│   • Timestamp range, device ID, metric type, value bounds    │
│   • Multi-tenant rules (optional tenant_id)                  │
│   • NaN and infinity rejection                               │
└──────────────────────┬───────────────────────────────────────┘
                       ▼
┌──────────────────────────────────────────────────────────────┐
│  Bounded Queue (Crossbeam channel)                           │
│   • Fixed capacity → predictable memory usage                │
│   • try_push is non-blocking                                 │
│   • Returns HTTP 503 when full (backpressure)                │
└──────────────────────┬───────────────────────────────────────┘
                       ▼
┌──────────────────────────────────────────────────────────────┐
│  Arrow FFI Export (zero-copy)                                │
│   • Vec<TelemetryRecord> → Arrow RecordBatch                 │
│   • PyCapsule interface → PyArrow → Polars DataFrame         │
│   • No serialization, no memory duplication                  │
└──────────────────────┬───────────────────────────────────────┘
                       ▼
┌──────────────────────────────────────────────────────────────┐
│  Python (Polars / Pandas / DuckDB / Parquet export)          │
└──────────────────────────────────────────────────────────────┘

Performance

Benchmarks were run on consumer hardware (AMD Ryzen 3 3200G, 4 cores / 4 threads, 16GB RAM, Windows 11) using a Rust-based client to eliminate the Python client bottleneck.

Throughput (Rust client, batch ingestion)

Workers Batch Size Records/sec Request Throughput
1 100 ~40,000 ~400 req/s
4 100 ~150,000 ~1,500 req/s
4 500 ~400,000 ~800 req/s

Note: Throughput scales linearly with CPU cores. On a cloud VPS with 4 vCPU you can expect ~200,000+ records/sec sustained.

Memory Usage

State Memory
Server idle ~25 MB
Server at capacity (100k records) ~120 MB
Client (Python, multiprocess) ~30 MB

Why Not Higher Numbers?

The server itself is not the bottleneck. A single Rust worker handles JSON parsing + validation + queueing in microseconds. The real-world throughput depends on:

  • Network latency (local loopback vs. internet)
  • Client throughput capability
  • Number of CPU cores available to Tokio

On a $20/month cloud VPS (4 vCPU, 8GB RAM), you can expect to sustain 100,000+ records/sec with zero backpressure.


Comparison

Metric FastIngestor FastAPI + Redis Node.js + Express
Setup Time 5 minutes 30+ minutes 20+ minutes
External Dependencies None Redis required Redis/Kafka typical
Memory (idle) ~25 MB ~200 MB ~150 MB
Memory (100k buffered) ~120 MB ~800 MB ~500 MB
Backpressure Built-in Manual Manual
Zero-copy to Python ✅ Arrow FFI ❌ JSON round-trip N/A
P99 Latency < 10 ms 40-100 ms 20-50 ms

Use Cases

1. IoT Telemetry Ingestion

Thousands of devices sending temperature, humidity, pressure, etc.

ingestor = FastIngestor(api_key="...", capacity=200_000)
while True:
    df = ingestor.drain_batch()
    if not df.is_empty():
        df.write_parquet(f"telemetry_{int(time.time())}.parquet")
    time.sleep(1)

2. FastAPI / Django Integration

Run alongside your existing app, no architecture changes needed.

from fastapi import FastAPI
from contextlib import asynccontextmanager
from fast_ingestor import FastIngestor

ingestor = None

@asynccontextmanager
async def lifespan(app):
    global ingestor
    ingestor = FastIngestor(api_key="...", port=8081)
    yield

app = FastAPI(lifespan=lifespan)

3. MVP Data Pipeline

Skip Redis/Kafka for your MVP. Upgrade later if needed.

# No Redis, no Kafka, no separate workers.
# Just ingest, drain, analyze.
df = ingestor.drain_batch()
insights = df.group_by("device_id").agg(pl.col("value").mean())

4. Edge Computing / Raspberry Pi

Runs on 1GB RAM devices. Perfect for gateways collecting sensor data.


Installation

pip install fast-ingestor

From source

git clone https://github.com/YOUR_USERNAME/fast-ingestor.git
cd fast-ingestor
pip install maturin
maturin develop --release

Requirements

  • Python 3.9+
  • Rust 1.75+ (only for building from source)
  • No external services required

Examples

See the examples/ directory for:


Configuration

FastIngestor(
    api_key: str,          # Required API key for authentication
    port: int = 8080,      # TCP port to listen on
    capacity: int = 100_000, # Max buffered records before 503
    multi_tenant: bool = False, # Require tenant_id in payloads
)

Sending Data

Single record

curl -X POST http://localhost:8080/ingest \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-secret-key" \
  -d '{
    "timestamp": 1700000000000,
    "device_id": "sensor-001",
    "metric_type": "temperature",
    "value": 23.7
  }'

Batch of records

curl -X POST http://localhost:8080/ingest \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-secret-key" \
  -d '[
    {"timestamp": 1700000000000, "device_id": "s1", "metric_type": "temp", "value": 23.7},
    {"timestamp": 1700000001000, "device_id": "s1", "metric_type": "temp", "value": 23.8}
  ]'

Responses

Status Meaning
202 Accepted Record(s) enqueued successfully
401 Unauthorized Missing or invalid API key
413 Payload Too Large Body exceeds 2MB limit
422 Unprocessable Entity Validation failed (bad timestamp, NaN value, etc.)
503 Service Unavailable Queue full (backpressure)

Testing

# Rust unit + integration tests (34 total)
cargo test

# Python integration tests
pip install -e .[dev]
pytest tests/

Benchmarks

Reproduce benchmarks locally:

# Start the server (terminal 1)
python examples/demo.py

# Run Rust benchmark (terminal 2)
cargo run --release --example throughput_bench

Contributing

Contributions welcome! Areas where help is especially appreciated:

  • Additional input formats (MsgPack, CBOR, Protobuf)
  • Prometheus metrics endpoint
  • Docker image
  • More integration examples (Django, Flask, gRPC)

Roadmap

  • MsgPack / CBOR input formats (via decoder trait)
  • Prometheus metrics endpoint (/metrics)
  • Batch export to Parquet/CSV
  • gRPC ingestion endpoint
  • Multi-tenant isolation improvements
  • Official Docker image

License

MIT. See LICENSE.


Why This Project?

Built to solve a real problem: teams spending $50+/month on Redis + workers just to buffer a few thousand req/sec of telemetry. FastIngestor proves that a single VPS with the right architecture can handle IoT-scale ingestion without external dependencies.

The Rust core handles what Rust is best at (I/O concurrency, fast parsing, memory safety). Python handles what Python is best at (data analysis with Polars/Pandas). Arrow FFI bridges them with zero overhead.

Qué hacer después

  1. Reemplaza YOUR_USERNAME en la sección de instalación con tu usuario real de GitHub
  2. Actualiza los números de benchmarks con los resultados reales que obtengas de cargo run --release --example throughput_bench
  3. Agrega badges reales cuando subas a GitHub (los de tests passing y build status requieren Actions)

Metadata

Release files for fast-ingestor 0.1.0

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

Built distributions (wheels)

Table of built distributions (wheels) for fast-ingestor 0.1.0
File
fast_ingestor-0.1.0-cp312-cp312-win_amd64.whl CPython 3.12 CPython 3.12 Windows x86-64 Details
fast_ingestor-0.1.0-cp312-cp312-manylinux_2_34_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.34+ x86-64 Details
fast_ingestor-0.1.0-cp312-cp312-macosx_11_0_arm64.whl CPython 3.12 CPython 3.12 macOS 11.0+ ARM64 Details
fast_ingestor-0.1.0-cp311-cp311-win_amd64.whl CPython 3.11 CPython 3.11 Windows x86-64 Details
fast_ingestor-0.1.0-cp311-cp311-manylinux_2_34_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.34+ x86-64 Details
fast_ingestor-0.1.0-cp311-cp311-macosx_11_0_arm64.whl CPython 3.11 CPython 3.11 macOS 11.0+ ARM64 Details
fast_ingestor-0.1.0-cp310-cp310-win_amd64.whl CPython 3.10 CPython 3.10 Windows x86-64 Details
fast_ingestor-0.1.0-cp310-cp310-manylinux_2_34_x86_64.whl CPython 3.10 CPython 3.10 Linux glibc 2.34+ x86-64 Details
fast_ingestor-0.1.0-cp310-cp310-macosx_11_0_arm64.whl CPython 3.10 CPython 3.10 macOS 11.0+ ARM64 Details
fast_ingestor-0.1.0-cp39-cp39-win_amd64.whl CPython 3.9 CPython 3.9 Windows x86-64 Details
fast_ingestor-0.1.0-cp39-cp39-manylinux_2_34_x86_64.whl CPython 3.9 CPython 3.9 Linux glibc 2.34+ x86-64 Details
fast_ingestor-0.1.0-cp39-cp39-macosx_11_0_arm64.whl CPython 3.9 CPython 3.9 macOS 11.0+ ARM64 Details

Total release size: 7.2 MB

Release files / fast_ingestor-0.1.0-cp312-cp312-win_amd64.whl

Download URL fast_ingestor-0.1.0-cp312-cp312-win_amd64.whl
Size 543.0 kB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
da333b0eee87c0d8a8553f1f44631a57fc16b3429d88f07b217bd94c9ffca18a
BLAKE2b-256 checksum
How to use checksums
2d0da52f85b432fe17258e73c57fbd883bedad58d36b084a801a82b49563a560
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / fast_ingestor-0.1.0-cp312-cp312-manylinux_2_34_x86_64.whl

Download URL fast_ingestor-0.1.0-cp312-cp312-manylinux_2_34_x86_64.whl
Size 673.8 kB
Tags CPython 3.12 Linux glibc 2.34+ x86-64
SHA-256 checksum
How to use checksums
ee51f0f6e2a614e3a47c9f63eeafdd89feb2b5161e5718dbeb5aac912f904ed6
BLAKE2b-256 checksum
How to use checksums
aa67c4827fc3ae1baa7003a6c9652c3dcb80d483ca96e2a3420fd40c184309af
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / fast_ingestor-0.1.0-cp312-cp312-macosx_11_0_arm64.whl

Download URL fast_ingestor-0.1.0-cp312-cp312-macosx_11_0_arm64.whl
Size 589.0 kB
Tags CPython 3.12 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
4359b877dd4ff78879bb51a67bc488ee21a930d27eeac354bb91539bb19745d2
BLAKE2b-256 checksum
How to use checksums
b47a18891b9591be7757144fc642653b98aae4bda1502127af83d56909a97095
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / fast_ingestor-0.1.0-cp311-cp311-win_amd64.whl

Download URL fast_ingestor-0.1.0-cp311-cp311-win_amd64.whl
Size 541.4 kB
Tags CPython 3.11 Windows x86-64
SHA-256 checksum
How to use checksums
abaa418f4498c5c095ebc92834b8b2c9243a7ddea82dfbfc18e20aac41fd9b44
BLAKE2b-256 checksum
How to use checksums
d09d8bb5c118ad81538c86033823dda15b18d9f7062b8fa044336978f6f7363a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / fast_ingestor-0.1.0-cp311-cp311-manylinux_2_34_x86_64.whl

Download URL fast_ingestor-0.1.0-cp311-cp311-manylinux_2_34_x86_64.whl
Size 672.0 kB
Tags CPython 3.11 Linux glibc 2.34+ x86-64
SHA-256 checksum
How to use checksums
11d22e29b6bf436c5e8e8858847bfef7a7861c3d3dd9317c021d48b292540ff6
BLAKE2b-256 checksum
How to use checksums
615d1a9265d7b41ae57553f1a97dcc0befa20d706ebe77284f70e47ead2198ad
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / fast_ingestor-0.1.0-cp311-cp311-macosx_11_0_arm64.whl

Download URL fast_ingestor-0.1.0-cp311-cp311-macosx_11_0_arm64.whl
Size 590.3 kB
Tags CPython 3.11 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
7981832dd5b975fde135ca22e9dfc810054130a68f60def970319d12d074057d
BLAKE2b-256 checksum
How to use checksums
3824a97da29b3628a47849cf212c7706b6519ef1bab0bdc8f0e5caef6d13baae
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / fast_ingestor-0.1.0-cp310-cp310-win_amd64.whl

Download URL fast_ingestor-0.1.0-cp310-cp310-win_amd64.whl
Size 541.6 kB
Tags CPython 3.10 Windows x86-64
SHA-256 checksum
How to use checksums
f437411ee68806be43ef4c339eb784354c571316958b35238eb1e86fcfd2a5d5
BLAKE2b-256 checksum
How to use checksums
d29d088a1cf337137a6ab8cd22110d4252ac28dfb950bf578c3ceee294232af7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / fast_ingestor-0.1.0-cp310-cp310-manylinux_2_34_x86_64.whl

Download URL fast_ingestor-0.1.0-cp310-cp310-manylinux_2_34_x86_64.whl
Size 672.3 kB
Tags CPython 3.10 Linux glibc 2.34+ x86-64
SHA-256 checksum
How to use checksums
37ed8d349be08ee0eafdfd0912e317d1e0b5f25c3cbe8ef3841bf3596b661298
BLAKE2b-256 checksum
How to use checksums
027045eae09fe396bde6fde1a29cac570e2deb63a50fb49a3adf721b6b990c34
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / fast_ingestor-0.1.0-cp310-cp310-macosx_11_0_arm64.whl

Download URL fast_ingestor-0.1.0-cp310-cp310-macosx_11_0_arm64.whl
Size 590.1 kB
Tags CPython 3.10 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
88492ed68e64e17359208a4157bab70424d71f01ebbc3313f1023ccf6b4a9fe5
BLAKE2b-256 checksum
How to use checksums
52db0d12a06e647e1f7caf97f807c8d32ec976b96fd5ba723aa6c61623b1439b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / fast_ingestor-0.1.0-cp39-cp39-win_amd64.whl

Download URL fast_ingestor-0.1.0-cp39-cp39-win_amd64.whl
Size 542.5 kB
Tags CPython 3.9 Windows x86-64
SHA-256 checksum
How to use checksums
09a72c0582cb334c83a3a0e8a92f859115bbc18187c78e33f8125d1f3df6dc1f
BLAKE2b-256 checksum
How to use checksums
52ace84a5228035b9a18168528a91d193b0a7a901c210a05d805f1730749d242
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / fast_ingestor-0.1.0-cp39-cp39-manylinux_2_34_x86_64.whl

Download URL fast_ingestor-0.1.0-cp39-cp39-manylinux_2_34_x86_64.whl
Size 673.4 kB
Tags CPython 3.9 Linux glibc 2.34+ x86-64
SHA-256 checksum
How to use checksums
6f3e0fc812936a453ca2710c4cc54eead11779129781df3ca73619ab34d46888
BLAKE2b-256 checksum
How to use checksums
575135cd885c36908b1f7691aa8fc5918c50b0abbe459c697730417c3562c9cd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / fast_ingestor-0.1.0-cp39-cp39-macosx_11_0_arm64.whl

Download URL fast_ingestor-0.1.0-cp39-cp39-macosx_11_0_arm64.whl
Size 591.2 kB
Tags CPython 3.9 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
742c6b65ab8199bcc938796961d2d9dc830cd3271ecd6fd698a18c635625c52b
BLAKE2b-256 checksum
How to use checksums
ceab6dde770c90f4fc682dc0798cf1ad9818c3af10fb7304001d99e5bdb61165
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release history Release notifications | RSS feed

0.1.1

12 release files

This release

0.1.0 This release

12 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