Agents, Vars and Dynamic Binding
25.1 Agents
(def log-agent (agent []))
(send log-agent conj "started") ; asynchronous; runs on a fixed thread pool
(send-off log-agent (fn [log] (Thread/sleep 100) (conj log "io done"))) ; for blocking work
(await log-agent) ; wait for pending actions
@log-agent ; ["started" "io done"]
(def writer (agent nil))
(defn log-line! [msg] (send-off writer (fn [_] (spit "app.log" (str msg "\n") :append true))))
(agent-error log-agent) ; inspect a failed agent
(restart-agent log-agent [] :clear-actions true)
(set-error-handler! log-agent (fn [a ex] (println "agent error" ex)))
(shutdown-agents) ; stop the agent thread pools at program end25.2 Vars and Dynamic Binding
Prefer passing configuration explicitly. Dynamic vars are best for cross-cutting context (*out*, *print-length*, request context).
(def ^:dynamic *db-url* "jdbc:dev")
(defn query [] (str "querying " *db-url*))
(query) ; "querying jdbc:dev"
(binding [*db-url* "jdbc:test"] ; thread-local rebinding
(query)) ; "querying jdbc:test"
(alter-var-root #'*db-url* (constantly "jdbc:prod")) ; change the root value
(with-redefs [query (fn [] "mocked")] ; temporary redefinition (testing)
(query)) ; "mocked"
#'query ; the var itself
(meta #'query) ; metadata: :ns :name :file :line :arglists :doc
((var query)) ; calling through the var (sees redefinitions)