{"id":15470476,"url":"https://github.com/alfetahe/elector","last_synced_at":"2025-07-26T04:06:51.124Z","repository":{"id":65551034,"uuid":"566220265","full_name":"alfetahe/elector","owner":"alfetahe","description":"Elects master node from Erlang/Elixir cluster that is agreed by all nodes.","archived":false,"fork":false,"pushed_at":"2023-07-28T10:18:33.000Z","size":168,"stargazers_count":17,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-29T11:16:44.516Z","etag":null,"topics":["clustering","distributed-systems","elections","elixir","erlang","erlang-otp"],"latest_commit_sha":null,"homepage":"","language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alfetahe.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-11-15T08:05:52.000Z","updated_at":"2025-01-04T17:58:34.000Z","dependencies_parsed_at":"2025-03-03T16:47:16.342Z","dependency_job_id":null,"html_url":"https://github.com/alfetahe/elector","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/alfetahe/elector","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alfetahe%2Felector","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alfetahe%2Felector/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alfetahe%2Felector/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alfetahe%2Felector/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alfetahe","download_url":"https://codeload.github.com/alfetahe/elector/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alfetahe%2Felector/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267116325,"owners_count":24038623,"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-07-26T02:00:08.937Z","response_time":62,"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":["clustering","distributed-systems","elections","elixir","erlang","erlang-otp"],"created_at":"2024-10-02T02:04:55.386Z","updated_at":"2025-07-26T04:06:51.100Z","avatar_url":"https://github.com/alfetahe.png","language":"Erlang","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Elector\n\n![example workflow](https://github.com/alfetahe/elector/actions/workflows/erlang.yml/badge.svg)\n\n## Description\nElector is an Erlang application that automatically detects all nodes inside the distributed Erlang cluster and chooses the leader node.\nThe elections are started automatically when the Elector application is started or when a node joins or leaves the cluster.\nElector also allows you to run pre- and post-election hooks that will be triggered when the election process is started and finished.\n\nThe default election strategy is to choose the node with the highest uptime.\n\n## Features\n- Automatic election process on startup or when node joins/leaves the cluster\n- Ability to configure pre and post election hooks that will be called before and after the election process. \u003cstrong\u003eThese hooks must return within 1 second to avoid timeouts\u003c/strong\u003e.\n- Provides 4 built in election strategies(time based) and allows you to define your own strategy implementation (See `elector_strategy_behaviour` module for reference`)\n- Provides quorum option to detect split brain scenarios\n- Provides option to define the election delay in milliseconds before the election process is started automatically and queue the\nelection calls\n\n## Configuration\nElector supports the following configurations:\n- `election_delay` - The delay in milliseconds before the new election starts. This value is used automatic election is triggered either by node join/leave or startup. Default value is 1 second(1000).\n- `strategy_module` - The module that is used for the election strategy\nimplementation. Available options are: `elector_rt_high_strategy` and `elector_rt_low_strategy`. Feel free to write your own strategy module that implements the `elector_strategy_behaviour` module. Default value is `elector_rt_high_strategy` which chooses the node with the highest runtime.\n- `pre_election_hooks` - A list of hooks/function calls that will be triggered exactly before the node is starting the election. Expects\na list of tuples with the following format: `{Module, Function, Args}`. Default value is `[]`.\n`post_election_hooks` - A list of hooks/function calls that will be triggered exactly after the election process. Expects\na list of tuples with the following format: `{Module, Function, Args}`. Default value is `[]`.\n- `quorum_size` - The number of nodes(including the local node) that should be available in the cluster before the election process is started. Do not set it to `0` as it will disable the election process, leave empty or `1` if you want to run the election process even there are no other nodes in the cluster. Default value is `1`. \n- `candidate_node` - Boolean indicating if this node should be a candidate for the leader election. Default value is `true`.\n- `hooks_execution` - Atom indicating if the pre and post election hooks should be executed on the node starting the election process or on all nodes. The election process will be started automatically by the global commission process. The node who starts the commission process is not known and can be any node in the cluster. \nAvailable values are: `local` and `global`.\nDefault value is `global`.\n- `automatic_elections` - Boolean indicating if the automatic election process should be started when node joins or leaves the cluster. Default value is `true`.\n\nKeep in mind to use the same configuration for all nodes in the cluster!\n\n## Guides\n\n### Installation for Elixir application\n- Add `{:elector, \"~\u003e 0.3.0\"}` under the deps in the `mix.exs` file: \n```elixir\ndefp deps do\n    [\n        {:elector, \"~\u003e 0.3.0\"}\n    ]\nend\n```\n- Add `elector` under the extra_applications in the `mix.exs` file:\n```elixir\ndef application do\n    [\n        extra_applications: [:elector],\n        mod: {MyApp, []}\n    ]\nend\n```\n\n### Installation for Erlang application\n- Add `elector` to the deps in the `rebar.config` file: `{deps, [{\"elector\", \"0.3.0\"}]}.`.\n- Add `elector` to the `applications` list in the `myapp.app.src` file: `{applications, [elector]}.`\n\n## Examples\n\n### Start election manually\n\n#### Elixir\n```elixir\n\u003e alias :elector, as Elector\n\u003e Elector.elect_sync() # Start election synchronously\n{:ok, :election_finished}\n\u003e Elector.elect() # Start election asynchronously\n{:ok, :election_started}\n```\n#### Erlang\n```erlang\n\u003e elector:elect_sync(). % Start election synchronously\n{ok, election_finished}\n\u003e elector:elect(). % Start election asynchronously\n{ok, election_started}\n```\n\n### Get current leader\n\n#### Elixir\n```elixir\n\u003e alias :elector, as Elector\n\u003e Elector.get_leader()\n{:ok, :example_node}\n```\n\n#### Erlang\n```erlang\n\u003e elector:get_leader().\n{ok, example_node}\n```\n\nSee the `elector` module for more.\n\nhttps://hexdocs.pm/elector/\n\n\n## High level overview\nElector is a distributed application that utilizes the Erlang global module to spawn a singleton process named\n`elector_commission`. The commission process is responsible for starting the election process and keeping track of the nodes in the cluster.\nThe election process is started by the commission process, which calls the `elect/1` function from the strategy module.\nThis function gathers the necessary information from the cluster and decides which node should become the leader.\n\nEach node spawns the following local processes:\n- `elector_overviewer` process is responsible for starting the commission and monitor it across the cluster.\n- `elector_candidate` process holding the candidate information that describes if the node is a candidate for the leader election.\n- `elector_state` process holding the selected leader information.\n\nAll processes are supervised by the `elector_sup` supervisor.\n\n\n## Setup Elector locally\n\n### Setup the elector locally and run the application:\n- `docker-compose up -d`\n- `docker exec -it elector_elector_1 sh`\n- `rebar3 compile`\n- `erl -sname local -setcookie cookievalue -pa ./_build/default/lib/elector/ebin -eval \"application:start(elector)\"`\n\n### Run tests:\n- `rebar3 compile \u0026\u0026 ct_run -dir test -logdir test_logs -pa ./_build/default/lib/elector/ebin -setcookie cookievalue`\n\n### Generate documentation:\n- `rebar3 edoc`","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falfetahe%2Felector","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falfetahe%2Felector","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falfetahe%2Felector/lists"}