System
BigConfig System is a library for implementing system lifecycles as programmable workflows rather than static dependency graphs. You should be familiar with libraries like Integrant .
- Add BigConfig as a dependency to your project
Terminal window neil add dep io.github.amiorin/big-config - Require the system library, it is just 6 functions so far
(ns systems(:require[babashka.process :as p][big-config.core :refer [->workflow]][big-config.system :as system :refer [stop stop! add-stop-fn re-program env destroy-forcibly]]))
- Trivial background process in place of a real database for example
;; Define a managed background process with a specific lifecycle;; Start the process in the background and block the main thread;; until the regex is found or the timeout triggers.(defn background-process [opts](let [cmd "bash -c 'for i in {10..1}; do echo $i; sleep 0.1; done;'"regex #"7"](-> (re-program cmd regex ::proc opts)(add-stop-fn (fn [{:keys [::proc] :as opts}](when proc@(p/destroy-tree proc)@(destroy-forcibly proc))opts)))))
- The system function is just a BigConfig workflow
;; Define the system as a stateful, wired workflow(def ->system(->workflow {:first-step ::start:wire-fn (fn [step _](case step::start [background-process ::end]::end [stop]))}))
- Start and stop the system differently based on the use case
;; sys1 starts and stops the system. It useful during the development of the system itself.;; sys2 starts only. This is useful in all the other cases.(into {} [[:sys1 (->system [log-step-fn] {::bc/env :repl})][:sys2 (let [system (atom (->system [log-step-fn]{::bc/env :repl ::async true}))](stop! @system)@system)]])))
With use-fixtures
Section titled “With use-fixtures”In Clojure’s clojure.test framework, use-fixtures is the standard mechanism for managing setup and teardown logic across your test suite. It allows you to wrap your tests with specific functions to prepare a clean environment—such as starting a database connection or binding dynamic variables—and then clean up afterward. You can apply fixtures at two levels: each (running once for every individual test) or once (running a single time for the entire namespace). A fixture is simply a higher-order function that accepts a test function as an argument, executes your setup code, calls the test function, and finally runs your teardown logic.
(defonce system (atom nil))
(defn with-system [f] (when @system (system/stop! @system)) (reset! system (components/->system {::bc/env :repl ::components/profile :test ::system/async true})) (f))
(use-fixtures :each with-system)