hey, mount newbie here. Do you use partially applied functions as states in mount? E.g. I have (defn find-user [db id] …)
function and turn it into state that depends on db
state like (defstate user-finder :start (partial find-user db))
.
This works fine, but doesn’t obviously “react” properly when db
state is stopped
I mean it still keeps the “running” version of db
state. Is there a way to combine those two: partial application to avoid dragging all the “deps” as well as having “live-link” to db
state? Gist here: https://gist.github.com/mostr/372f65ece0ad6ea218d1
@mostr: welcome! :simple_smile:
looks like you are missing a :stop
(defstate db :start users)
that's why it is not stopped when (mount/stop)
is called
try (defstate db :start users :stop #{})
or whatever stop value makes more sense
in reality it will be a real db disconnect
hm, so I did the following:
(defn stop []
(prn "Stopping users db")
#{})
(defstate db
:start users
:stop (stop))
but still get
Loading src/clj_sandbox/ms/users_db.clj... done
(mount/stop)
=> {:stopped []}
(mount/start)
=>
{:started ["#'clj-sandbox.ms.users-db/db"
"#'clj-sandbox.ms.user-finder/user-finder"
"#'clj-sandbox.ms.user-finder/user-finder2"]}
(user-finder 2)
=> {:id 2, :name "bar"}
(mount/stop #'clj-sandbox.ms.users-db/db)
"Stopping users db"
=> {:stopped ["#'clj-sandbox.ms.users-db/db"]}
(user-finder 2)
=> {:id 2, :name "bar”}
not sure if this is real-life case (stop db while running), but trying to understand how things work in mount
Actually this works as expected as there is (partial…)
in user-finder
state definition which just probably takes “current” value/reference to db
and doesn’t care about state changes. But I wonder whether there is a way to combine these two things: partial application + being aware of state changes
I'll check it out in a couple hours.. will let you know
sure, no worries :simple_smile:
looking at it with less distractions... :simple_smile: yea, this is expected, here is just plain Clojure example:
boot.user=> (def db {:a 42})
#'boot.user/db
boot.user=> (def find-key (partial db))
#'boot.user/find-key
boot.user=> (find-key :a)
42
boot.user=> (def a {})
#'boot.user/a
boot.user=> (find-key :a)
42
in case you are ok with closing state over in function, you can simply (:require [users-db :refer [db]])
in user-finder
and use it within a function.
you are of course have freedom of where to use defstate
, but I found it is best used for resources, like db
in this case
and API, such as user-finder
could just use it as functions, rather than be defstates themselves
there you can choose whether to close over that db and pass it there directly
for example, say you have your db API that have access to db state live in app.db
namespace. then you can do:
(:require [app.db :as db])
(GET "/find-user" [user]
(db/find-user user))
or, if you'd like to use your pure find-user
function, you can do that too:
(:require [app.db :refer [db]])
(GET "/find-user" [user]
(find-user db user))
you could notice that in the second example, a route closes over the db
state. which is ok, since this is the edge of your application (i.e. no impact or coupling with business logic).