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.1

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.1
File
fast_ingestor-0.1.1-cp312-cp312-win_amd64.whl CPython 3.12 CPython 3.12 Windows x86-64 Details
fast_ingestor-0.1.1-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.1-cp312-cp312-macosx_11_0_arm64.whl CPython 3.12 CPython 3.12 macOS 11.0+ ARM64 Details
fast_ingestor-0.1.1-cp311-cp311-win_amd64.whl CPython 3.11 CPython 3.11 Windows x86-64 Details
fast_ingestor-0.1.1-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.1-cp311-cp311-macosx_11_0_arm64.whl CPython 3.11 CPython 3.11 macOS 11.0+ ARM64 Details
fast_ingestor-0.1.1-cp310-cp310-win_amd64.whl CPython 3.10 CPython 3.10 Windows x86-64 Details
fast_ingestor-0.1.1-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.1-cp310-cp310-macosx_11_0_arm64.whl CPython 3.10 CPython 3.10 macOS 11.0+ ARM64 Details
fast_ingestor-0.1.1-cp39-cp39-win_amd64.whl CPython 3.9 CPython 3.9 Windows x86-64 Details
fast_ingestor-0.1.1-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.1-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.1-cp312-cp312-win_amd64.whl

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

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

Download URL fast_ingestor-0.1.1-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
21786b3d5ec7673b90a2cf78c067a2324451efea086ed43b50567e71b7ccd658
BLAKE2b-256 checksum
How to use checksums
c68ad25efb9dbff8148823224069c8a66b0731704c63cae1c4ad88de1e357749
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

Download URL fast_ingestor-0.1.1-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
005a322c5ddc977b34c392d43bae94fb9e28111f43d71b49fbbe9204e7895780
BLAKE2b-256 checksum
How to use checksums
c01c78717ec931be283ba69795f11303992c73473851ff2a13e7cfa277d6be8b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

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

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

Download URL fast_ingestor-0.1.1-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
698c6c5a4ac85e3b6f0047b99f21f5b91e7826c57df5c01c575ce26b2bae8d9e
BLAKE2b-256 checksum
How to use checksums
b34e6a32a10e2a5b651080f9b035ac58d9bc30da2747a7a6136e6e4be0523a98
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

Download URL fast_ingestor-0.1.1-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
c39972c9f15a5bdb8af3a9a8a95e1b022a8e6053e0ca506f0526bdd24428bfcb
BLAKE2b-256 checksum
How to use checksums
c79219a8ef9e58cbe24711722e800723113f8552824f52ca1e8b418930d7c104
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

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

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

Download URL fast_ingestor-0.1.1-cp310-cp310-manylinux_2_34_x86_64.whl
Size 672.2 kB
Tags CPython 3.10 Linux glibc 2.34+ x86-64
SHA-256 checksum
How to use checksums
ea206d7a67e6fdeee88929036ff3cd5044081d41b18ba7c6e66a90bd74c08de1
BLAKE2b-256 checksum
How to use checksums
22277fb76978bbda589838821f103461624d7b5519ae48e238354f0fd5e198f0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

Download URL fast_ingestor-0.1.1-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
bd92b8667ddf6aca86a1fd7900fb7524e81e31cbd2b6a863c48afeda125c456f
BLAKE2b-256 checksum
How to use checksums
5197f5a5ff622482d22e6ae09cdb6b5dc4f1ad04442c580f47ef3677f8949fec
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

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

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

Download URL fast_ingestor-0.1.1-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
6fa78974d867b7dd6ca4b87b5f17f55eeff59c463c0eb8759ba73e627b403579
BLAKE2b-256 checksum
How to use checksums
eb51b55405020630d40fc002083bb08bf6133a29c3cfa466204ef238314d6c87
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

Download URL fast_ingestor-0.1.1-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
745b1c7c24699437b4839209c2ed39a116f0fd78bbee6400ba98797cebd7f3dd
BLAKE2b-256 checksum
How to use checksums
bde4de837ed55f7dfc1861aa641b290d2784cf77e3ec1a08d249e05d5f3fce76
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release history Release notifications | RSS feed

This release

0.1.1 This release

12 release files

0.1.0

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