{"id":13686561,"url":"https://github.com/liebke/avout","last_synced_at":"2026-02-19T09:01:44.492Z","repository":{"id":57713190,"uuid":"2640442","full_name":"liebke/avout","owner":"liebke","description":"Avout: Distributed State in Clojure","archived":false,"fork":false,"pushed_at":"2019-08-29T01:18:25.000Z","size":6621,"stargazers_count":423,"open_issues_count":8,"forks_count":29,"subscribers_count":18,"default_branch":"master","last_synced_at":"2025-04-22T18:12:42.401Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/liebke.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2011-10-25T01:14:06.000Z","updated_at":"2024-12-18T11:48:55.000Z","dependencies_parsed_at":"2022-09-06T02:10:48.894Z","dependency_job_id":null,"html_url":"https://github.com/liebke/avout","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liebke%2Favout","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liebke%2Favout/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liebke%2Favout/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liebke%2Favout/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/liebke","download_url":"https://codeload.github.com/liebke/avout/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251852818,"owners_count":21654473,"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","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":[],"created_at":"2024-08-02T15:00:35.060Z","updated_at":"2025-10-22T02:44:06.376Z","avatar_url":"https://github.com/liebke.png","language":"Clojure","readme":"\u003ca href=\"http://avout.io\"\u003e\u003cimg width=\"550\" src=\"http://avout.io/images/avout-logo.png\" /\u003e\u003c/a\u003e\n\n\n\u003ca name=\"about-avout\" /\u003e\n## About Avout\n\n\u003cp\u003e\u003ca href=\"http://avout.io\"\u003eAvout\u003c/a\u003e brings Clojure's in-memory model of \u003ca href=\"http://clojure.org/state\"\u003estate\u003c/a\u003e to distributed application development by providing a distributed implementation of Clojure's \u003ca href=\"http://en.wikipedia.org/wiki/Multiversion_concurrency_control\"\u003eMultiversion Concurrency Control\u003c/a\u003e (MVCC) \u003ca href=\"http://en.wikipedia.org/wiki/Software_transactional_memory\"\u003eSTM\u003c/a\u003e along with distributable, durable, and extendable versions of Clojure's \u003ca href=\"http://clojure.org/atoms\"\u003eAtom\u003c/a\u003e and \u003ca href=\"http://clojure.org/refs\"\u003eRef\u003c/a\u003e concurrency primitives.\u003c/p\u003e\n\n\u003cp\u003eAvout enables techniques that require synchronous, coordinated (i.e. transactional) management of distributed state (see also \u003ca href=\"http://java.sun.com/developer/technicalArticles/tools/JavaSpaces/\"\u003eJavaSpaces\u003c/a\u003e), complementing approaches that focus on asynchronous, uncoordinated communication between distributed components, e.g. message queues (\u003ca href=\"http://www.zeromq.org/\"\u003e0MQ\u003c/a\u003e, \u003ca href=\"http://www.rabbitmq.com/\"\u003eRabbitMQ\u003c/a\u003e, \u003ca href=\"http://www.jboss.org/hornetq\"\u003eHornetQ\u003c/a\u003e), event-driven approaches (\u003ca href=\"http://www.jboss.org/netty\"\u003eNetty\u003c/a\u003e, \u003ca href=\"https://github.com/ztellman/aleph\"\u003eAleph\u003c/a\u003e), and actors (\u003ca href=\"http://www.erlang.org/\"\u003eErlang\u003c/a\u003e, \u003ca href=\"http://akka.io\"\u003eAkka\u003c/a\u003e).\u003c/p\u003e\n\n\u003cp\u003eMuch has been written [\u003ca href=\"#references\"\u003e1\u003c/a\u003e, \u003ca href=\"#references\"\u003e2\u003c/a\u003e, \u003ca href=\"#references\"\u003e3\u003c/a\u003e] on functional programming and the advantages of designing programs that emphasize pure functions and immutable values, and that minimize or eliminate, wherever possible, mutable state. Of course, it's not always possible to completely eliminate the need for mutable state, and that's where Clojure's precise \u003ca href=\"http://clojure.org/state\"\u003emodel of time, identity, and state\u003c/a\u003e becomes powerful.\u003c/p\u003e\n\n\u003cp\u003eLikewise, when designing distributed applications, it is desirable to create components that are loosely coupled and that communicate with each other asynchronously, but this too is also not always possible. There are times when you need coordinated access to state across systems in a distributed application, and this is where Avout comes in.\u003c/p\u003e\n\n\u003cp\u003e\u003cem\u003eAvout\u003c/em\u003e uses \u003ca href=\"http://zookeeper.apache.org\"\u003eZooKeeper\u003c/a\u003e and \u003ca href=\"https://github.com/liebke/zookeeper-clj\"\u003ezookeeper-clj\u003c/a\u003e to coordinate state change, and also includes distributed implementations of \u003ca href=\"http://download.oracle.com/javase/1,5,0/docs/api/java/util/concurrent/locks/Lock.html\"\u003e\u003cem\u003ejava.util.concurrent.lock.Lock\u003c/em\u003e\u003c/a\u003e and \u003ca href=\"http://download.oracle.com/javase/1,5,0/docs/api/java/util/concurrent/locks/ReadWriteLock.html\"\u003e\u003cem\u003ejava.util.concurrent.lock.ReadWriteLock\u003c/em\u003e\u003c/a\u003e.\u003c/p\u003e\n\n\u003ch3\u003eUsing Avout\u003c/h3\u003e\n\n\u003cp\u003eTo get started, you'll need to \u003ca href=\"http://avout.io/index.html#running-zookeeper\"\u003erun ZooKeeper\u003c/a\u003e, and include Avout as a dependency by adding the following to your project.clj file:\u003c/p\u003e\n\n```clojure\n[avout \"0.5.3\"]\n```\n\n\u003cp\u003eBelow is the Avout equivalent of *Hello World*.\u003c/p\u003e\n\n```clojure\n(use 'avout.core)\n(def client (connect \"127.0.0.1\"))\n\n(def r0 (zk-ref client \"/r0\" 0))\n(def r1 (zk-ref client \"/r1\" []))\n\n(dosync!! client\n  (alter!! r0 inc)\n  (alter!! r1 conj @r0))\n```\n\n\u003cp\u003eStart by creating a ZooKeeper client with the \u003cstrong\u003econnect\u003c/strong\u003e function, then create two ZooKeeper-backed distributed Refs using the \u003cstrong\u003ezk-ref\u003c/strong\u003e function. Finally, perform a \u003cstrong\u003edosync!!\u003c/strong\u003e transaction that updates both Refs with \u003cstrong\u003ealter!!\u003c/strong\u003e. Using Avout isn't much different than using Clojure's in-memory Atoms and Refs.\u003c/p\u003e\n\n\u003cp\u003e\u003cem\u003eAvout\u003c/em\u003e Atoms and Refs implement Clojure's IRef interface, and therefore support functions that operate on IRefs, including: deref (and its reader-macro, @), set-validator!, add-watch, and remove-watch.\u003c/p\u003e\n\n\u003cp\u003e\u003cem\u003eAvout\u003c/em\u003e also provides \u003cstrong\u003e\"double-bang\"\u003c/strong\u003e versions of the remaining core Atom and Ref functions (\u003ca href=\"http://clojuredocs.org/clojure_core/clojure.core/reset!\"\u003ereset!\u003c/a\u003e, \u003ca href=\"http://clojuredocs.org/clojure_core/clojure.core/swap!\"\u003eswap!\u003c/a\u003e, \u003ca href=\"http://clojuredocs.org/clojure_core/clojure.core/dosync\"\u003edosync\u003c/a\u003e, \u003ca href=\"http://clojuredocs.org/clojure_core/clojure.core/ref-set\"\u003eref-set\u003c/a\u003e, \u003ca href=\"http://clojuredocs.org/clojure_core/clojure.core/alter\"\u003ealter\u003c/a\u003e, \u003ca href=\"http://clojuredocs.org/clojure_core/clojure.core/commute\"\u003ecommute\u003c/a\u003e) for use with distributed Atoms and Refs, \u003cstrong\u003ereset!!, swap!!, dosync!!, ref-set!!, alter!!, commute!!\u003c/strong\u003e.\u003c/p\u003e\n\n\u003cp\u003e\u003cem\u003eNote: Avout Refs cannot participate in in-memory dosync transactions, but Avout's **local-ref** provides the equivalent of an in-memory Ref that can participate in dosync!! transactions with distributed Refs.\u003c/em\u003e\u003c/p\u003e\n\n\u003ch3\u003eExtending Avout\u003c/h3\u003e\n\n\u003cp\u003eTwo types of Atoms, zk-atom and mongo-atom, and three types of Refs, zk-ref, mongo-ref, and local-ref have been implemented, and Avout can be extended with additional types of Atoms and Refs that use different containers for their state, durable or not, including (No)SQL databases, (distributed) filesystems, in-memory data structures, and RESTful webservices. The types of values supported by each depends on both the backend store and the method of serialization used, and transactions containing different types of Avout Refs are supported.\u003c/p\u003e\n\n\u003cp\u003eNew types of Atoms can be created by implementing the \u003cstrong\u003eavout.state.StateContainer\u003c/strong\u003e protocol,\u003c/p\u003e\n\n```clojure\n(defprotocol StateContainer\n  (initStateContainer [this])\n  (destroyStateContainer [this])\n  (getState [this])\n  (setState [this value]))\n```\n\n\u003cp\u003eand new Ref types can be created by implementing \u003cstrong\u003eavout.state.VersionedStateContainer\u003c/strong\u003e.\u003c/p\u003e\n\n```clojure\n(defprotocol VersionedStateContainer\n  (initVersionedStateContainer [this])\n  (destroyVersionedStateContainer [this])\n  (getStateAt [this version])\n  (setStateAt [this value version])\n  (deleteStateAt [this version]))\n```\n\n\u003ch3\u003eMore on Avout\u003c/h3\u003e\n\u003cp\u003eTo learn more about Avout and distributed-state in Clojure, visit \u003ca href=\"http://avout.io\"\u003eavout.io\u003c/a\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://avout.io/#background\"\u003eBackground\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://avout.io/#tutorial\"\u003eGetting Started\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://github.com/liebke/avout\"\u003eSource Code\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ca name=\"contributing\" /\u003e\n\u003ch3\u003eContributing\u003c/h3\u003e\n\nAlthough Avout is not part of Clojure-Contrib, it follows the same guidelines for contributing, which includes signing a \u003ca href=\"http://clojure.org/contributing\"\u003eClojure Contributor Agreement\u003c/a\u003e (CA) before contributions can be accepted.\n\n\n\u003ch3\u003eLicense\u003c/h3\u003e\n\nAvout is distributed under the Eclipse Public License, the same as Clojure.\n\n\u003ch3\u003eCopyright\u003c/h3\u003e\n\nAvout is Copyright © 2011 David Liebke and Relevance, Inc\n\n\n","funding_links":[],"categories":["Clojure","\u003ca name=\"Clojure\"\u003e\u003c/a\u003eClojure"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliebke%2Favout","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fliebke%2Favout","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliebke%2Favout/lists"}