tolitius / mount

managing Clojure and ClojureScript app state since (reset)
Eclipse Public License 1.0
1.22k stars 88 forks source link

Option to disable lazy-starting of states in CLJC mode #99

Closed krajj7 closed 5 years ago

krajj7 commented 5 years ago

It would be nice to have an option to throw an exception when using a stopped state in CLJC mode, rather than starting it lazily.

I'm using CLJC mode in Clojure (not ClojureScript) and encountered subtle bugs when only a subset of the states is started first. These states can start other states in the wrong order or multiple times.

Minimal example of a problem:

(mount/in-cljc-mode)

(mount/defstate B
  :start (do (println "B starting")
             (Thread/sleep 1000))
  :stop (println "B stopping"))

(mount/defstate A
  :start (doseq [x (range 3)]
           (future @B)))

Now if you (mount/start [#'A #'B]), everything is OK, but if you forget about B and only start A - (mount/start [#'A]), it will lazily start B up to three times (and only stops it once when later calling (mount/stop)).

tolitius commented 5 years ago

added ^{:on-lazy-start :throw} meta option.

how to work it

(mount/in-cljc-mode)

(defstate ^{:on-lazy-start :throw} B
  :start (do (println "B starting")
             (Thread/sleep 1000))
  :stop (println "B stopping"))

(mount/defstate A
  :start (doseq [x (range 3)] @B))
=> (mount/start #'dev/A)
java.lang.RuntimeException: could not start [#'dev/A] due to
java.lang.RuntimeException: :on-lazy-start is set to :throw i.e. (defstate {:on-lazy-start :throw} #'dev/B...) and #'dev/B state was not explicitly started before it was deref'ed (i.e. @#'dev/B)

included in version & docs

it's in [mount "0.1.14-SNAPSHOT"]

docs: https://github.com/tolitius/mount/blob/master/README.md#cljc-mode

krajj7 commented 5 years ago

Tried the new option with 0.1.14-SNAPSHOT and it works as expected, thank you! I'm using this for all my states now - a global switch (like a third nonlazy-cljc-mode) would be convenient, although I'm quite happy with it as-is as well :)