gorp
Gorp is a Raft [1] implementation built in Go. It includes all the essential features of a good Raft implementation: replication, config changes, status tracking, and more. A blog post going into detail about the development and more personal motivations can be found here.
Previously this project contained an interface for uploading files, serving as a local file store for my family. Now this project is focused on just being an implementation of Raft. The latest release with the interface can be found here, and a demo of it has been posted to YouTube.

Running gorp
Quickstart
Start a local cluster by running cd build && docker compose up. This starts three instances hosted on localhost:4234, localhost:4235, and localhost:4236.
Setting up your own cluster
Define your cluster
Copy config.local.json to config.json. This will be the master config list that each replica starts with to read its own attributes and to know where the other members are, edit accordingly.
Start an instance
Copy the built gorp binary and the master config.json to your target machine. Run gorp with the following command to specify its config and which replica in the config the machine is:
gorp -config=config.json -id=<which replica this machine should be>.
Use it
Query any machine in the cluster at its user/http endpoints.
API endpoints
POST /api
Submit a new log entry (write, update, delete) to the cluster.
Request body:
{
"type": "data",
"message": {
"path": "<path to file on server>",
"blob": "<binary data>",
"operation": "<write | update | delete>"
}
}
Response (200):
{
"hash": "abc123...",
"timestamp": "2024-01-01T00:00:00.000000000Z"
}
GET /status?hash=<hash>
Poll for the status of a previously submitted log entry.
Response (200):
{ "status": "<success|pending|failed>", "hash": "abc123..." }
GET /file?path=<path>
Read a file from the committed state machine.
Response (200): <binary data>
Response (404): "File not found."
GET /files
List all files in the data directory.
Response (200):
["docs/hello.txt", "docs/world.txt"]
Implemented features
- Message appending - follower replicas need to be able to add new
messages to the end of their log when the appropriate conditions are met
(message term is valid, log is up-to-date, the previous message of both
replicas match).
- Leadership consensus - if a system is disturbed in some way, like a
network partition or leader crash, then the system needs to recover in a
timely way. This is done through an election.
- Log replication - the follower logs needs to heal themselves to be
up-to-date from the leader's logs. This is done through an inductive process.
- Config changes - special messages can be passed that define updated
network configurations. The new set of hosts in the configuration will be
transitioned to while perserving the protocol invariants.
- Status tracking - Raft sacrificies availability over consistency and
partionability; this means that a message's status needs to be tracked by the
user for success, in this project's case using unique hashes
Roadmap
- Architecture overhaul - the current implementation uses a state machine pattern with separate definitions for each candidate, follower, and leader state. Actor-based architectures are more naturally expressed in Go and would allow for the removal of a decent amount of escape-hatching code that allows the state machine pattern to work here.
- Enhanced observability - logs are currently piped to standard output. This solution works on small scales, but as the cluster grows, traces, logs, and metrics would better be analyzed through OTel-based obversation.
References
[1] In Search of an Understandable Consensus Algorithm (Extended
Version), Diego Ongaro and John Ousterhout