component 2020-02-19

@souenzzo has joined the channel

Hello I have a system

(let [system (-> (component/system-map
                   ::rest1 (->Http)
                   ::db1 (->Sql))
                 (component/system-using
                   {::rest1 {:db ::db1}}))]
  (component/start-system system [::rest1]))
When I call it, it start rest1 without db Is it expected? There is some way to "resolve deps" before start?

@souenzzo Why are you calling that helper function (`start-system`)? All the examples/documentation show to call component/start instead.

That aside, How is your Http component defined?

It looks a little odd to me to see a mix of qualified and unqualified keys here...

start-system without any component names is a a synonym for calling components/start on a system

but with component names it only starts the components you named

Yeah, just looked at the source -- I'd never seen anyone calling start-system or stop-system directly.

so by passing in component names you are overriding the automatic dependency starting logic

Makes sense. Only the whole system knows about the dependency from ::rest1 to :db right? Could you do (component/using (->Http) {:db ::db1}) instead of (->Http) to be able to start ::rest1 on its own with ::db1 started and injected?

I thought that component has "lazy" capabilities to handle cases like

(let [system (-> (component/system-map
                   ::rest1 (->Http)
                   ::db1 (->Sql)
                   ::rest2 (->Http))
                 (component/system-using
                   {::rest1 {:db ::db1}
                    ::rest2 {:db ::db1}}))]
  (component/start-system system [::rest1]))
Where when I ask rest1 it will start just what it really need But okay. Already Implement it at my side 🙂 May PR?

Use component/start on the whole system and it will work.

(PR with another signature, sure)

the way start-system works is it sorts the set of names (defaulting to all the names) according to dependency order and then starts each thing

and component/start on a system calls start-system

so if you don't give it a name, it will not be in the list regardless of the dependency information, and will not be started

there is a function component/dependencies you can use

you need the transitive closure of it

so something like

(component/start-system
 sys
 ((fn f [sys name]
    (cons name
          (for [[_ n] (component/dependencies (get sys name))
                i (f sys n)]
            i)))
  system
  ::rest1))

Maybe I will do a ubercomponent lib

(let [system (-> (component/system-map
                   ::rest1 (my-comp {::id :rest1})
                   ::rest2 (my-comp {::id :rest2})
                   ::gql (my-comp {::id :gql})
                   ::db1 (my-comp {::id :db1})
                   ::db2 (my-comp {::id :db2}))
                 (component/system-using
                   {::rest1 {:db ::db1}
                    ::rest2 {:db ::db2}
                    ::db2   {:db ::db1}
                    ::gql   {:db1 ::db1
                             :db2 ::db2}}))
      inits (for [[from component] system
                  :let [edges (component/dependencies component)]
                  [label to] edges
                  inits [[from {:label (pr-str from)}]
                         [to {:label (pr-str to)}]
                         [from
                          to
                          {:label (pr-str label)}]]]
              inits)]
  (-> (apply uber/digraph inits)
      (doto (uber/viz-graph))
      (uber.alg/topsort ::rest2)))

it may need a distinct around it too