ruby / debug

Debugging functionality for Ruby
BSD 2-Clause "Simplified" License
1.12k stars 126 forks source link

debugger and binding.b are blocking in rspec, and not binding.pry for instance #404

Open dorianmariecom opened 2 years ago

dorianmariecom commented 2 years ago

Your environment

Describe the bug

When I do debugger or binding.b in my tests it blocks the background requests

To Reproduce

For instance:

require "rails_helper"

RSpec.describe "Approvals" do
  let!(:user) { create(:user) }
  let!(:approved_user) { create(:user) }

  before { create(:event, :approved, user: approved_user) }

  it "can approve events" do
    system_login_as(user)
    binding.b
  end
end

Expected behavior

Requests are not blocked, like what binding.pry does

Additional context

I'm using the preload, maybe that's related

dorianmariecom commented 2 years ago

Also happens without the preload

st0012 commented 2 years ago

@dorianmariefr can you provide an example app? I also use debugger with rspec for my Rails project, and the request specs can run without any issue (whether the breakpoint is set in the spec file or the application).

dorianmariecom commented 2 years ago

You can try in https://github.com/dorianmariefr/parlement and put a debugger before the register here https://github.com/dorianmariefr/parlement/blob/master/spec/system/main_spec.rb#L11

and then click on "register" and notice nothing happens

st0012 commented 2 years ago

@dorianmariefr the app takes multiple env var to run, e.g. SECRET_KEY_BASE and BASE_URL (needed for capybara). it also requires postgresql to start. can you either make it easier to setup, or create a simpler application/script for reproducing the issue? thanks.

st0012 commented 2 years ago

btw, I think the cause may be related to the forking mechanism as well, similar to https://github.com/ruby/debug/issues/336. can you try putting this in rails_helper and see if it fixes the issue? (as a temporary workaround)

ENV["RUBY_DEBUG_FORK_MODE"] ||= "parent"
dorianmariecom commented 2 years ago

You can put this in a .env.test:

HOST=localhost:4312
BASE_URL=http://localhost:4312

And I get the blocking behavior with and without the ENV

(rdbg) ENV["RUBY_DEBUG_FORK_MODE"]    # ruby
"parent"
st0012 commented 2 years ago

@dorianmariefr I'm now able to reproduce the behavior locally. But I think this may be an intentional behavior.

When breakpoint is activated, the debugger will enter a subsession:

https://github.com/ruby/debug/blob/bd6947b7aa14c7c0d5ae97b62fe53af1b5738659/lib/debug/session.rb#L231-L232

And then it'll stop all threads under the process with thread stopper

https://github.com/ruby/debug/blob/bd6947b7aa14c7c0d5ae97b62fe53af1b5738659/lib/debug/session.rb#L1500

https://github.com/ruby/debug/blob/bd6947b7aa14c7c0d5ae97b62fe53af1b5738659/lib/debug/session.rb#L1468-L1478

This includes all the threads

--> #0 (sleep)@/Users/st0012/projects/parlement/spec/system/main_spec.rb:14:in `block (2 levels) in <top (required)>'
    #1 (sleep)@#<Thread:0x00007fbee3127448 /Users/st0012/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/bundler/gems/rails-6f2c4027e820/activerecord/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb:40 sleep> (not under control)
    #2 (sleep)@#<Thread:0x00007fbf12abf210 /Users/st0012/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/capybara-3.36.0/lib/capybara/server.rb:76 sleep_forever> (not under control)
    #3 (puma reactor)@/Users/st0012/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/puma-5.5.2/lib/puma/reactor.rb:75:in `block in select_loop'
    #4 (puma server threadpool reaper)@/Users/st0012/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/puma-5.5.2/lib/puma/thread_pool.rb:310:in `block in start!'
    #5 (puma server threadpool trimmer)@#<Thread:0x00007fbef5e0af68@puma server threadpool trimmer /Users/st0012/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/puma-5.5.2/lib/puma/thread_pool.rb:307 sleep> (not under control)
    #6 (puma server)@#<Thread:0x00007fbef5e0ad38@puma server /Users/st0012/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/puma-5.5.2/lib/puma/server.rb:259 sleep> (not under control)
    #7 (puma server threadpool 001)@#<Thread:0x00007fbee38d2a58@puma server threadpool 001 /Users/st0012/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/puma-5.5.2/lib/puma/thread_pool.rb:104 sleep_forever> (not under control)
    #8 (puma server threadpool 002)@/Users/st0012/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/concurrent-ruby-1.1.9/lib/concurrent-ruby/concurrent/map.rb:123:in `initialize'
    #9 (worker-1)@#<Thread:0x00007fbf02918390@worker-1 /Users/st0012/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/concurrent-ruby-1.1.9/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:332 sleep> (not under control)

(Thread 7 and 8, puma server threadpool 001 and 002, are the ones that serve requests).

So when you try to make another request from the browser, there will be no threads to serve them.

But I don't know why it's designed this way and need @ko1 to add a comment here.

dorianmariecom commented 2 years ago

thanks for looking into it, it prevents me from debugging my system specs with debug

On Sat, Dec 04, 2021 at 21:36:49, Stan Lo < @.*** > wrote:

