Although it technically works, it seems to fail consistently in real-life scenarios.
My objective was to get this working with Genie apps, where this handleReq
function does a lot of complex work. So it would be something like:
function handleReq()
response = a_lot_of_deep_nested_computations()
return response
end
When passing this through the debugger, two things happen:
1 - it is unbearably slow, to the point of not being usable;
2 - breaking on error, deep in the computation, starts a debug session. Quitting the debug session returns nothing
. Which raises another exception because response
should not be nothing
. Which is being caught again, and so on - it just never seems to exit the debugger which is amplified by being so slow and unresponsive to the point of having to quit the whole thing.
So another approach I took was to load the debugger a lot later within the a_lot_of_deep_nested_computations()
stack. Something in the line of:
function a_lot_of_deep_nested_computations()
a(
b(
c(
# more stuff happening
Debugger.@run user_generated_code_to_be_debugged()
)
)
)
end
That works much better, performance wise, but the debugger goes nuts. It doesn’t properly process the input, any input is interpreted like garbage:
1|debug>
Unknown command `lphfea`. Executing `?` to obtain help.
1|debug> lphttt?
Unknown command `lphttt?`. Executing `?` to obtain help.
Sometimes it falls down to the julian REPL with garbage, then back to debug:
julia> i_tsss
ERROR: UndefVarError: i_tsss not defined
1|debug>
Unknown command `lphfea`. Executing `?` to obtain help.
I can’t comment on the technicalities as I’m not familiar with the debugger (nor with the debugging process too much), but I guess we can conclude that:
a. it doesn’t seem to work well across spawned processes;
b. it’s not flexible enough - due to its performance penalty, there should be a global flag to disable all debugging. For instance, I’d be happy to use it in development but automatically disable it in production. A global flag like Revise has would be very useful, which would turn the call to @run
to doing nothing. This would allow having @run
in the codebase without the risk of breaking the app in production or having to chase down all the calls before release.
c. there’s an issue with returning nothing
from the debug session - this raises more exceptions if the calling function does not expect nothing
.
d. the interpreter is still too slow for randomly complex computations.
e. a @debug
helper to make code debuggable would be useful. For instance, in a module like this, which is a Controller
, the index()
function is automatically invoked by the framework:
module BooksController
using Debugger
Debugger.break_on(:error)
function index()
a()
b()
c()
end
# more code
To make it debuggable I need to do something like:
function index()
function debuggable_index()
a()
b()
c()
end
Debugger.@run debuggable_index()
end
I would be nice to just say @debug
and have the function modified for debugging:
@debug function index()
# code
end
Thanks, I hope it makes sense.