component

wilkerlucio 2022-07-04T18:06:09.689069Z

hello, is there a way to measure how much time each component is taking to start? I'm trying to debug why some project here takes so long to start, and having the time for each specific component would be super helpful. the hard part of my case is that most components are part of external libraries, so changing their code to measure is painful

✅ 1
wilkerlucio 2022-07-04T18:37:01.263269Z

so far I got around by forking component and adding my measurement code there, but would be nice a way that doesn't require hacking the library

2022-07-04T19:20:31.520859Z

What do you mean by start?

wilkerlucio 2022-07-04T19:20:50.628229Z

how long the start fn (from Component/start) takes to run, for each component

wilkerlucio 2022-07-04T19:21:04.729879Z

this is what I did on my hack:

wilkerlucio 2022-07-04T19:21:06.425719Z

(defn- try-action [component system key f args]
  (try (println "starting" component)
       (time
         (apply f component args))
       (catch #?(:clj Throwable :cljs :default) t
         (throw (ex-info (str "Error in component " key
                           " in system " (platform/type-name system)
                           " calling " f)
                  {:reason     ::component-function-threw-exception
                   :function   f
                   :system-key key
                   :component  component
                   :system     system}
                  t)))))

wilkerlucio 2022-07-04T19:21:33.406689Z

(the hack is back because this fn might be called during stop as well, but just a dirty hack to get it working for my case)

2022-07-04T19:22:25.943069Z

Sure, but I mean, take a step back, of your application is slow to start it is very unlikely that component start time meaningfully contributes to that

wilkerlucio 2022-07-04T19:22:51.537819Z

it actually is, from my debug I could find a single component taking 97s to start

wilkerlucio 2022-07-04T19:23:13.024389Z

from the 120s total

2022-07-04T19:23:29.626859Z

That is crazy

2022-07-04T19:24:00.274659Z

It is possible to do arbitrary stuff in start, but that doesn't mean you should

wilkerlucio 2022-07-04T19:24:38.003929Z

well, the slow ones are things that depend on external data, so they have to download things from the internet, it happens the perpetrator is doing a lot of downloading

2022-07-04T19:25:44.711019Z

Oof, horrendous

wilkerlucio 2022-07-04T19:26:30.738979Z

so, this debug allowed me to pinpoint that component, and that's the gist of why I want something like that

2022-07-04T19:29:46.254219Z

Sure, well the component library has a function I forget the name of that basically maps whatever over the components in a system

2022-07-04T19:30:07.109639Z

Starting a system is using that function together with the start function

2022-07-04T19:30:37.550579Z

So you just use that function with a function that wraps start with time

2022-07-04T19:33:20.381499Z

(update-system s (keys s) (fn [c] (prn (type c)) (time (start c)))) or something

2022-07-04T19:34:21.175779Z

But once you identify the components that are fetching things over the internet when starting, absolutely ditch them

wilkerlucio 2022-07-04T19:36:33.093509Z

its not that easy, because the components might implement other protocols other than the component one (and most on them in my case does) so wrapping that instance while forwarding every protocol is complicated

wilkerlucio 2022-07-04T19:37:57.304979Z

I think the ideal situation would be have sort of plugins/hooks support on component itself, so we could react to things like start/stop

2022-07-04T19:39:28.409009Z

There is no wrapping

2022-07-04T19:40:05.198739Z

You just use your own call using update-system like above in place of calling start on the whole system

2022-07-04T19:40:58.381929Z

Er start-system

2022-07-04T19:41:32.650929Z

Your can see it is what start-system does https://github.com/stuartsierra/component/blob/master/src/com/stuartsierra/component.cljc#L165 but just adding a call to time

wilkerlucio 2022-07-04T20:09:15.784589Z

generically

wilkerlucio 2022-07-04T20:13:25.134809Z

ah, makes sense, afk now, but will try whenI get back :)

wilkerlucio 2022-07-04T21:45:12.702459Z

ok, this works:

(defn start-measured [component]
  (println "starting" component)
  (time (component/start component)))

(comment
  (time
    (let [sys (system-config)]
      (component/update-system sys (keys sys) #'start-measured))))