Fork me on GitHub
#mount
<
2018-09-19
>
tolitius03:09:40

@leblowl a couple of thoughts > but that's a little tedious with a lot of states how many states do you have? usually states help with something primitive, like connections, cache, thread pool, etc. both of your projects have a lot of them? > two projects that both use mount and one proj depends on the other could you be more specific on why they depend on each other. usually a project would depend on libraries, and libraries would usually not have states. they may certainly have functions that return state. this would all depend on your use case, so, if possible, let's talk about why you have these two projects have many states and most importantly why they would need to depend on each other

tolitius03:09:40

@leblowl a couple of thoughts > but that's a little tedious with a lot of states how many states do you have? usually states help with something primitive, like connections, cache, thread pool, etc. both of your projects have a lot of them? > two projects that both use mount and one proj depends on the other could you be more specific on why they depend on each other. usually a project would depend on libraries, and libraries would usually not have states. they may certainly have functions that return state. this would all depend on your use case, so, if possible, let's talk about why you have these two projects have many states and most importantly why they would need to depend on each other

leblowl03:09:51

Hey thanks for the reply. I think the library has around 20 states. The library builds a bunch of in memory indexes instead of using a database for some of it's data. I inherited it that way. I am not sure if using mount adds much for this scenario, but it's nice to be able rebuild dependent indexes more-or-less automatically on re-eval. I could also just use vars and refresh the namespaces. But anyways that's how it is now. But I don't think the quantity of states has much to do with the actual issue (my expectations not matching up regarding what states get started when). The two projects do not depend on each other...I am sorry for not being clear. I have a parent project that has state and then a child library that also has state. Since I thought mount relied on dependencies to start the correct components, I am confused why running mount/start in the library's namespace causes the whole project to start. This library has state in this case... it's a stateful library that may become it's own server at some point. Does that help clear things up for context?

leblowl03:09:58

I start a REPL via the parent process. Connect to it, require the child-library and call child-library/start which in turn calls mount/start thinking it will only start the child library's state. But it doesn't... it starts the child library's state and then all of the parent's state. Does that make sense?

leblowl03:09:51

So I am looking at your examples on the Github and it seems like that may not be intended behavior...I just wanted to check

leblowl03:09:16

no circular dependencies! haha

leblowl03:09:06

unless there is one hiding somehow..

tolitius14:09:27

> I am confused why running mount/start in the library's namespace causes the whole project to start. (mount/start) will start all the components that are known to compiler, since compiler is the one to tell mount what states are available. Hence it does include "transitive" dependencies. For example if a state a is defined in a namespace na, and another namespace foo where the (mount/start) is called from requires na, a will be stared. In case (mount/start) is called from a namespace bar that has a single "require" to foo, state a will still be started since it is that transitive dependency of foo. > it's a stateful library that may become it's own server at some point I don't think it makes sense to use mount in a library. stateful components are better started/stopped by the "main" / "external" application: which would make starting/stopping these states on the "edges" of the application. library could of course provide a way to start / stop its components: i.e. have functions to start / stop its components. take and server library you know, for example http-kit. it has a function run-server: https://github.com/http-kit/http-kit/blob/0cc921f0c2b62566f0884f0d8affa52516e30ac7/src/org/httpkit/server.clj#L9 which is later can be used by mount to start the server:

(defstate http-server :start (hk/run-server config)
                      :stop ((:stop-server http-server)))
where (:stop-server http-server) returns its "stop" function also provided by http-kit. hence you have a server library that does not start or stop anything. just provides the means to do so later in the entry point of the application. > The library builds a bunch of in memory indexes instead of using a database for some of it's data it would of course depend on the library design and purpose, but why do you need any mount states in this library at all? this library could have a make-indices function that would build all indices and return a map of all of them. later, in the application entry point, you could have a state:
(defstate in-memory-db :start (indexer/make-indices))
and then it's just a map where you could get to your data: i.e. (-> in-memory-db :foo :bar (get "42"))

leblowl16:09:57

@ Hey thanks for the reply. Yea I think that first part about the compiler is the part I didn't understand. If I start a REPL in my parent process and the initial namespace pulls in the parent's state, then the compiler is always going to know about it. If I then change into another namespace, and run mount/start its going to start any states in namespaces that have been required up to that point. So I think that was one of my misunderstandings. Thanks for re-iterating that for me. IMO, my example is just like HTTP kit. My library has a start/stop function and it takes care of it's own state. Internally it uses mount to start/stop that state. I could change it and I probably should. I do see some benefits to using a tool like mount. It handles creating a var dynamically in one sense. And I think simplifies the whole (def ^:dynamic x) && (defn init-x []) pattern. Maybe it's not intended to be used like that, but it works pretty well. But I think the real value with such a tool (in relation to my use-case) is being able to react to changes in state and re-compile dependents automatically... this feature would simplify needing to refresh/rebuild dependent states manually. But apparently we need some sort of graph for that (https://github.com/tolitius/mount/issues/88) (we need state to track the state! haha) ... So yea I think I'll just switch it to vars and fns for now and probably reduce some overhead at the same time

leblowl16:09:42

yea also a make-indices function like you describe that just build them all would handle the reloading aspect very easily/simply

leblowl16:09:44

Thanks for the suggestions

tolitius16:09:04

> IMO, my example is just like HTTP kit. My library has a start/stop function and it takes care of it's own state. Internally it uses mount to start/stop that state. I could change it and I probably should. if this is a library internally it should not use mount though, that's the difference from http-kit and other server libraries >I'll just switch it to vars and fns for now and probably reduce some overhead at the same time what will you switch to vars? if I understand your setup correctly, I would just extract all the states from the library into the application/project. by states I don't mean functions that start or stop components, but defstates that plug these components into the overall application state management

leblowl16:09:57

I understand your first point. I am planning to switch my library's defstates to vars and initialize those vars dynamically with functions. The states are really local to the library and the library exposes interfaces to access that state in different ways, so I don't want to move anything from the library to the parent project. From the parent I just care about starting the library/service and using it's interface/API. The idea is this data-access library is pretty useful on it's own and can be used by several projects at some point.

leblowl16:09:18

... remove mount from the library entirely

leblowl17:09:19

I think removing mount entirely is sort of more work in some ways. If this library were it's own HTTP server, I could use mount and not run into any trouble.

leblowl17:09:35

cuz they are totally separate projects

leblowl17:09:11

currently I just use something like this in the library:

(def lib-states [#'yea/yea #'a/b])
(defn start [] (mount/start lib-states))

leblowl17:09:17

and that works very well

leblowl17:09:33

I can still use mount in a library this way

tolitius17:09:20

you definitely have a better understanding of the project(s) you are working on, so of course do whatever makes sense 🙂 I would just suggest to minimize number of stateful components as much as possible, and to try not having mount in libraries. in case it is "a self starting" server, it might be more beneficial to decouple server library from the "starter". then you and anyone else can use the library on its own.

leblowl17:09:37

yea I think you are referring to de-coupling the server from the actual API library interface?

leblowl17:09:23

so that anyone can use the library without worrying about starting the server. and then starting the server in a separate process?

tolitius20:09:18

> you are referring to de-coupling the server from the actual API library interface? I meant decoupling the server library from the code that has the server (i.e. the code that calls a server start function)

leblowl20:09:23

Ok, yea that was the plan... not sure when I will get to it though