I'm currently learning to work with component, please excuse me if this is a n00b question.
Calling reloaded.repl/start
, stop
, reset
, reset-all
, go
, suspend
and resume
on the repl in the user namespace works.
However, if I hit C-c C-x
(that is cider-refresh) I don't get an error message, but jetty isn't reachable afterwards, even though the port is still blocked.
Calling (stop)
and (start)
afterwards manually doesn't seem to affect any components any more.
Here is the *Messages*
output for the command:
cider-refresh: Calling reloaded.repl/suspend
cider-refresh: Successfully called reloaded.repl/suspend
cider-refresh: Reloading (re-frame.db re-frame.loggers re-frame.registrar re-frame.interceptor re-frame.cofx re-frame.utils re-frame.trace re-frame.subs re-frame.std-interceptors re-frame.events re-frame.router re-frame.fx re-frame.core com.stuartsierra.dependency example.config com.stuartsierra.component example.routes example.application example.example-test example.common user example.common-test)
cider-refresh: Reloading successful
cider-refresh: Calling reloaded.repl/resume
cider-refresh: Successfully called reloaded.repl/resume
The only way I have managed to get back into a working state is by restarting the JVM.
How can I debug what is going wrong?Following the steps that reset does manually also works:
(reloaded.repl/suspend)
(clojure.tools.namespace.repl/refresh :after `reloaded.repl/resume)
What am I missing here?
@vinai likely refresh is destroying the var that contained the server, the only safe option is to make sure you stop the component before reloading the code
I don’t know cider very well, but I’d imagine it provides some customization for hooks to call before reloading?
Thanks for responding @noisesmith. The customization hook runs reloaded.repl/suspend
before and reloaded.repl/resume
afterwards.
wouldn’t you want to use stop and start instead?
if you put the component in a top level binding, refresh (or even reload if you don’t use defonce) will destroy the accessible binding and you won’t be able to access it to stop it after that point
so the only safe thing is to destroy it before reloading code
suspend and resume seems to do the same as stop and start for most components. If I call it manually suspend calls .stop on the jetty instance var.
I don't know elisp but from what I can tell all it should do is run refresh or refresh-all in between suspend and resume. However, when I do that manually all is okay.
oh, OK - if you are losing access to a running component, it’s not doing that process properly, I was suspicious of suspend and resume because I know that stop and start work, and haven’t used suspend and resume
Only the cider keyboard shortcut messes the state up.
right, what I was suggesting was hooking onto the keyboard shortcut
because there is nothing you can do easily to make that not break your app
Currently I'm just invoking reset when I need to manually, but it would be nice to have the keyboard shortcut working... Here are the docs:
(cider-refresh &optional MODE)
Reload modified and unloaded namespaces on the classpath.
With a single prefix argument, or if MODE is `refresh-all', reload all
namespaces on the classpath unconditionally.
With a double prefix argument, or if MODE is `clear', clear the state of
the namespace tracker before reloading. This is useful for recovering from
some classes of error (for example, those caused by circular dependencies)
that a normal reload would not otherwise recover from. The trade-off of
clearing is that stale code from any deleted files may not be completely
unloaded.
Maybe I should head over to #cider
The elisp code in question is
`("op" ,(if refresh-all? "refresh-all" "refresh")
"print-length" ,cider-stacktrace-print-length
"print-level" ,cider-stacktrace-print-level)
So it really only seems to send the op nrepl message refresh-all or refresh.Anyway, thanks for chiming in!