Ale*_*nov 3 ruby multithreading rspec ruby-on-rails
运行下面列出的规范时出错。它不会等待线程完成并取消存根迁移方法,从而导致其中一个线程命中真正的方法。
注意到它只发生在加载导轨的情况下,没有它们它可以正常工作或者只是更快地完成......
规格:
it "should not allow infinit recursion" do
runner.stub(total_records: 4)
runner.stub(:fetch_records_batch).and_return([:one, :two])
runner.should_receive(:migrate).at_most(100).times
expect { runner.run }.to raise_error(Exception, /Migration fall into recursion/)
end
it "should pass"
1.should eq 1
end
Run Code Online (Sandbox Code Playgroud)
提取的一段代码:
class Runner
def migrate(record)
raise NotImplementedError
end
def run
while have_records?(records = fetch_records_batch)
threads = []
records.each do |record|
threads << Thread.new(record) do |thread_record|
begin
result = migrate(thread_record)
rescue RuntimeError => exception
register_event :record_migration_error, thread_record, exception
end
end
recursion_preventer
end
threads.each(&:join)
end
end
def recursion_preventer
@counter ||= 0
@counter += 1
raise Exception, "Migration fall into recursion. Check logs." if @counter > (total_records * 1.1).round + 10
end
end
Run Code Online (Sandbox Code Playgroud)
您始终可以模拟 Thread 类以简单地不启动线程,而是运行代码,我发现这比按照您建议的方式重写测试的侵入性要小得多。
将其添加到您的测试类中:
describe MyClass do
before(:each) do
allow(Thread).to receive(:new).and_yield
end
#Your normal unaltered tests under here
end
Run Code Online (Sandbox Code Playgroud)
此方法的陷阱是您不会遇到竞争条件,因此代码仍然可能包含诸如“线程 a 和线程 b 同时写入同一变量,导致问题”之类的错误。您还应该考虑死锁场景,因为依赖其他线程来完成某些操作的代码很可能会用这种方法锁定。
| 归档时间: |
|
| 查看次数: |
2912 次 |
| 最近记录: |