Hello all, I know that the compiler define the order of creation, but is there any way to define the order manually?
I´m having problem starting threading with mount
@fabrao: what problems are you having?
you can control the start order by simply starting states explicitly vs. starting all with (mount/start)
i.e.
(mount/start #'app.a #'app.c)
(mount/start #'app.b #'app.d)
will start a
and c
first, and then b
and d
but do I have to separate in two?
yes, if you do (mount/start)
or (mount/start #'app.a #'app.c #'app.b #'app.d)
, it will start all 4 states (given that you only have these four) in the order they were discovered by the compiler
hummmm
think about it as (mount/start "set" of states)
I´ll give a try
thanks
sure, let me know if this solves your use case
@tolitius It worked, many thanks
G'day! My apologies if this has been asked before (fwiw I spent a bit of time searching, but didn't find anything that seemed relevant). Is there an established way of having config specified via the command line (come in through -main [& args]
), but be handled from that point onward as "normal" mount state?
@pmonks we just pass it in using mount's with-args
in our -main
:
(->
cli-config
mount/with-args
mount/start)
where cli-config
is your config map
How do I refer to cli-config from other namespaces?
If you want to combine that with a static edn
file or something you can simply merge them in a config
state using mount/args
mount/args
will return the args you passed in
@fabrao greats, thanks for the feedback
@pmonks: there are a few ways
1. mount/args
is one, but this would be "global" per app: i.e. any ns will be able to access it without requiring anything
2. another one would be to use a known config path (or just pass this path via mount/args
), but use it to create a state: https://github.com/tolitius/stater/blob/master/smsio/src/app/conf.clj#L12-L13
3. another would be to use something like cprop: https://github.com/tolitius/cprop where you can use all the -Dconf=config-path
(or any system props), or env vars, or classpath resource, etc..
Nice - thanks @manderson, @tolitius!
Yeah I like the idea of require
as the dependency graph of states, and would like to preserve that if I can.
(also because I want different "components" to be able to define additional state based on this config state)
cprop sounds interesting, though I don't like System properties much - I tend to use tools.cli to handle this kind of thing as "real" CLI parameters.
But great pointers - you've gotten me moving again!
@pmonks: sure, sys props is just one of many venues to get config(s). I usually just use a single config file (`.edn`) and override props at runtime depending on environment with ENV vars (just one way to do it). there are also cursors in cprop that I use a bit to not have to destructure very nested configs in multiple places: https://github.com/tolitius/cprop#cursors
Ah ok - and yeah my plan is to have a single central config file, with a single CLI arg that points to it at runtime.
configuring apps is an interesting subject, and also quite opinionated in our community 🙂 I prefer to use whatever makes sense for a given problem with no ground rules like 12 factor and others..
👍
Bootstrapping is one place where things get squirrelly, I've found. 😉
right, just try several different approaches, see what works best, I found just slurping .edn
works great for little apps, whereas a config lib (i.e. cprop) comes very handy for larger apps: different modules, dockerized and overriden by envs, etc..
So am I right in thinking I could do something like (defstate config :start (load-config))
? Could this be done within a (def -main ...
, so that I can set the :file
based on CLI opts?
e.g. something like (not code checked, so probably contains syntax errors):
(defn -main [& args]
(let [config-file (parse-args args)]
(defstate config :start (load-config :file config-file))))
you're not supposed to defstate
in the functions
just (mount/start)
there's a version of start
that takes arguments
(I think)
Ok. I guess I'm still not clear on how I can parse the args passed to -main, then put them in a mount state (which can be depended upon by other states via standard require
).
https://github.com/tolitius/mount#be-composing says you need to
(defstate config :start (load-config :file (mount/args)))
(defn -main [& args]
(-> (parse-args args)
(mount/with-args)
(mount/start)))
or something like that@pmonks: is (load-config)
your function or is it coming from a library (i.e. cprop
)?
If it is coming from cprop, it would work without needing to pass runtime mount/args, as cprop would look in two places for configuration files:
* classpath: for the config.edn
resource
* file system: for a path identified by the conf
system property (i.e. the one you can pass via -Dconf=[path]
)
in case the (load-config)
is your function, you could just access the system property directly:
(defn load-config [path]
(info "loading config from" path)
(-> path
slurp
edn/read-string))
(defstate config
:start (load-config (System/getProperty "conf")))
given that conf
is your property with a path to the your-config.edn
file (i.e. -Dconf=/opt/app/yourapp/conf/app-conf.edn
<< an example path)
Yeah the challenge is that I need to parse the args
passed into -main
in order to know what path to call load-config
with. It looks like mount's with-args
fn might be the missing link I'm looking for though (thanks @dm3!).