Fork me on GitHub
#luminus
<
2020-08-27
>
mokr07:08:13

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.

Casey08:08:25

The first thing you should do after getting your repl is call (start)

Casey08:08:32

then the config will be setup

mokr09:08:19

@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 nil to 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.

Casey10:08:28

The luminus documentation on this pattern is described here https://luminusweb.com/docs/components.html

Casey10:08:49

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.

Casey10:08:16

You can use defstate for this, see the docs I linked.

mokr10:08:41

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.

Casey10:08:11

FWIW I stumbled through the same issues when I was getting started with it.

Casey10:08:04

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.

Casey10:08:25

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)))

Casey10:08:42

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

👍 3
mokr10:08:20

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. 🙂

🙌 3