What is the recommended way to debug multi-threaded applications or in general code that does not hit a breakpoint by the way it’s constructed? For instance, when I use the #dbg macro or just instrument a function for debugging in Calva, it won’t be hit if I use a http call to get to this place in the code
I'm a big fan of tap> and Portal for debugging.
I have just tried to set Portal up inside Calva, without any luck so far. My Clojure service is dockerized and I am exposing the nrepl to host - connecting Calva via "Connect to a running REPL". Do you by any chance know of a resource that explains how to get it to work with docker (seeing that you have an extensive https://github.com/seancorfield/vscode-calva-setup working 🙂)?
That setup includes examples of Joyride creating an ssh tunnel and connecting to a remote nREPL and setting Portal up (copying the port file to the remote server). I use it with a VPN but the ports are open. If you're running Clojure in Docker for development (why would anyone do that???) you'll need more ports open/proxied and you'll have to ask in #portal for details on that.
Thanks, will give that a try. Running in Docker because I have a handful of microservices (python, node.js etc.) that all get spun up in a single docker compose up call and that interface through a shared network bridge. I guess I could still run clojure directly on the host but spinning the environment up wouldn't be as convenient.
I use Docker (w/compose) for Elastic Search, MySQL, and Redis, but run Clojure directly on the host -- well, in my case on WSL2 for Windows, with VS Code on the Windows side. Dealing with dev tools that open random ports makes Docker a PITA.
yes seems like it's a PITA... well I'll let you know if end up going the Docker way and somehow get it to work, or switch to Clojure on host - which would require me to rewrite my integrant system config to connect to the other microservices on localhost rather than virtual host names like http://mjml-server etc. It kind of makes for a nice separation, but may not be worth it after all...
In case someone stumbles upon this later I got it to work with Clojure inside Docker with this config:
(do
(require '[portal.api :as p])
(def p (p/open {:port 7123 ;; port needs to be mapped to host in Docker
:launcher :vs-code
:launcher-config {:host "host.docker.internal"}}))
(add-tap #'p/submit))
This just merges the host into the launcher-config that gets automatically written by the Portal VSCode extension (.portal/vs-code.edn) and which gets overwritten with every restart of VSCode (changing the port). So "localhost" becomes "host.docker.internal". I got the idea from this thread which provides some more context: https://clojurians.slack.com/archives/C0185BFLLSE/p1731329965040199
The relevant code that merges the configs is here: https://github.com/djblue/portal/blob/a3fca39f633108ac2cdfa8d44ef2facd98f11fe3/src/portal/runtime/jvm/launcher.clj#L24