Raft3D is a distributed, fault-tolerant 3D printer management system built on the Raft consensus algorithm. It allows for the management of 3D printers, filaments, and print jobs with strong consistency guarantees across multiple nodes.
- distributed consensus: uses the Raft algorithm to maintain consistency across nodes
- fault tolerance: continues to operate even when nodes fail
- automatic leader election: elects a new leader when the current leader fails
- persistent storage: uses BoltDB for durable storage of the system state
- comprehensive logging: logs are stored in files with configurable verbosity
- health monitoring: automatically detects and removes unresponsive nodes
- restful API: simple HTTP API for managing printers, filaments, and print jobs
- Go 1.21 or higher
- tmux (for the automated testing scripts)
- jq (for JSON formatting in the testing scripts)
On Ubuntu/Debian:
sudo apt install tmux jqYou can run Raft3D either manually from the terminal or using the provided scripts for automated setup and testing.
The first node needs to bootstrap the cluster:
go run main.go -id node1 -http :8080 -raft 127.0.0.1:7000 -data ./data -bootstrap -console-level info -file-level debug -logs ./logsThis creates a new Raft cluster with a single node and starts the HTTP API server on port 8080.
Once the bootstrap node is running, you can add additional nodes:
# Second node
go run main.go -id node2 -http :8081 -raft 127.0.0.1:7001 -data ./data -join 127.0.0.1:8080 -console-level info -file-level debug -logs ./logs
# Third node
go run main.go -id node3 -http :8082 -raft 127.0.0.1:7002 -data ./data -join 127.0.0.1:8080 -console-level info -file-level debug -logs ./logsThe -join parameter specifies the HTTP address of any existing node in the cluster.
Once the cluster is running, you can interact with it using HTTP requests:
# Check cluster status
curl http://localhost:8080/cluster/status | jq
# Add a printer
curl -X POST -H "Content-Type: application/json" -d '{"id":"printer1","company":"Prusa","model":"MK3S+"}' http://localhost:8080/api/v1/printers
# Add a filament
curl -X POST -H "Content-Type: application/json" -d '{"id":"filament1","type":"PLA","color":"Red","total_weight_in_grams":1000,"remaining_weight_in_grams":1000}' http://localhost:8080/api/v1/filaments
# Add a print job
curl -X POST -H "Content-Type: application/json" -d '{"id":"job1","printer_id":"printer1","filament_id":"filament1","filepath":"/models/benchy.gcode","print_weight_in_grams":15}' http://localhost:8080/api/v1/print_jobs
# Update a print job status
curl -X POST "http://localhost:8080/api/v1/print_jobs/job1/status?status=Running"Raft3D includes scripts to automate the setup and testing process:
./reset_data.shThis script:
- Stops any running Raft nodes
- Removes existing data and log directories
- Ensures file system syncs to prevent data corruption
- Creates fresh empty directories
./run_raft_cluster.shThis script:
- Runs reset_data.sh to clean up existing data
- Creates a tmux session with 4 panes for Raft nodes and 1 for commands
- Starts a bootstrap node (node1)
- Starts 3 follower nodes with automatic joining
- Provides a command pane with example test commands
The resulting tmux session will look like:
initial config. monitor nodes on the left and run stuff on the right
+-----------------+-------------------------------+
| Node 1 | |
| (Bootstrap) | |
+-----------------+ |
| Node 2 | |
| (Follower) | test cmds |
+-----------------+ (your window) |
| Node 3 | (to run cmds) |
| (Follower) | run ./test_scenarios.sh |
+-----------------+ |
| Node 4 | |
| (Follower) | |
+-----------------+-------------------------------+
./test_scenarios.shThis script:
- Checks that the tmux session is running
- Verifies cluster health and leader election
- Offers an interactive menu of tests:
- Basic Workflow Test (add printer, filament, job, update status)
- Node Failure and Recovery Test
- Leader Failure and Election Test
- Run All Tests
- Executes the selected tests and reports results
When in the tmux session:
- To detach (leave the session running):
Ctrl+B, then D - To reattach to a running session:
tmux attach-session -t raft3d - To kill the session:
tmux kill-session -t raft3d - To scroll in a pane:
Ctrl+B, then [(use arrow keys to scroll, pressqto exit scroll mode)
The system provides a RESTful API for managing printers, filaments, and print jobs.
- GET /api/v1/printers - List all printers
- POST /api/v1/printers - Add a new printer
- GET /api/v1/filaments - List all filaments
- POST /api/v1/filaments - Add a new filament
- GET /api/v1/print_jobs - List all print jobs
- POST /api/v1/print_jobs - Add a new print job
- POST /api/v1/print_jobs/{id}/status?status={status} - Update a print job status
- GET /cluster/status - Get cluster status
- POST /join - Join a node to the cluster
- DELETE /cluster/servers?id={nodeId} - Remove a node from the cluster
Raft3D follows a layered architecture:
- API Layer: Handles HTTP requests and routes them to the store
- Store Layer: Implements the business logic and interacts with the Raft node
- Raft Layer: Manages consensus and replication across nodes
- Storage Layer: Uses BoltDB for durable storage
The system uses the Hashicorp Raft implementation for consensus, which ensures:
- Leader Election
- Log Replication
- Safety (never returning incorrect results)
go run main.go [options]
-id string # Node ID (required)
-http string # HTTP service address (default ":8080")
-raft string # Raft transport address (default "127.0.0.1:7000")
-data string # Data directory (default "data")
-logs string # Log directory (default "logs")
-join string # Join address(es) (comma-separated)
-bootstrap # Bootstrap the cluster
-clean # Clean data directory before starting
-console-level string # Console log level (debug, info, warn, error)
-file-level string # File log level (debug, info, warn, error)To manually remove a server from the cluster:
curl -X DELETE "http://localhost:8080/cluster/servers?id=node3"To check the current leader:
curl http://localhost:8080/cluster/status | jq