Fetch
The fetch vertical is Rafka's consumer-side Kafka op. A standard Kafka client sends a FetchRequest to the gateway on TCP :9092. The gateway decodes it, forwards a FetchOp to the broker over the iroh mesh, the broker reads records from the WAL, and the gateway returns a FetchResponse — all standard Kafka wire.
The fetch flow
Kafka client ──TCP :9092──▶ gateway (kafka_ingress.rs)
ApiVersions negotiation
Metadata request → self-advertise (gateway is the single broker)
ListOffsets (optional) → earliest/latest offset from WAL bitset
FetchRequest decode → FetchOp (postcard-encoded)
→ kafka_op_call(broker_peer, KAFKA_OP_FETCH, org_id, payload)
▼ iroh QUIC bi-stream
broker (run_bi_reader dispatch → handle_fetch)
→ wal_store().fetch_virtual(vt_key, fetch_offset, max_bytes)
◀ FetchOpResp { records, high_watermark, error_code }
→ gateway re-encodes records into a RecordBatch
→ gateway encodes FetchResponse ──────────────────▶ client
Every step emits an OTLP span. The fetch trace chain is:
gateway.kafka.connect → gateway.kafka.request → rafka.gateway.kafka.fetch → rafka.broker.fetch.read
FetchOp wire types
FetchOp and FetchOpResp are postcard-encoded and live in crates/rafka-mesh-ops:
FetchOp { topic, partition, fetch_offset, max_bytes }— what to fetch.FetchOpResp { records: Vec<Vec<u8>>, high_watermark, error_code }— the raw record values and the topic's high-watermark offset.
The op code is KAFKA_OP_FETCH = 0x03.
How records are read from the WAL
The broker's handle_fetch handler:
- Builds the virtual-topic key:
"{org_id}-{topic_hash_decimal}-{partition}". Thetopic_hashis a Blake3 org-salted u128 truncation of(org_id, topic_name). - Reads the high-watermark as
virtual_index.bitsets[vt_key].len(). - Fetches records one-by-one starting at
fetch_offsetviawal.fetch_virtual(vt_key, offset, max_bytes), stopping when the next record isNone(past HWM) or themax_bytesbudget is exhausted. - Wraps the raw
Vec<Vec<u8>>in a KafkaRecordBatchbefore returning.
Span attributes:
virtual_topic— the vt_key stringfetch_offset— the starting offset requestedreturned_count— number of records returnedhigh_watermark— total record count for the topic/partition
Offsets and the high-watermark
fetch_offset = 0returns from the beginning of the log.high_watermarkequals the total number of records produced to the (topic, partition) pair. A fetch fromfetch_offset >= high_watermarkreturns an empty record set.- The WAL's virtual topic index is a
RoaringTreemapbitset; virtual offsets are zero-indexed positions in the bitset.
ListOffsets integration
Before fetching, clients typically send a ListOffsetsRequest to discover the earliest or latest offset:
timestamp value | Meaning | Resolved offset |
|---|---|---|
-2 | Earliest | 0 (WAL always starts at 0) |
-1 | Latest | high_watermark (bitset len) |
>= 0 | By timestamp | high_watermark (approximate; exact timestamp indexing not yet implemented) |
Span name: rafka.broker.list_offsets.read.
Metadata and self-advertisement
When kcat or librdkafka opens a connection it first sends a MetadataRequest. Rafka's gateway responds as the single broker (node_id=0, pointing at itself). Every requested topic gets a 1-partition entry (partition 0, leader 0) regardless of whether any records have been produced. Topics spring into existence on first produce — there is no explicit topic-creation step in P1.
Supported Kafka API versions
| API Key | Name | Version range |
|---|---|---|
| 18 | ApiVersions | v0–v3 |
| 3 | Metadata | v0–v5 |
| 2 | ListOffsets | v1–v5 |
| 1 | Fetch | v0–v11 |
Version caps are set below each API's flexible-encoding threshold so the response header remains v0 (no tagged fields) in all supported version ranges.
Current limitations
- Single-tenant —
org_idis hardcoded to1. Multi-tenancy arrives in Phase 2. - Timestamp-exact ListOffsets (
timestamp >= 0) returnshigh_watermarkas an approximation; a full time index is a later phase item. - Consumer-group coordination (
JoinGroup/SyncGroup/OffsetCommit) is not yet implemented (Phase 3).
Related pages
- Quickstart: Produce → Fetch — try the full loop
- Concepts: Produce — the produce vertical
- Concepts: WAL Durability — the storage engine
- Kafka API & Wire Compatibility — full version reference