raft_rx is a Raft consensus implementation built on top of
rxnet, with parallel C and Python
implementations.
The project provides:
- a Raft core modeled as
rxnetfinite state machines, - leader election, heartbeats, log replication, commit, and recovery,
- persistent term, vote, log, snapshot, and membership configuration,
- stable and joint-consensus cluster membership changes,
- pluggable transports,
- a replicated key-value example,
- standalone multi-process demo applications in C and Python.
The C and Python implementations are intentionally not ABI-compatible. They share the same protocol model, public concepts, and observable behavior while using idioms appropriate for each language.
| Path | Purpose |
|---|---|
c/ |
C library, tests, and TCP demo application |
python/ |
Python package, tests, shell, and HTTP demo application |
docs/ |
Requirements, design notes, tasks, and user guides |
rxnet/ |
Expected sibling checkout of greenlsi/rxnet |
- C user guide: C integration, storage, transports, event loops, membership changes, and the C demo application.
- Python user guide: Python integration, simulation clusters, shell, observability, HTTP demo application, and API reference.
- Requirements
- Design
- Tasks
PDF versions are generated under docs/ by the documentation Makefile.
make -C docsThe repository expects rxnet to be
checked out next to it:
parent/
├── raft_rx/
└── rxnet/
For Python workflows, use uv. For C workflows, use a C99 compiler and
make.
Run the full project test suite from the repository root:
make testThat command runs the Python tests and then the C tests.
Run the Python library tests:
uv run --project python --extra dev pytest -qBuild the Python package:
uv build pythonBuild the C library, trace variant, and tests:
make -C cRun the C tests:
make -C c testBuild only the standard C library artifact:
make -C c build/libraft_rx.aBuild the trace-enabled variant:
make -C c build/libraft_rx_trace.aAll size constants (RAFT_MAX_NODES, RAFT_MAX_QUEUE, RAFT_MAX_BATCH, …)
use #ifndef guards and can be overridden via compiler -D flags without
touching any source file. The defaults are sized for desktop / server use
(≈ 42 MB per raft_cluster_t). For embedded targets such as ESP32, pass
small values at build time:
make -C c CPPFLAGS="-DRAFT_MAX_NODES=3 -DRAFT_MAX_QUEUE=8 -DRAFT_MAX_BATCH=4 \
-DRAFT_MAX_LOG=32 -DRAFT_MAX_KEY=32 -DRAFT_MAX_VALUE=64"This reduces raft_cluster_t to ≈ 104 KB. See section 13 of the C user
guide for the full table and ESP32
CMake snippet.
The standalone demos run one Raft node per process and demonstrate how the core library can be embedded in an application with networking, a local CLI, persistence, and dynamic membership.
The Python demo lives in python/examples/demo_app. It uses HTTP as the Raft
transport and exposes both an interactive CLI and REST endpoints. Each node ID
is its advertised HOST:PORT.
Build/package the demo:
uv build python/examples/demo_appRun its tests:
uv run --project python/examples/demo_app --extra dev pytest -qStart a first node:
uv run --project python/examples/demo_app raft-rx-demo --bind 127.0.0.1:7400Start additional nodes in separate terminals:
uv run --project python/examples/demo_app raft-rx-demo \
--join 127.0.0.1:7400 \
--bind 127.0.0.1:7401
uv run --project python/examples/demo_app raft-rx-demo \
--join 127.0.0.1:7400 \
--bind 127.0.0.1:7402Useful CLI commands inside a node are status, members, log [LIMIT],
set KEY VALUE, get KEY, delete KEY, addnode HOST:PORT,
rmnode HOST:PORT, join HOST:PORT, merge HOST:PORT, stop, start, and
quit.
The C demo lives in c/examples/demo_app. It uses the pluggable TCP transport,
a replicated key-value state machine, and a local CLI running in the same
rxnet runtime as the Raft node.
Build the demo:
make -C c/examples/demo_appStart a fresh 3-node cluster in three terminals:
./c/examples/demo_app/build/raft_node --id n1 --port 5001 \
--member n1 --member n2 --member n3 \
--peer n2=127.0.0.1:5002 --peer n3=127.0.0.1:5003./c/examples/demo_app/build/raft_node --id n2 --port 5002 \
--member n1 --member n2 --member n3 \
--peer n1=127.0.0.1:5001 --peer n3=127.0.0.1:5003./c/examples/demo_app/build/raft_node --id n3 --port 5003 \
--member n1 --member n2 --member n3 \
--peer n1=127.0.0.1:5001 --peer n2=127.0.0.1:5002Add a fourth node from another terminal:
./c/examples/demo_app/build/raft_node --id n4 --port 5004 --join 127.0.0.1:5001Useful CLI commands inside a node are status, leader, members, log,
set KEY VALUE, get KEY, delete KEY, addnode ID, rmnode ID, leave,
join HOST:PORT, merge HOST:PORT, stop, start, and quit.
After the first run, node state is stored under var/raft/<id>/. A node can be
restarted with only its ID:
./c/examples/demo_app/build/raft_node --id n1This project is distributed under the GNU General Public License v3.0 or later. See LICENSE for the full text.