I am trying to get dirac working with my app, but am getting the error "Dirac Agent is not listening at <ws://localhost:8231>"
My app uses mount, and I am starting the dirac agent like so:
(mount/defstate ^{:on-reload :noop} repl-server
:start
(when (env :nrepl-port)
(dirac.agent/boot!)
(nrepl/start {:bind (env :nrepl-bind)
:port (env :nrepl-port)
:handler (nrepl.server/default-handler dirac.nrepl/middleware)}))
:stop
(when repl-server
(dirac.agent/destroy!)
(nrepl/stop repl-server)))
In my repl I can see:
@dirac.agent/current-agent
=> #object[clojure.lang.Atom 0x63c0dbd6 {:status :ready, :val nil}]
can you copy what Dirac Agent prints during start?
I don't see any logs printed on startup.
From dirac, at least
then (dirac.agent/boot!)
didn’t do its job, it should tell you that it is listening on 8231
Dirac Agent v1.3.0
Connected to nREPL server at <nrepl://localhost:8230>.
Agent is accepting connections at <ws://localhost:8231>.
Aha, now I am getting an exception from dirac I wasn't seeing before.
Does (dirac.agent/boot!)
have to be called after the nrepl is started?
no, it runs a background thread which tries to connect repeatedly
[clojure-agent-send-off-pool-9] ERROR nrepl.misc - (#error {
:cause nil
:via
[{:type java.lang.NullPointerException
:message nil
:at [clojure.core$swap_BANG_ invokeStatic core.clj 2346]}]
:trace
[[clojure.core$swap_BANG_ invokeStatic core.clj 2346]
[clojure.core$swap_BANG_ invoke core.clj 2337]
[dirac.nrepl.state$register_last_seen_nrepl_message_BANG_ invokeStatic state.clj 52]
[dirac.nrepl.state$register_last_seen_nrepl_message_BANG_ invoke state.clj 49]
[dirac.nrepl.state$register_last_seen_nrepl_message_BANG_ invokeStatic state.clj 50]
[dirac.nrepl.state$register_last_seen_nrepl_message_BANG_ invoke state.clj 49]
[dirac.nrepl.piggieback$handler_job_BANG_ invokeStatic piggieback.clj 93]
[dirac.nrepl.piggieback$handler_job_BANG_ invoke piggieback.clj 92]
[dirac.nrepl.piggieback$dirac_nrepl_middleware_handler invokeStatic piggieback.clj 104]
[dirac.nrepl.piggieback$dirac_nrepl_middleware_handler invoke piggieback.clj 100]
[clojure.core$partial$fn__5561 invoke core.clj 2616]
[nrepl.middleware$wrap_conj_descriptor$fn__47766 invoke middleware.clj 15]
[nrepl.server$handle_STAR_ invokeStatic server.clj 17]
[nrepl.server$handle_STAR_ invoke server.clj 14]
[nrepl.server$handle$fn__48186 invoke server.clj 26]
[clojure.core$binding_conveyor_fn$fn__5476 invoke core.clj 2022]
[clojure.lang.AFn call AFn.java 18]
[java.util.concurrent.FutureTask run FutureTask.java 266]
[java.util.concurrent.ThreadPoolExecutor runWorker ThreadPoolExecutor.java 1142]
[java.util.concurrent.ThreadPoolExecutor$Worker run ThreadPoolExecutor.java 617]
[java.lang.Thread run Thread.java 745]]} Unhandled REPL handler exception processing message {:id f181b5ef-f5af-4b46-b28c-89eefe77b65e, :op describe})
hmm
my wild guess is that you don’t have standard nrepl middleware present or in wrong order
(nrepl/start {:bind (env :nrepl-bind)
:port (env :nrepl-port)
:handler (nrepl.server/default-handler dirac.nrepl/middleware)})
it picks codepath when it expectes nrepl session to be present, but it is nil
and AFAIK session is handled by nrepl session middleware
Let me see if I can grok where this falls in relation to nrepl middleware
Ah, I think you are right and this middleware is being called before nrepl session middleware
Let me see if I can fix that
btw. this is the problematic line: https://github.com/binaryage/dirac/blob/master/src/nrepl/dirac/nrepl/state.clj#L50
it expects some previous code was wrapped in ensure-session
btw. here are more details: https://github.com/binaryage/dirac/blob/master/docs/about-repls.md#clojure-nrepl-sessions I don’t even remember them, the code is pretty old and I forgot the details
For this trick to work our 'session' middleware must be configured to go first (or very early before 'eval' middleware).
I have some sanity checks in during nrepl startup, for example I check for this list of “middleware operations” present (also their order matters): https://github.com/binaryage/dirac/blob/master/src/lib/dirac/lib/nrepl_tunnel.clj#L97-L98
it should give you this warning during startup if your middleware list is non-standard: https://github.com/binaryage/dirac/blob/master/src/lib/dirac/lib/nrepl_tunnel.clj#L68
I guess in your case it failed even before it got there
I'm getting the right message printed, and just resolved a warning about mismatch nrepl version
Running things again, hopefully it all works now
good, maybe I should make that swap
more resilient for this case, I’m pretty sure it would print that warning later
Indication that the middleware must come after nrepl session in either error or installation instructions would have probably helped quite a bit
Looks like it is all working now. Thank you!
nice, let me know if anything, I don’t personally use boot, so I would be curious if it worked end-to-end
When I stop and then restart the server (and dirac agent) using mount, I see the dirac console correctly stall waiting on the agent, and then reconnect and allow use again
However, after maybe a minute it will show:
Unable to bootstrap ClojureScript REPL due to a timeout.
Usually this happens when server-side process raised an exception or crashed.
Please check error output in Dirac Agent.
With this printed on server:
[async-dispatch-3] WARN dirac.lib.weasel-server - Received eval result without matching eval-id #2
[async-dispatch-8] ERROR dirac.lib.nrepl-tunnel-server - [NREPLTunnelServer#3 of [NREPLTunnel#3]] Received a bootstrap timeout from client [WebSocketServerClient#11] :
{:op :bootstrap-timeout}
It does allow use and return correct responses for about a minute until that occurs, however
This is after closing both the nrepl server using nrepl/stop
and the dirac agent using dirac.agent/destroy!
before starting both again with nrepl/start
and dirac.agent/boot!
respectively
try to enable verbose logging vie env var: https://github.com/binaryage/dirac/blob/master/docs/faq.md#how-to-enable-debug-logging-in-dirac-agent
we will see just agent side of the communication, but it could help
ah, it will be more involved
not just the env var
I have a meeting in a few minutes. I will have to revisit this.
Meanwhile, another hopefully quick question:
Autocomplete recognizes that I have added the require [reagent.session :as session]
However, if I try to utilize the alias I see:
I don't get this behavior in the figwheel repl
look here: https://github.com/binaryage/dirac-sample#hello-world
you have to require the stuff first for REPL environment to be aware of it
also more is here: https://github.com/binaryage/dirac/blob/master/docs/about-repls.md#dirac--figwheel
In my first screenshot you can see that I changed ns to the one with the dependency
Which appears to follow the first instructions you linked
short answer: figwheel uses the same clojurescript compiler state as your live reloading
in-ns
will just set current ns, but won’t load code which should be in it
your REPL is a blank slate in case of Dirac (or any other repl except figwheel)
I was also surprised when I first learned about it, maybe you can somehow load all your namespaces as part of your nREPL startup
I think that makes sense now. Are you aware of an easy way to execute all code found in that namespace from within the dirac console?
require
will load everything transitively, so if you have one namespace which requires all others that should do the job
you could require that in your REPL init script (I believe) or as your first command before starting working with REPL
All right, for now simply requiring the ns before calling in-ns appears to be sufficient (at least until I start trying to create circular dependencies :D).
I really appreciate all the help. It's looking like this will really improve my workflow
Thanks for the awesome tool! 🙂
np, good luck 🙂
btw. the reason why it sees [reagent.session :as session]
is because auto-completion uses just info from source maps, for example tries to parse ns form in associated sourcemap and help this way, it is not related to what nREPL server “thinks”