This library is based on stoic. It differs in that it doesn't inject configuration into components of a system-map, or "bounce" components on configuration change as the original intended. Instead it will retrieve config for system initialisation, and watch for any updates, which will be updated in (and availabe from) the config-supplier at runtime.
This readme assumes the reader is familiar with Stuart Sierra's Componets
The library will pull configuration from a file or Zookeeper source, and can be used as follows:
The project contains both File and Zookeeper (Curator) config suppliers:
stoic.config.file/config-supplierstoic.config.curator/config-supplier
Provide the path as an argument to the above; file-location in the case of stoic.config.file/config-supplier, root znode in the case of stoic.config.curator/config-supplier, to create the desired config-supplier component.
Alternatively, use stoic.config.supplier/make-config-supplier. The function takes 2 args:
config-supplier-type, which must be either:fileor:zkpath- path to file, or zk root, depending on the value ofconfig-supplier-type
Calling stoic.bootstrap/bootstrap with config-supplier and config-paths (see example below) args will cause Stoic to:
starttheconfig-suppliercomponent- Read in config from the defined
config-paths - Create
watchersfor each config item, updating the values to reflect any changes at source. - Return the config in a map, the keys of which are those provided in the
config-paths, along with the config-supplier, namedstoic-config.
e.g. Consider the following config, stored in a edn config file:
{:components {:db {:url "thin:@localhost:1521/orcl"
:user "user-name"
:password "password"}
:rabbit {:host "localhost" :consumer-id "my-consumer"}}
:applications {:comments-service: "http://comments-service.co.uk/retrieve-comments"}}The config-path for a component should be listed in a vector, the above db and rabbit entries could be accessed as follows:
(def ^:private config-paths {:db [:components :db]
:rabbit [:components :rabbit]
:comments-service [:applications :comments-service})Note, the same config-paths map would be used to access config from Zookeeper, stored under:
<zk-root>/components/db
<zk-root>/components/rabbit
<zk-root>/applications/comments-service
The returned map would contain:
{:db #<Atom@3b7b4bd: {:url "thin:@localhost:1521/orcl",
:user "user-name", :password "password"}
:rabbit #<Atom@3b7c840: {:host "localhost"
:consumer-id "my-consumer"}
:comments-service #<Atom@3b7b4f0: {:comments-service: "http://comments-service.co.uk/retrieve-comments"}
:stoic-config #stoic.config.file.FileConfigSupplier {...}}Create a Stuart Sierra Component system-map as normal, using the returned config. Note, the stoic-config should be included in the system-map to maintain correct Component Lifecycle.
Call stoic.bootstrap/start, providing the system-map as an argument to start the components.
If an error occurs whilst starting the system-map, stoic will attempt to stop all components, and return :start-error.
Any updates made to the configuration will be available from the stoic-config component. For example, assuming the system-map is called system, and the config supplier was added to the system under stoic-config:
(-> system :stoic-config :config)
(ns my-app.bootstrap
(:require [com.stuartsierra.component :as component]
[stoic.bootstrap :as bs]
[stoic.config.file :as fc]
[stoic.config.supplier :as config-supplier]
[my-app.components.web-server :refer [make-webserver]]
[my-app.endpoints.routes :refer [main-routes]]
[cljrc-web.components.db :as [make-db-client]]
[cljrc-web.components.rabbit :refer [make-rabbit-consumer]]))
(def system nil)
(def ^:private config-paths {:db [:components :db]
:rabbit [:components :rabbit}
:comments-service [:applications :comments-service}})
(defn- new-system [config]
(component/system-map
:db (make-db-client @(:db config))
:rabbit (make-rabbit-consumer @(:rabbit config))
:web-server (component/using (make-webserver (main-routes)) [:db :rabbit])
:config (:stoic-config config)))
(defn init [path]
(alter-var-root #'system (constantly
(bs/bootstrap (fc/config-supplier path)
config-paths)))
;; alternatively
;; (alter-var-root #'system (constantly
;; (bs/bootstrap (config-supplier/make-config-supplier :file path)
;; config-paths)))
(defn start [opts]
(alter-var-root #'system (fn [s] (new-system s opts)))
(alter-var-root #'system bs/start))
(defn stop []
(alter-var-root #'system (fn [s] (when s (component/stop s)))))
(defn go []
(init (str (System/getenv "HOME") "/.config.edn"))
(start))
(defn reset []
(stop)
;; normally refresh would be called here
(go))When using a file-based config supplier, ensure the config file is in a directory with few other files. Stoic uses dirwatch to keep track of config updates. In the event that there are many files in the configuration's parent directory, startup time and config updates will be slow.