[ruby/rubygems] Make the Bundler logger thread safe:

- The Logger is not thread safe when calling `with_level`.
  This now becomes problematic because we are using multiple
  threads during the resolution phase in order to fetch git gems.

https://github.com/ruby/rubygems/commit/380653ae74
This commit is contained in:
Edouard CHIN 2025-11-19 23:15:41 +01:00 committed by git
parent bd60600d00
commit 409c004aff
2 changed files with 38 additions and 6 deletions

View File

@ -17,6 +17,7 @@ module Bundler
@level = ENV["DEBUG"] ? "debug" : "info"
@warning_history = []
@output_stream = :stdout
@thread_safe_logger_key = "logger_level_#{object_id}"
end
def add_color(string, *color)
@ -97,11 +98,13 @@ module Bundler
end
def level(name = nil)
return @level unless name
current_level = Thread.current.thread_variable_get(@thread_safe_logger_key) || @level
return current_level unless name
unless index = LEVELS.index(name)
raise "#{name.inspect} is not a valid level"
end
index <= LEVELS.index(@level)
index <= LEVELS.index(current_level)
end
def output_stream=(symbol)
@ -167,12 +170,13 @@ module Bundler
end * "\n"
end
def with_level(level)
original = @level
@level = level
def with_level(desired_level)
old_level = level
Thread.current.thread_variable_set(@thread_safe_logger_key, desired_level)
yield
ensure
@level = original
Thread.current.thread_variable_set(@thread_safe_logger_key, old_level)
end
def with_output_stream(symbol)

View File

@ -81,4 +81,32 @@ RSpec.describe Bundler::UI::Shell do
end
end
end
describe "threads" do
it "is thread safe when using with_level" do
stop_thr1 = false
stop_thr2 = false
expect(subject.level).to eq("debug")
thr1 = Thread.new do
subject.silence do
sleep(0.1) until stop_thr1
end
stop_thr2 = true
end
thr2 = Thread.new do
subject.silence do
stop_thr1 = true
sleep(0.1) until stop_thr2
end
end
[thr1, thr2].each(&:join)
expect(subject.level).to eq("debug")
end
end
end