{"id":13550149,"url":"https://github.com/andreev-io/little-raft","last_synced_at":"2025-09-06T00:58:24.710Z","repository":{"id":44966158,"uuid":"359383434","full_name":"andreev-io/little-raft","owner":"andreev-io","description":"The lightest distributed consensus library. Run your own replicated state machine! ❤️","archived":false,"fork":false,"pushed_at":"2025-03-31T10:17:26.000Z","size":249,"stargazers_count":446,"open_issues_count":5,"forks_count":25,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-09-01T15:46:02.877Z","etag":null,"topics":["consensus","distributed-systems","raft","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andreev-io.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-04-19T08:25:25.000Z","updated_at":"2025-08-02T07:46:40.000Z","dependencies_parsed_at":"2022-08-12T11:40:36.484Z","dependency_job_id":null,"html_url":"https://github.com/andreev-io/little-raft","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/andreev-io/little-raft","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreev-io%2Flittle-raft","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreev-io%2Flittle-raft/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreev-io%2Flittle-raft/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreev-io%2Flittle-raft/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andreev-io","download_url":"https://codeload.github.com/andreev-io/little-raft/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreev-io%2Flittle-raft/sbom","scorecard":{"id":192575,"data":{"date":"2025-08-11","repo":{"name":"github.com/andreev-io/little-raft","commit":"15371d5a3a0ce19572d5a5a647a936eb190cac06"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.9,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/greetings.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/andreev-io/little-raft/greetings.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/rust.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/andreev-io/little-raft/rust.yml/master?enable=pin","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Code-Review","score":5,"reason":"Found 9/16 approved changesets -- score normalized to 5","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/greetings.yml:1","Warn: no topLevel permission defined: .github/workflows/rust.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":6,"reason":"4 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: RUSTSEC-2020-0159","Warn: Project is vulnerable to: RUSTSEC-2021-0093 / GHSA-pqqp-xmhj-wgcw","Warn: Project is vulnerable to: RUSTSEC-2022-0041 / GHSA-qc84-gqf4-9926","Warn: Project is vulnerable to: RUSTSEC-2020-0071 / GHSA-wcg3-cvx6-7396"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-16T21:05:55.633Z","repository_id":44966158,"created_at":"2025-08-16T21:05:55.633Z","updated_at":"2025-08-16T21:05:55.633Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273842834,"owners_count":25177921,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-05T02:00:09.113Z","response_time":402,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["consensus","distributed-systems","raft","rust"],"created_at":"2024-08-01T12:01:29.506Z","updated_at":"2025-09-06T00:58:24.685Z","avatar_url":"https://github.com/andreev-io.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"# Little Raft\nThe lightest distributed consensus library. Run your own replicated state machine! :heart:\n\n## Installing\nSimply import the crate. In your `Cargo.toml`, add\n```\n[dependencies]\nlittle_raft = \"0.2.0\"\n```\n\n## Using\nTo start running Little Raft, you only need to do three things.\n1. Implement the StateMachine that you want your cluster to maintain. Little Raft will take care of replicating this machine across the cluster and achieving consensus on its state.\n```rust\n/// StateMachine describes a user-defined state machine that is replicated\n/// across the cluster. Raft can Replica whatever distributed state machine can\n/// implement this trait.\npub trait StateMachine\u003cT\u003e\nwhere\n    T: StateMachineTransition,\n{\n    /// This is a hook that the local Replica will call each time the state of a\n    /// particular transition changes. It is up to the user what to do with that\n    /// information.\n    fn register_transition_state(\u0026mut self, transition_id: T::TransitionID, state: TransitionState);\n\n    /// When a particular transition is ready to be applied, the Replica will\n    /// call apply_transition to apply said transition to the local state\n    /// machine.\n    fn apply_transition(\u0026mut self, transition: T);\n\n    /// This function is used to receive transitions from the user that need to\n    /// be applied to the replicated state machine. Note that while all Replicas\n    /// poll get_pending_transitions periodically, only the Leader Replica\n    /// actually processes them. All other Replicas discard pending transitions.\n    /// get_pending_transitions must not return the same transition twice.\n    fn get_pending_transitions(\u0026mut self) -\u003e Vec\u003cT\u003e;\n}\n```\n\n2. Implement the Cluster abstraction so that the local Replica can communicate with other nodes.\n```rust\n/// Cluster is used for the local Raft Replica to communicate with the rest of\n/// the Raft cluster. It is up to the user how to abstract that communication.\n/// The Cluster trait also contains hooks which the Replica will use to inform\n/// the crate user of state changes.\npub trait Cluster\u003cT\u003e\nwhere\n    T: StateMachineTransition,\n{\n    /// This function is used to deliver messages to target Replicas. The\n    /// Replica will provide the to_id of the other Replica it's trying to send\n    /// its message to and provide the message itself. The send_message\n    /// implementation must not block but is allowed silently fail -- Raft\n    /// exists to achieve consensus in spite of failures, after all.\n    fn send_message(\u0026mut self, to_id: usize, message: Message\u003cT\u003e);\n\n    /// This function is used by the Replica to receive pending messages from\n    /// the cluster. The receive_messages implementation must not block and must\n    /// not return the same message more than once.\n    fn receive_messages(\u0026mut self) -\u003e Vec\u003cMessage\u003cT\u003e\u003e;\n\n    /// By returning true from halt you can signal to the Replica that it should\n    /// stop running.\n    fn halt(\u0026self) -\u003e bool;\n\n    /// This function is a hook that the Replica uses to inform the user of the\n    /// Leader change. The leader_id is an Option\u003cusize\u003e because the Leader\n    /// might be unknown for a period of time. Remember that only Leaders can\n    /// process transitions submitted by the Raft users, so the leader_id can be\n    /// used to redirect the requests from non-Leader nodes to the Leader node.\n    fn register_leader(\u0026mut self, leader_id: Option\u003cReplicaID\u003e);\n}\n```\n3. Start your replica!\n```rust\n    /// Create a new Replica.\n    ///\n    /// id is the ID of this Replica within the cluster.\n    ///\n    /// peer_ids is a vector of IDs of all other Replicas in the cluster.\n    ///\n    /// cluster represents the abstraction the Replica uses to talk with other\n    /// Replicas.\n    ///\n    /// state_machine is the state machine that Raft maintains.\n    ///\n    /// noop_transition is a transition that can be applied to the state machine\n    /// multiple times with no effect.\n    ///\n    /// heartbeat_timeout defines how often the Leader Replica sends out\n    /// heartbeat messages.\n    ///\n    /// election_timeout_range defines the election timeout interval. If the\n    /// Replica gets no messages from the Leader before the timeout, it\n    /// initiates an election.\n    ///\n    /// In practice, pick election_timeout_range to be 2-3x the value of\n    /// heartbeat_timeout, depending on your particular use-case network latency\n    /// and responsiveness needs. An election_timeout_range / heartbeat_timeout\n    /// ratio that's too low might cause unwarranted re-elections in the\n    /// cluster.\n    pub fn new(\n        id: ReplicaID,\n        peer_ids: Vec\u003cReplicaID\u003e,\n        cluster: Arc\u003cMutex\u003cC\u003e\u003e,\n        state_machine: Arc\u003cMutex\u003cS\u003e\u003e,\n        noop_transition: T,\n        heartbeat_timeout: Duration,\n        election_timeout_range: (Duration, Duration),\n    ) -\u003e Replica\u003cS, T, C\u003e;\n\n    /// This function starts the Replica and blocks forever.\n    ///\n    /// recv_msg is a channel on which the user must notify the Replica whenever\n    /// new messages from the Cluster are available. The Replica will not poll\n    /// for messages from the Cluster unless notified through recv_msg.\n    ///\n    /// recv_transition is a channel on which the user must notify the Replica\n    /// whenever new transitions to be processed for the StateMachine are\n    /// available. The Replica will not poll for pending transitions for the\n    /// StateMachine unless notified through recv_transition.\n    pub fn start(\u0026mut self, recv_msg: Receiver\u003c()\u003e, recv_transition: Receiver\u003c()\u003e);\n```\n\n\nWith that, you're good to go. We are working on examples, but for now you can look at the `little_raft/tests` directory and at the documentation at [https://docs.rs/little_raft/0.1.3/little_raft/](https://docs.rs/little_raft/0.1.3/little_raft/). We're working on adding more tests.\n\n\n## Testing\nRun `cargo test`.\n\n## Contributing\nContributions are very welcome! Do remember that one of the goals of this library is to be as small and simple as possible. Let's keep the code in `little_raft/src` **under 1,000 lines**. PRs breaking this rule will be declined.\n```bash\n\u003e cloc little_raft/src\n       6 text files.\n       6 unique files.                              \n       0 files ignored.\n\ngithub.com/AlDanial/cloc v 1.90  T=0.02 s (369.2 files/s, 56185.0 lines/s)\n-------------------------------------------------------------------------------\nLanguage                     files          blank        comment           code\n-------------------------------------------------------------------------------\nRust                             6             82            199            632\n-------------------------------------------------------------------------------\nSUM:                             6             82            199            632\n-------------------------------------------------------------------------------\n```\n\nYou are welcome to pick up and work on any of the issues open for this project. Or you can submit new issues if anything comes up from your experience using this library.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandreev-io%2Flittle-raft","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandreev-io%2Flittle-raft","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandreev-io%2Flittle-raft/lists"}