I'm trying to debug a multithreaded ruby script, the problem is when I do
binding.pry
The other threads continue sending output to the console. How do I make them stop at binding.pry and then start up again when I exit? I'm thinking there's a way to do this in .pryrc
To exit everything, use: exit! This should ignore all proceeding bindings. This also kills the server at the same time.
The Ruby programmer can invoke the pry console during runtime by inserting the line 'binding. pry' wherever they would like to stop the program. When the interpreter hits the binding. pry, Pry will open a REPL session in the console, allowing you to test variables, return values, iterations, and more.
To fix this just move the binding. pry command one line to the top and try to run your file again. If it still doesn't catch it, move the binding. pry command one more line to the top and keep doing this until your file catches the binding.
It sounds like you are proposing using the invocation of binding.pry
to interrogate all child threads and suspend them until you end your pry session. That is not possible for technical and practical reasons. The Binding
and Thread
classes don't work that way, and multithreading in Ruby doesn't work that way.
Threads in Ruby can only be suspended by calling Kernel#sleep
or Thread.stop
. (and those are functionally equivalent) Crucially, these methods can only be invoked on the current thread. One thread cannot suspend another thread. (Thread.stop
is a class method, not an instance method)
Let's look at what binding.pry
actually does: objects of class Binding encapsulate the execution context at some particular place in the code and retain this context for future use. So when you put binding.pry
into your code, you're telling Ruby to encapsulate the execution context for the current thread.
What that means is when you call binding.pry
in the main thread the Binding object has context for the current thread and can tell itself to sleep, but the core Ruby Thread class does not allow it to tell any other threads to sleep.
Even if it did support it, it would be weird and error-prone and the cause of a lot of head-scratching. Imagine that you have code like this:
# we are in the main thread
Thread.new do
# we are in the child thread
foo = Foo.new(bar.fetch(:baz, {}))
foo.save
end
# we are in the main thread
binding.pry
Because of the way Ruby handles context-switching, if binding.pry
told all child threads to stop then the child thread might stop ANYWHERE in the call stack, including anywhere in the code for Foo.new
or .save
. Having those threads pause and resume in the middle of executing code that you did not write will cause you trouble. For example, what happens if an ActiveRecord connection from the pool is checked out and used for a SELECT
query but the thread got put to sleep before it returned the connection to the pool and before it got a response? Bad stuff. Lots of bad stuff.
It sounds like the real solution for you is to change the verbosity of the child threads. If you are troubleshooting chatty code and your other threads are being noisy while you're trying to work in a single thread, then set the other threads to use, for example, a lower logging level temporarily.
If binding.pry is yielding inconsistent results, try the following:
If it exists, remove pry-stack_explorer
from your gemfile and then
repackage your application. That gem appears to have issues with
pry-byebug
.
Additionally, not sure if you tried this already but a few server restarts couldn't hurt; this has resolved weird issues like this for me more often than I'd like to admit.
However, you may be trying to do something that simply cannot be done with binding.pry:
One fundamental about binding.pry
that must be understood is that its scope would include only the current thread, not every thread in a multi-threaded application as you have described.
Hypothetically, if binding.pry
did affect every thread (again, it does not), this would result in unpredictable behavior especially if some threads are performing data access/retrieval/update operations.
To accomplish what you want, you may need to take a different approach:
Although it may be tedious depending on how many threads are in your application, you may need to control/stop each thread individually. Obviously, this can be done with Thread.stop
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With