@ dorianmariefr ( https://github.com/dorianmariefr ) I'm now able to reproduce the behavior locally. But I think this may be an intentional behavior.

When breakpoint is activated, the debugger will enter a subsession:

https:/ / github. com/ ruby/ debug/ blob/ bd6947b7aa14c7c0d5ae97b62fe53af1b5738659/ lib/ debug/ session. rb#L231-L232 ( https://github.com/ruby/debug/blob/bd6947b7aa14c7c0d5ae97b62fe53af1b5738659/lib/debug/session.rb#L231-L232 )

And then it'll stop all threads under the process with thread stopper

https:/ / github. com/ ruby/ debug/ blob/ bd6947b7aa14c7c0d5ae97b62fe53af1b5738659/ lib/ debug/ session. rb#L1500 ( https://github.com/ruby/debug/blob/bd6947b7aa14c7c0d5ae97b62fe53af1b5738659/lib/debug/session.rb#L1500 )

https:/ / github. com/ ruby/ debug/ blob/ bd6947b7aa14c7c0d5ae97b62fe53af1b5738659/ lib/ debug/ session. rb#L1468-L1478 ( https://github.com/ruby/debug/blob/bd6947b7aa14c7c0d5ae97b62fe53af1b5738659/lib/debug/session.rb#L1468-L1478 )

This includes all the threads

--> #0 (sleep)@/Users/st0012/projects/parlement/spec/system/main_spec.rb:14:in `block (2 levels) in <top (required)>'

1

(sleep)@#<Thread:0x00007fbee3127448 /Users/st0012/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/bundler/gems/rails-6f2c4027e820/activerecord/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb:40 sleep> (not under control)

2 (sleep)@#<Thread:0x00007fbf12abf210

/Users/st0012/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/capybara-3.36.0/lib/capybara/server.rb:76 sleep_forever> (not under control)

3 (puma

reactor)@/Users/st0012/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/puma-5.5.2/lib/puma/reactor.rb:75:in `block in select_loop'

4 (puma server threadpool

reaper)@/Users/st0012/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/puma-5.5.2/lib/puma/thread_pool.rb:310:in `block in start!'

5 (puma server threadpool

trimmer)@@.*** server threadpool trimmer /Users/st0012/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/puma-5.5.2/lib/puma/thread_pool.rb:307 sleep> (not under control)

6 (puma

server)@@.*** server /Users/st0012/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/puma-5.5.2/lib/puma/server.rb:259 sleep> (not under control)

7 (puma server threadpool

001)@@.*** server threadpool 001 /Users/st0012/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/puma-5.5.2/lib/puma/thread_pool.rb:104 sleep_forever> (not under control)

8 (puma server threadpool

002)@/Users/st0012/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/concurrent-ruby-1.1.9/lib/concurrent-ruby/concurrent/map.rb:123:in `initialize'

9 (worker-1)@@.***

/Users/st0012/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/concurrent-ruby-1.1.9/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:332 sleep> (not under control)

(Thread 7 and 8, puma server threadpool 001 and 002 , are the ones that serve requests).

So when you try to make another request from the browser, there will be no threads to serve them.

But I don't know why it's designed this way and need @ ko1 ( https://github.com/ko1 ) to add a comment here.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub ( https://github.com/ruby/debug/issues/404#issuecomment-986089190 ) , or unsubscribe ( https://github.com/notifications/unsubscribe-auth/AOASD56VY6T64QAYXECHI6LUPJ3WDANCNFSM5IPICIWQ ).

ko1 commented 2 years ago

Without stopping all threads, we can not observe the status of the program. Do you want to start all threads except the current thread?

dorianmariecom commented 2 years ago

I guess it could stop only the current thread?

On Fri, Dec 17, 2021 at 18:13:06, Koichi Sasada < @.*** > wrote:

Without stopping all threads, we can not observe the status of the program. Do you want to start all threads except the current thread?

— Reply to this email directly, view it on GitHub ( https://github.com/ruby/debug/issues/404#issuecomment-996885190 ) , or unsubscribe ( https://github.com/notifications/unsubscribe-auth/AOASD55EAUJE2MTXBUZ6ZHDURNVSFANCNFSM5IPICIWQ ). Triage notifications on the go with GitHub Mobile for iOS ( https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 ) or Android ( https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub ). You are receiving this because you were mentioned. Message ID: <ruby/debug/issues/404/996885190 @ github. com>

ko1 commented 2 years ago

in theory, yes. we don't provide this feature yet.

st0012 commented 2 years ago

How about we introduce a setting like: RUBY_DEBUG_CONCURRENCY_CONTROL_LEVEL with these levels:

dorianmariecom commented 2 years ago

Good idea, maybe Debug.concurrency = :thread in Ruby ?

st0012 commented 2 years ago

Consider the current interface we have, may be

DEBUGGER__::CONFIG[:concurrency_control_level] = :thread
ko1 commented 2 years ago

Please survey other debuggers. It is not simple.

beauraF commented 8 months ago

Hello! I'd like to reopen this conversation. We'd like to migrate our codebase from pry-byebug to debug, but this issue is the last thing holding us back.

Putting a breakpoint in a system test, in order to stop at a specific step, but still be able to play with our SPA (only the capybara thread being blocked), is an important part of our workflow. Unfortunately, it's currently impossible with debug.

Maybe also worth to mention others cases where it could be interesting, like https://github.com/Shopify/ruby-lsp-rails/issues/29.

@ko1 do you think that the proposal of @st0012 , could be concidered?

dorianmariecom commented 8 months ago

@beauraF you can use binding.irb instead, and it's shipped by default, no need for an extra gem.

You can have an alias from binding.pry to binding.irb for those used to pry