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