lsp

rolt 2025-09-01T07:45:20.324269Z

Hello, I've been experiencing an issue where clojure-lsp would use 100% cpu for a long time (way longer that it takes analysing the whole project from scratch) when changing branches or rebasing. I tracked down the problem and found 2 issues ๐Ÿงต

rolt 2025-09-01T07:45:32.532829Z

1) the client has a weird behavior where, for the same file, I'm getting multiple didChangeWatchedFiles, one per type, which seems weird. This leads to unnecessary analysis but it's not the most important problem. Is git doing several operations per file when changing branch ?

rolt 2025-09-01T07:46:56.732899Z

2) The server receives the didChangeWatchedFiles notification sequentially, and treat each one separately. Now If I have ns a & b that are both required in c, when both a and b change we re-analyze c twice. In my project I have a few namespaces that are really used everywhere. In my testing the same namespace was re-analyzed 62 times when my branch only changed 59 files (125 didChangeWatchedFiles notifications. If I simply batch and de-duplicate the analysis of referenced files the problem goes away.

rolt 2025-09-01T07:48:07.549509Z

Here is the code I used in file_management.clj (sorry about the ugly inefficient code, just wanted something that works first try):

(def queue (atom []))

(defn batching-worker
  []
  (future
    (loop []
      (Thread/sleep 1000)
      (when (seq @queue)
        (let [batch @queue
              n-items (count batch)]
          (swap! queue #(vec (drop n-items %)))
          (doseq [[db* v] (group-by :db* batch)]
            (let [uris (into #{} (mapcat :uris v))]
              (analyze-reference-uris! uris db*)
              (run! #(deliver (:response-promise %) ::done) v)))))
      (recur))))

(batching-worker)

(defn analyze-reference-uris!*
  [uris db*]
  (let [p (promise)]
    (swap! queue #(conj % {:uris uris :db* db* :response-promise p}))
    @p))

rolt 2025-09-01T08:11:16.515489Z

(ping @lasse.olavi.maatta you can check if this also solves the problem for you)

lassemaatta 2025-09-01T08:14:34.089269Z

I have some utility namespaces, which are referenced in over 600 other namespaces in my project, which might explain why this issue haunts me ๐Ÿ˜…

rolt 2025-09-01T08:16:22.455919Z

you can exclude those namespace from re-analysis with lsp-file-watch-ignored-files as a partial solution, at least when rebasing things

ericdallo 2025-09-01T12:14:33.478429Z

yeah, we had multiple improvements in clojure-lsp related to that, but your fix seems to be a good improvement, feel free to open a pr @rolthiolliere so I can take a closer look

rolt 2025-09-01T12:43:57.134619Z

Great if a batching approach seems sound I'll prepare something. The "patch" I wrote here has a few issues.

ericdallo 2025-09-01T12:50:27.368379Z

it's way important to analyze files changed outside editor slowly, but consistenly , than faster and wrong or affecting performance