Ingestion Pipeline
The ingestion pipeline receives telemetry over QUIC via the nerve_ingester crate.
Each frame passes through a six-stage pipeline before reaching the event bus. Backpressure
is enforced at the transport layer using a token-bucket algorithm.
Pipeline Stages
Text
QUIC Stream
│
▼
ProtocolAdapter::decode() ← trait: pluggable per wire format
│
▼
Validate ← schema check, required fields, range bounds
│
▼
DedupeFilter ← bloom + LRU, keyed on (entity_id, ts, hash)
│
▼
Router ← domain-based fan-out to partition writers
│
▼
Partitioner ← assigns ClickHouse partition key
│
▼
WalWriter ← fsync WAL segment, then ack upstream
│
▼
EventBus ← broadcast to subscribers (GPU, agents, MV) QUIC Listener
- Crate:
nerve_ingester - Transport: QUIC (quinn) with TLS 1.3, 0-RTT enabled
- Bidirectional: Commands flow back to SDKs over the same QUIC bidi stream
- Concurrency: One tokio task per accepted stream
Protocol Adapter Trait
Rust
pub trait ProtocolAdapter: Send + Sync {
fn decode(&self, raw: &[u8]) -> Result<TelemetryFrame>;
fn encode_command(&self, cmd: &Command) -> Result<Vec<u8>>;
} Backpressure
- Token bucket: Per-source rate limit (default 10k frames/sec)
- WAL pressure: If WAL segment exceeds 256 MB, new streams are paused
- Poison pill queue: Frames that fail validation 3 times are routed to a dead-letter queue for manual inspection
Deduplication
DedupeFilter uses a two-layer strategy: a counting Bloom filter
for fast rejection (0.1% false-positive rate) backed by an LRU cache of recent
(entity_id, ts, payload_hash) tuples. Duplicates are silently
dropped and counted in the ingestion metrics.
Questions?
Reach out for help with integration, deployment, or custom domain codecs.