#99 and #95: add ^{:on-lazy-start :throw}

This commit is contained in:
anatoly 2018-10-12 14:22:49 -04:00
parent db38d8cacd
commit 6e848d1ee4
2 changed files with 55 additions and 2 deletions

View file

@ -551,6 +551,56 @@ Mount detected that `#'dev/won't-be-here-long` was deleted, hence:
<< stopping.. #'dev/won't-be-here-long (it was deleted)
```
## `cljc` mode
By default mount states are kept under var references. While it works for Clojure, it falls short in the land of ClojureScript since, especially during an `:advanced` compilation, var names get compressed + ClojureScript does not support reified vars.
To support both Clojure and ClojureScript mount has a `cljc` mode which is well documented in [here](doc/clojurescript.md#managing-state-in-clojurescript), and can be enabled by `(mount/in-cljc-mode)`.
### Disable Lazy Start
When in `cljc` mode, mount states that are not started by `(mount/start a b c)`, or that are not transitive states: i.e. not `:require`d at the time `(mount/start)` is called, will start lazily whenever they are dereferenced:
```clojure
=> (mount/in-cljc-mode)
:cljc
=> (defstate db-connection :start (println "connecting")
:stop (println "disconnecting..."))
=> db-connection
#object[mount.core.DerefableState 0x546b9d51 {:status :pending, :val nil}]
dev=> (mount/running-states)
#{}
dev=> @db-connection ;; db-connection will start here when deref'ed even though it was not started explicitly
connecting
dev=> (mount/running-states)
#{"#'dev/db-connection"}
```
This can be quite handy as it allows certain app states to start lazily.
However there are cases when it is best to fail in case a certain state is deref'ed while it was not yet started. This is possible by marking such states with `^{:on-lazy-start :throw}` metadata:
```clojure
=> (defstate ^{:on-lazy-start :throw} db-connection :start (do (println "connecting") 42)
:stop (println "disconnecting..."))
=> @db-connection ;; this will throw since db connection is deref'ed before it was started
java.lang.RuntimeException: :on-lazy-start is set to :throw i.e. (defstate {:on-lazy-start :throw} #'dev/db-connection...) and #'dev/db-connection state was not explicitly started before it was deref'ed (i.e. @#'dev/db-connection)
=> (mount/start #'dev/db-connection)
connecting
{:started ["#'dev/db-connection"]}
=> @db-connection
42
```
## Packaging
Since `mount` relies on the Clojure/Script Compiler to learn about all the application states, before `mount/start` is called all the namespaces that have `defstate`s need to be compiled.

View file

@ -126,9 +126,12 @@
(#?(:clj deref
:cljs -deref)
[_]
(let [{:keys [status inst] :as state} (@meta-state name)]
(let [{:keys [status var inst] :as state} (@meta-state name)]
(when-not (:started status)
(up name state (atom #{})))
(if (= :throw (-> var meta :on-lazy-start))
(throw-runtime (str ":on-lazy-start is set to :throw i.e. (defstate {:on-lazy-start :throw} " name "...) "
"and " name " state was not explicitly started before it was deref'ed (i.e. @" name ")"))
(up name state (atom #{}))))
@inst))
#?(:clj clojure.lang.IPending
:cljs IPending)