pathom

:pathom: https://github.com/wilkerlucio/pathom/ & https://pathom3.wsscode.com & https://roamresearch.com/#/app/wsscode
tony.kay 2020-12-17T19:22:32.498600Z

I’ve got a pathom performance problem. I’m hitting a resolver like this:

(defresolver all-products-resolver
  [{:keys [conn ast] :as env} _]
  {::pc/output [{:product/all-products [:product/id
                                        :product/sku
                                        :product/description
                                        :product/precise-price
                                        {:taxable/taxes [:tax/rate :tax/category]}
                                        {:product/tax [:tax/rate :tax/category]}
                                        :product/inventory-tracked?]}]}
  (let [db         (d/db conn)
        company-id (env->effective-company-id env)]
    {:product/all-products (get-all-products db company-id)}))
and the query function on the last line returns exactly what the query asks for. The incoming query is exactly what this resolver outputs. When I measure this the get-all-products takes 680ms, and Pathom takes another 6s to process the result…and it invokes readers 10000 times (I have 10000 products) for every attribute…though those calls are instantly satisfied by map-reader they still consume about 3s of CPU. How do I optimize this to stop abusing Pathom (this is version 2.2.30. I tried 2.3.0 and it was much much much worse for some reason)

tony.kay 2020-12-17T19:22:50.499Z

I was hoping that satisfying the exact query would make pathom just return the result

tony.kay 2020-12-17T19:24:39.499400Z

Perhaps this is the kind of thing you’re restructuring in Pathom 3 😄

tvaughan 2020-12-17T19:39:59.001800Z

A total shot in the dark, but would it help just to specify :product/all-products in the output, like ::pc/output [:product/all-products]? We have a query that has an output that is a map and we don't specify any of the sub-keys. We only query for the top-level key.

wilkerlucio 2020-12-17T20:03:15.002700Z

@tony.kay there is a escape feature for this situation, add the metadata ::p/final true to the list (when returning from the resolver), by doing so Pathom will skip processing it completly

1👍1🔖
tony.kay 2020-12-18T16:17:54.038400Z

This seems to be a problem in dev now. If I reload all nses for dev work, it pulls in pathom, which pulls in gen, which unfortunately pulls in Fulcro 2 stuff:

#error{:cause "Could not locate fulcro/client/primitives__init.class, fulcro/client/primitives.clj or fulcro/client/primitives.cljc on classpath.",
       :via [{:type clojure.lang.Compiler$CompilerException,
              :message "Syntax error compiling at (com/wsscode/pathom/gen.cljc:1:1).",
              :data #:clojure.error{:phase :compile-syntax-check,
                                    :line 1,
                                    :column 1,
                                    :source "com/wsscode/pathom/gen.cljc"},
              :at [clojure.lang.Compiler load "Compiler.java" 7647]}
             {:type java.io.FileNotFoundException,
              :message "Could not locate fulcro/client/primitives__init.class, fulcro/client/primitives.clj or fulcro/client/primitives.cljc on classpath.",

tony.kay 2020-12-18T16:18:39.038600Z

but you didn’t change anything in this rev…

tony.kay 2020-12-18T16:18:50.038800Z

hm, perhaps I’ll try 2.3.0 w/guardrails disabled 🙂

1👍
wilkerlucio 2020-12-17T20:05:37.004300Z

the reason is pathom don't know its exact data, so it has to scan anyway, doing a check for each data shape could have a similar cost, with the user declaration Pathom accepts that the user know more about it, and just skips processing

wilkerlucio 2020-12-17T20:12:43.005400Z

@tvaughan better to always keep the nested on the output, it doesn't affect running in any way, but improves the intelisense of pathom viz for queries (better auto-complete)

tvaughan 2020-12-17T20:13:32.005800Z

Good to know. Thanks @wilkerlucio

tony.kay 2020-12-17T21:40:16.006Z

thanks, I had a vague memory there was an escape hatch, but could not remember

tony.kay 2020-12-17T22:38:09.006600Z

no go. Does it matter what order the readers are installed?

tony.kay 2020-12-17T22:39:12.006800Z

I added debug breakpts in pathom, and only saw lots of calls to nested resolution..never saw that part of the program ever get the top-level list…

tony.kay 2020-12-17T22:47:01.007100Z

Map reader’s where I found that ::p/final, and when I watch what it does, I only ever see the individual nested entities. It never sees the list, so never skips it

tony.kay 2020-12-17T23:46:26.007800Z

Yeah, I’m getting into here in connect:

(defn- process-simple-reader-response [{:keys [query] :as env} response]
  (let [key (-> env :ast :key)
        x   (get response key)]
    (cond
      (and query (sequential? x))
      (->> (mapv atom x) (p/join-seq env))

      (nil? x)
      (if (contains? response key)
        nil
        ::p/continue)

      :else
      (p/join (atom x) env))))

tony.kay 2020-12-17T23:47:39.008Z

key is :products/all-products, and x is my list of 10,000 things, but it ignore metadata here and just processes them all anyway…unless, the query is nil

wilkerlucio 2020-12-17T23:56:57.008200Z

the thing that takes care of it is the map-reader

tony.kay 2020-12-17T23:57:28.008700Z

I’m tracing code with breakpoints

tony.kay 2020-12-17T23:57:41.008900Z

that is where I land, and then it does all 10000

wilkerlucio 2020-12-17T23:58:00.009100Z

I can't find process-simple-reader-response in pathom, isn't this in your codebase?

tony.kay 2020-12-17T23:58:14.009300Z

tony.kay 2020-12-17T23:58:16.009700Z

connect.cljc

tony.kay 2020-12-17T23:58:33.009900Z

v 2.2.30

wilkerlucio 2020-12-17T23:58:33.010100Z

ah, right

wilkerlucio 2020-12-17T23:59:05.010300Z

did you tried bumping to 2.3.0? I think that fn got removed

tony.kay 2020-12-17T23:59:25.010500Z

no, but 2.3.0 was waaaaay slower

tony.kay 2020-12-17T23:59:28.010700Z

can’t risk that in prod

tony.kay 2020-12-17T23:59:58.010900Z

I guess I could try and diagnose that, but I’ve already spent 5 hours on what should have been easy optimizations 😄