Skip to content

On irb:rdbg: IRB commands run in a different thread than the debugged program #1158

@jvlara

Description

@jvlara

Your environment

  • ruby -v: 3.3.7
  • rdbg -v: 1.11.0
  • IRB integration: enabled

Describe the bug
When using debug with IRB integration (RUBY_DEBUG_IRB_CONSOLE=true), commands from IRB entered in the irb:rdbg console are evaluated on a different thread from the currently debugged program thread.

This causes problems when commands depend on thread-local data (Thread.current[:foo]), ActiveRecord::Base.connection (which may be bound per-thread), or other thread-local behaviors, like Apartment gem in our case.

To Reproduce
For example, having this on

# .irbrc
command = Class.new(IRB::Command::Base) do
  category "Helpers"
  description "Testing thread behaviour"
  help_message "Testing thread behaviour"
  define_method(:execute) do |arg|
    puts "Modifying thread variables on: #{Thread.current.object_id}"
    Thread.current[:testing_variable] = arg
  end
end

IRB::Command.register "st", command

with this script

require 'debug'
require 'irb'

debugger;
x=1

Run
RUBY_DEBUG_IRB_CONSOLE=1 bundle exec ruby script.rb

Image

As you can see in the image, the thread variable :testing_variable got modified on another thread different from the current session (1140 instead of 1120)

Expected behavior
When inside an interactive irb:rdbg session, commands should execute on the same thread and binding as the current debug frame (or at least provide a way to opt into that).

Additional context
This happened to us in a helper moving from binding.pry to debugger, the helper uses Apartment::Tenant.switch! from apartment gem which uses Thread variables to know in which tenant is currenly on

Because of this bug, the helper stop working and our state of the current_tenant on the debugger session gets corrupted, inside the db the schema_search_path is right but on the debugger the switch did not happen...

Questions
I’m not fully clear on how debug and IRB interact. I tried to trace where command execution is split so I could make an IRB command run in the debugger’s context, but I couldn’t figure it out. Could you briefly explain the execution flow?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions