Hi! What’s the trick to using the config created as <myproject>.config/env by the Luminus template? If I use it as a map directly it might not be ready yet and cause nil values. If I defer it I see a message that it is not started and that mount/start should have been called for that to happen. Since the Luminus code doesn’t do the latter I guess there’s something I’m missing. Help for reliable use would be appreciated.
The first thing you should do after getting your repl is call
then the config will be setup
@ramblurr I don’t see how that will help. What about code that is already evaluated before that, eg. a
(def foo (:bar env)) in another ns (effectively assigning
foo as env is not ready). In addition I start it with
lein run and would like it to get into a fully working state without any repl interaction. Sorry if I’m missing something obvious here, but I don’t see how having required repl steps is attractive. Sound like something that is easy to forget from time to time.
Feels like I’m missing the idea behind this design.
The luminus documentation on this pattern is described here https://luminusweb.com/docs/components.html
The intention is that any use of
env will occur after the config component is mounted (which is done as part of
(start)) . If you are
def ing something that needs a value from the config, then whatever you're defing should probably become a component itself, and managed via mount's start and stop.
You can use
defstate for this, see the docs I linked.
Thanks, I will have to sit down and read that doc more closely. My previous skimming through it did not give me the answers I was looking for.
I’ve previously attempted to only access
env from inside
defstate but that just propagated the problem in the sense that whatever uses what I define will also have to be inside a
defstate… That issue told me that it was something I had not really grasped.
My underlying “problem” is that that Luminus template has been serving me very well, so I haven’t really spent the required time on getting to know all the libraries well enough.
FWIW I stumbled through the same issues when I was getting started with it.
The simplest advice I can give on this topic, is to realize that when you are
(def foo (:bar env)) you are declaring state that depends on something external (as opposed to a constant like
(def foo 3.14)). Anytime you have state that depends on something external, declare it with defstate.
In your example, foo is just a config key from env. Presumably this foo will be used in some other piece of state, like a database connection. You do not need to
(defstate foo :start (:bar env)) but rather defstate the thing that will consume :bar,
(defstate a-thing :start (fn  (let [foo (:bar env)] (do-thing-with foo)))) then whatever (do-thing-with) returns can be accessed via a-thing.. or in other words that defstate is similar to
(def a-thing (do-thing-with (:bar env)))
for more background: luminus uses the
mount library to manage stateful components (that's what (start) is calling). mount is an adaption of stuart sierra's https://github.com/stuartsierra/component . I recommend watching stuart's talk that explains (in 45 minutes of detail) what this is all about
Thanks again, @ramblurr, very helpful. I kind of know what all of this is, but it hasn’t clicked yet. I just have to sit down and read, watch and code until it does. 🙂1🙌