{"id":40407735,"url":"https://github.com/danrl/skinny","last_synced_at":"2026-01-20T14:02:56.286Z","repository":{"id":57554182,"uuid":"160562084","full_name":"danrl/skinny","owner":"danrl","description":"The Skinny Distributed Lock Service","archived":false,"fork":false,"pushed_at":"2020-05-23T16:14:56.000Z","size":716,"stargazers_count":94,"open_issues_count":0,"forks_count":15,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-06-20T10:17:07.231Z","etag":null,"topics":["consensus","consensus-algorithm","consensus-protocol","distributed-lock","site-reliability-engineering","sre"],"latest_commit_sha":null,"homepage":"https://danrl.com","language":"Go","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/danrl.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":"2018-12-05T18:37:20.000Z","updated_at":"2024-05-22T08:51:27.000Z","dependencies_parsed_at":"2022-09-26T18:51:12.244Z","dependency_job_id":null,"html_url":"https://github.com/danrl/skinny","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/danrl/skinny","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danrl%2Fskinny","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danrl%2Fskinny/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danrl%2Fskinny/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danrl%2Fskinny/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danrl","download_url":"https://codeload.github.com/danrl/skinny/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danrl%2Fskinny/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28604712,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T12:01:53.233Z","status":"ssl_error","status_checked_at":"2026-01-20T12:01:46.545Z","response_time":117,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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","consensus-algorithm","consensus-protocol","distributed-lock","site-reliability-engineering","sre"],"created_at":"2026-01-20T14:02:54.433Z","updated_at":"2026-01-20T14:02:56.274Z","avatar_url":"https://github.com/danrl.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# The Skinny Distributed Lock Service\n\n![Build](https://github.com/danrl/skinny/workflows/Build/badge.svg)\n[![codecov](https://codecov.io/gh/danrl/skinny/branch/master/graph/badge.svg?token=u9RZS2ts8s)](https://codecov.io/gh/danrl/skinny)\n[![Go Report Card](https://goreportcard.com/badge/github.com/danrl/skinny)](https://goreportcard.com/report/github.com/danrl/skinny)\n[![GoDoc](https://godoc.org/github.com/danrl/skinny?status.svg)](https://godoc.org/github.com/danrl/skinny)\n[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)\n\n![Giraffe](doc/img/giraffe-small.png)\n\n\n## Welcome\n\nThis is the Skinny distributed lock service. It is feature-free and uses a Paxos-like protocol for reaching distributed\nconsensus. The purpose of this software is to educate its author and interested folks on the broader topic of\ndistributed systems, reliability, and particularly distributed consensus. The naming was totally not inspired by\nGoogle's wonderful [Chubby lock service for loosely-coupled distributed systems](https://static.googleusercontent.com/media/research.google.com/en//archive/chubby-osdi06.pdf). Or was it?\n\n**Note:** *This is a hobby project of mine. I wanted to learn about distributed consensus and subsequently spread\nthe knowledge within the Site Reliability Engineering community. This software shall under no circumstances be run in a\nproduction environment. Furthermore, it shall not be trusted in any way. This code is shared for educational purposes\nonly. Have fun, tinker, learn!*\n\n\n## Building\n\n* Install build dependencies first\n  * Skinny uses the [Mage](https://magefile.org/) build tool. Therefore it needs the `mage` command to be installed.\n  * Skinny uses [Protocol Buffers](https://developers.google.com/protocol-buffers/) and [gRPC](https://grpc.io/).\n  It requires the `protoc` compiler with the *go* and *grpc* output plugins installed.\n  * Some build dependencies can be installed by running `mage builddeps`.\n* Download code dependencies by running `mage deps` or `go mod vendor`.\n* Build the `skinnyctl` client tool and the `skinnyd` server binaries by running `mage build`.\n  You can find the final artifacts in the `./bin/` directory.\n\nSkinny comes with few code dependencies. \n\n\n## The Daemon (skinnyd)\n\nA Skinny instance is started by running `skinnyd`, preferably with the `--config` option.\n\n    ./bin/skinnyd --config doc/examples/skinnyd/london.yml\n\nThe Skinny instance will add the peers it finds in the configuration file to the quorum.\nFor each instance in the quorum, a separate `skinnyd` process is started.\nInstances are expected to be able to reach out to each other via HTTP/2.\nTo run multiple instances locally, it is advised to assign each instance its own port and listen on `localhost`.\n\nA typical Skinny configuration file for a Skinny instance in a quorum of five looks like this:\n\n~~~yaml\n---\nname: london\nincrement: 1\ntimeout: 500ms\nlisten: 0.0.0.0:9000\npeers:\n- name: oregon\n  address: oregon.skinny.cakelie.net:9000\n- name: spaulo\n  address: spaulo.skinny.cakelie.net:9000\n- name: sydney\n  address: sydney.skinny.cakelie.net:9000\n- name: taiwan\n  address: taiwan.skinny.cakelie.net:9000\n~~~\n\nAll options are required.\n\n| Option            | Description |\n| ----------------- | ----------- |\n| **Name**          | The name of the Skinny instance. Should be unique within the quorum to avoid confusion. |\n| **Increment**     | The number by which the instance increases the round number (ID). Must be unique within the quorum to prevent dueling proposers. |\n| **Timeout**       | The timeout for Remote Procedure Calls (RPCs) made to other Skinny instances in the quorum. |\n| **Listen**        | The listening address of the Skinny instance. Other instances can connect to this address for RPCs. |\n| **Peers**         | The complete list of the *other* instances of the quorum. Should contain an even number of peers. |\n| **Peers/Name**    | The name of a peer instance. |\n| **Peers/Address** | The address under which a peer instance's RPCs are exposed. |\n\n\nThere must be one configuration file for each Skinny instance in the quorum.\nExample configuration files are available in the [`doc/examples`](doc/examples) directory.\n\n\n## The Client Tool (skinnyctl)\n\nA quorum of Skinny instances is controlled via `skinnyctl`.\n\nThe tool implements two APIs:\n\n* The rather simple *control* API. Used for fetching the current status of a quorum.\n* The barely more complex *lock* API. This one acquires and releases *locks* on behalf of a *holder*.\n\nTo be able to work with a quorum of instances `skinnyctl` needs to know about it. The quorum's connection information is\nusually stored in a `quorum.yml` configuration file.\n\n~~~yaml\n---\ntimeout: 5s\ninstances:\n- name: london\n  address: london.skinny.cakelie.net:9000\n- name: oregon\n  address: oregon.skinny.cakelie.net:9000\n- name: spaulo\n  address: spaulo.skinny.cakelie.net:9000\n- name: sydney\n  address: sydney.skinny.cakelie.net:9000\n- name: taiwan\n  address: taiwan.skinny.cakelie.net:9000\n~~~\n\nAll options are required.\n\n| Option                | Description |\n| --------------------- | ----------- |\n| **Timeout**           | The timeout for Remote Procedure Calls (RPCs) made to the Skinny instances in the quorum. |\n| **Instances**         | The complete list of all instances of the quorum. |\n| **Instances/Name**    | The name of an instance. |\n| **Instances/Address** | The address under which an instance's RPCs are exposed. |\n\n\n## Acquiring and Releasing a Lock\n\n**Note:** Locks are always advisory. There is neither a dead-lock detection nor are locks enforced. The holder of a lock is\nresponsible for releasing the lock after leaving the critical section of an application.\n\nTo acquire a lock in behalf of a holder named *Beaver* simply run:\n\n    $ ./bin/skinnyctl acquire \"Beaver\"\n    📡 connecting to london (london.skinny.cakelie.net:9000)\n    🔒 acquiring lock\n    ✅ success\n\nOnce *Beaver* is done accessing the protected resource the lock should be released so that other potential holders can\nacquire it.\n\n\n    $ ./bin/skinnyctl release\n    📡 connecting to london (london.skinny.cakelie.net:9000)\n    🔓 releasing lock\n    ✅ success\n\n\n### Monitoring Quorum State\n\nA quorum's state can be fetched by issuing a request for status information to every instance in the quorum.\n\n    $ ./bin/skinnyctl status\n    NAME     INCREMENT   PROMISED   ID   HOLDER   LAST SEEN\n    london   1           1          1    beaver   now\n    oregon   2           1          1    beaver   now\n    spaulo   3           1          1    beaver   now\n    sydney   4           1          1    beaver   now\n    taiwan   5           1          1    beaver   now\n\nTo continously monitor a quorum's state use the `--watch` option.\n\n    $ ./bin/skinnyctl status --watch\n\n![](doc/img/skinnyctl-status-watch.gif)\n\n\n## Bonus: Lab Infrastructure via Terraform\n\nTerraform definitions and a *skinny_instance* module are available in the [`doc/terraform`](doc/terraform) directory.\nChange the `variables.tf` to your needs and initialize and deploy the environment via:\n\n    $ terraform init\n    $ terraform apply\n\nIt takes a couple of minutes to fire up all the resources. Be patient.\n\n\n## Bonus: Lab Software Deployment via Ansible\n\nAnsible playbooks for deploying a Skinny quorum are available in the [`doc/ansible`](doc/ansible) directory.\nAdjust the hostnames in the `inventory.yml` file and run the playbook:\n\n    $ ansible-playbook -i inventory.yml site.yml\n\nIt takes a while to fetch the source code and build the binaries on each instance.\nWhile you wait, how's the weather today? Well, well...\n\n\n## Sources and Acknowledgements\n\n* [*Reaching Agreement in the Presence of Faults*](https://lamport.azurewebsites.net/pubs/reaching.pdf), M. Pease, R, Shostak, and L. Lamport\n* [*Paxos Made Simple*](https://lamport.azurewebsites.net/pubs/paxos-simple.pdf), L. Lamport\n* [*Paxos Agreement - Computerphile*](https://youtu.be/s8JqcZtvnsM), Heidi Howard\n  (University of Cambridge Computer Laboratory)\n* [*The Paxos Algorithm*](https://youtu.be/d7nAGI_NZPk), Luis Quesada Torres (Google Site Reliability Engineering)\n* Giraffe and beaver graphics by OpenClipart contributor\n  [Lemmling](https://openclipart.org/user-detail/lemmling)\n* Alien graphic by OpenClipart contributor [Anarres](https://openclipart.org/user-detail/anarres)\n* A related talk exists which's slides were improved thanks to helpful comments from John Reese, Ben Appleton, and Peter Júnoš.\n\n\n## License\n\nCopyright 2018 Dan Lüdtke \u003cmail@danrl.com\u003e\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanrl%2Fskinny","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanrl%2Fskinny","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanrl%2Fskinny/lists"}