{"id":19488599,"url":"https://github.com/petrglad/compost","last_synced_at":"2026-02-11T13:02:55.006Z","repository":{"id":57713881,"uuid":"70436279","full_name":"PetrGlad/compost","owner":"PetrGlad","description":"Manage lifecycle of stateful components","archived":false,"fork":false,"pushed_at":"2023-11-07T19:41:05.000Z","size":47,"stargazers_count":17,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-05T07:22:21.830Z","etag":null,"topics":["clojure","components","lifecycle","stateful"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PetrGlad.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,"zenodo":null}},"created_at":"2016-10-09T23:22:46.000Z","updated_at":"2025-02-20T23:43:18.000Z","dependencies_parsed_at":"2023-11-07T23:16:59.217Z","dependency_job_id":"2f4037df-f2cc-46f4-958d-af5c726dfccc","html_url":"https://github.com/PetrGlad/compost","commit_stats":{"total_commits":40,"total_committers":2,"mean_commits":20.0,"dds":0.07499999999999996,"last_synced_commit":"7ac8843c132ad03c115f447614f221aae0220367"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/PetrGlad/compost","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PetrGlad%2Fcompost","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PetrGlad%2Fcompost/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PetrGlad%2Fcompost/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PetrGlad%2Fcompost/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PetrGlad","download_url":"https://codeload.github.com/PetrGlad/compost/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PetrGlad%2Fcompost/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29333155,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-11T12:42:24.625Z","status":"ssl_error","status_checked_at":"2026-02-11T12:41:23.344Z","response_time":97,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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":["clojure","components","lifecycle","stateful"],"created_at":"2024-11-10T21:04:09.326Z","updated_at":"2026-02-11T13:02:54.987Z","avatar_url":"https://github.com/PetrGlad.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Compost\n\nLibrary that manages lifecycle of stateful components. \nThis is a variation of https://github.com/stuartsierra/component project's idea.\nAt the moment this library does not support ClojureScript.\n\n## Usage\n\nAdd this dependency to your project\n```\n  [net.readmarks/compost \"0.2.0\"]\n```\n\nSee tests for examples. Component declaration has form\n```clojure\n   {:requires #{:required-component-id-1 :required-component-id-2}}\n    :this initial-state\n    :get (fn [this] ...) ;; Returns value of this component that other components will get as dependency. \n    :start (fn [this dependency-components-map] ...) ;; Acquire resources (open connections, start threads ...)\n    :stop (fn [this] ...)} ;; Release resources.\n```\nAll fields are optional, defaults are:\n```clojure\n   {:requires #{}\n    :this nil\n    :get identity \n    :start (fn [this dependency-components-map] this)\n    :stop identity}\n```\n`:start` and `:stop` functions should return new value of component's `:this`.\nIf component acquires resources in `:start` it must release them in `:stop`. \nSystem declaration is a plain map\n```clojure\n  {:component-1-id component-1-declaration\n   :component-2-id component-2-declaration\n   ...\n  }\n```\n\nLifecycle usage example\n```clojure\n (require '[net.readmarks.compost :as compost])\n (let [s (compost/start system-map #{:web-component :some-worker-component})]\n   (Thread/sleep 5000)\n   (compost/stop s))\n```\n\nYou can salvage current system state after exception as follows:\n```clojure\n (try\n   (compost/start system-map)\n   (catch ExceptionInfo ex\n     (if-let [sys (compost/ex-system ex)]\n       (compost/stop sys) ;;; Handle this system as desired here.\n       (throw ex))))\n```\n\n### Error handling helpers\n\nThis feature is implemented by net.readmarks.compost.keeper namespace.\nThis namespace is considered experimental, it's contents might change in any version.\n\nThe agent (\"keeper\") holds current state of system along with lifecycle's exceptions.\nThe usage example:\n\n```clojure\n (require '[net.readmarks.compost :as compost])\n (require '[net.readmarks.compost.keeper :as keeper])\n\n (def sys (keeper/keeper system-map))\n\n (keeper/update-keeper! sys compost/start)\n ;; Now sys holds current system value and errors if there are any.\n ;; (:system @sys) is current system map value.\n ;; (:errors @sys) is list of of system lifecycle errors. It is empty if system changes were successful.\n\n ;; You can send these errors into a log, for example:\n (keeper/flush-errors! sys println) ;; The function gets errors one by one.\n```\n\n### Using com.stuartsierra.component components\n\nYou can adapt existing components as follows:\n\n```clojure\n(defn component-using [init using]\n  {:requires (set using)\n   :this init\n   :start (fn [this deps]\n            (-\u003e (merge this deps)\n                component/start)\n   :stop component/stop})\n \n(def system \n  {:conn-source (component-using\n                   (-\u003eMyConnPool)\n                   [])\n   :dao (component-using\n          (map-\u003eMyDbComponent {})\n          [:conn-source])}\n```\n\nNote that unlike com.stuartsierra.component sequence of `n.r.compost/stop` might differ from reverse startup one.\nOnly explicitly declared dependencies are respected. If you need to account for implicit dependencies \nyou should add additional elements to components' `:require` collections.\n\n## Motivation\n\nI like what [component](https://github.com/stuartsierra/component) provides but I also want\n* Use any value as component. E.g. often I want a function closure to be a component. \n  Or, alternatively, a component be visible as a function. Besides this, I do not like the idea of\n  always keeping dependency reference even though it might be needed only in start function. \n* Do not require a new type for each component. Implementing `Lifecycle`\n  gets in the way when you only need an ad hoc component. Also requirement for component \n  to be a map and implement LifeCycle effectively restricts component to be a record. \n  This also means that sometimes people resort to work-arounds to avoid creating new types.\n* Use plain Clojure data structures to configure system. I think that putting configuration into metadata\n  was a mistake. Instead of streamlining it actually complicates code. System configuration is also data \n  that one might want to inspect or modify. Give it equal rights :)\n* Be compatible with com.stuartsierra.component/Lifecycle components. \n  There are already lots of such components and this is a good thing. \n  This part should require only small amount of glue code.\n\n## License \n\nCopyright © Petr Gladkikh \u003cPetrGlad@gmail.com\u003e\n\nDistributed under the Eclipse Public License either version 1.0 or (at\nyour option) any later version.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpetrglad%2Fcompost","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpetrglad%2Fcompost","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpetrglad%2Fcompost/lists"}