Skip to content

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 .

  1. Add BigConfig as a dependency to your project
    Terminal window
    neil add dep io.github.amiorin/big-config
  2. 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]]))
  3. 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)))))
  4. 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]))}))
  5. 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)]])))

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)

Testing with BigConfig System