Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic resolvers are called more than necessary. #193

Open
JohanCodinha opened this issue Feb 21, 2023 · 1 comment
Open

Dynamic resolvers are called more than necessary. #193

JohanCodinha opened this issue Feb 21, 2023 · 1 comment

Comments

@JohanCodinha
Copy link

Dynamic resolver could be further optimize by the planner to avoid unnecessary call to external services.
They tend to be used to talk to external services (DB, graphql, API) round trip to such services is usually slow so they should be merged as much as possible to batch request.

Here's a proposed algo for the planer to merge dynamic revolvers:
From a dynamic resolver node that is present multiple time in the graph.
Walk the graph towards the root and find a branching node where the node to be moved.
If that node already has the same dynamic resolver, merge them.

(defn highest-acceptable-parent-for-node
  "Search the node ancestors for a suitable branch target to move node,
   the target :run-next must either be the same resolver or empty,
   the paths must not contain the node resolver"
  [graph node-id]
  (let [{node-op-name ::pco/op-name} (get-node graph node-id)]
    (->> (node-ancestors graph node-id)
       rest
       (map #(get-node graph %))
       (take-while #(not= (::pco/op-name %) 'dynamic-res))
       (filter (comp #{::node-or ::node-and} node-kind))
       (filter #(not= (::run-next %) node-id))
       (take-while #(or (not (::run-next %))
                        ((into #{} (run-next-chain graph (::node-id %))) node-id)
                        (= (::pco/op-name (get-node graph (::run-next %)))
                           node-op-name)))
       (filter #(or (not (::run-next %))
                    (= (::pco/op-name (get-node graph (::run-next %)))
                       node-op-name)))
       last)))

(defn optimize-resolver-hoisting
  [graph env node-id]
  (if (::experimental-branch-optimizations env)
    (let [node        (get-node graph node-id)
          op-name'    (::pco/op-name node)
          dynamic?    (pci/dynamic-resolver? env op-name')
          has-duplicate? ((duplicate-node-ids graph) node-id)
          {target-node-id ::node-id
           target-has-next ::run-next} (highest-acceptable-parent-for-node graph node-id)]
      (if (and dynamic? has-duplicate? target-node-id)
        (if target-has-next
          (-> graph
              (add-snapshot! env {::snapshot-message "Merge dynamic resolver to higher parent"
                                  ::highlight-nodes  #{node-id target-has-next}
                                  ::highlight-styles {node-id 1
                                                      target-has-next 1}})
              (merge-sibling-resolver-nodes env target-node-id [target-has-next node-id])
              (optimize-node env target-node-id))
          (-> graph
              (add-snapshot! env {::snapshot-message "Move dynamic resolver to higher parent"
                                  ::highlight-nodes  #{node-id target-node-id}
                                  ::highlight-styles {node-id 1
                                                      target-node-id 1}})
              (remove-from-parent-branches node)
              (set-node-run-next target-node-id node-id)
              (optimize-node env target-node-id)))
        graph))
    graph))
@wilkerlucio
Copy link
Owner

Hi @JohanCodinha! Sorry for the long delay, I'm getting back to this now. I like the idea, can you provide me some test examples that can demonstrate the improvement of these optimizations?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants