Fork me on GitHub
#component
<
2020-02-19
>
souenzzo21:02:30

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?

seancorfield21:02:08

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

seancorfield21:02:40

That aside, How is your Http component defined?

seancorfield21:02:14

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

hiredman21:02:43

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

hiredman21:02:59

but with component names it only starts the components you named

seancorfield21:02:07

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

hiredman21:02:50

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

seancorfield21:02:09

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?

souenzzo21:02:52

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?

seancorfield21:02:28

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

souenzzo21:02:33

(PR with another signature, sure)

hiredman22:02:14

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

hiredman22:02:29

and component/start on a system calls start-system

hiredman22:02:57

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

hiredman22:02:49

there is a function component/dependencies you can use

hiredman22:02:09

you need the transitive closure of it

hiredman22:02:45

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

souenzzo22:02:06

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

hiredman22:02:41

it may need a distinct around it too