Ruby 2.7+ NoMethodError默认调用inspect打印全属性导致服务卡顿问题咨询
问题定性
这是Ruby 2.7及更高版本的设计特性,并非版本缺陷。
该特性是Ruby核心开发团队为了提升调试效率新增的:当NoMethodError抛出时,默认会在报错信息中打印目标对象的全部实例变量详情,底层实现确实调用了对象的inspect方法生成相关内容,对于属性多、嵌套深或携带二进制数据的对象,就会出现你遇到的耗时过长、甚至服务卡住的问题。
可行解决方案
全局关闭NoMethodError详情输出
Ruby官方提供了直接的开关配置,你可以根据场景二选一:- 在应用启动入口/初始化代码中添加如下代码:
NoMethodError.prepend_message = false如果是Rails项目,将该行代码放入
config/initializers下任意.rb文件即可全局生效。
2. 启动程序时指定环境变量:RUBY_NO_METHOD_ERROR_PREPEND_MESSAGE=false rails s两种方式都可以让
NoMethodError的输出格式回到Ruby 2.6的样式,只打印对象类名和内存地址,不输出实例变量。针对特定类自定义
inspect方法
如果你不想全局关闭该调试特性,只想处理puppeteer-ruby这类特殊类的报错输出问题,可以为对应类重写inspect方法,只返回必要的精简信息:# 放在puppeteer初始化之后执行即可 class Puppeteer::Browser def inspect "#<Puppeteer::Browser:0x#{object_id.to_s(16)} @headless=#{@headless}>" end end # 其他puppeteer相关的类也可以按同样逻辑自定义inspect重写后就算触发报错,也只会输出你定义的短内容,不会遍历全部属性。
特定代码块捕获处理
对于极个别高频触发未定义方法的代码块,可以主动捕获NoMethodError,输出自定义报错信息避免执行默认的inspect逻辑:begin browser.foo rescue NoMethodError => e puts "NoMethodError: undefined method `#{e.name}' for #{e.receiver.class}:#{e.receiver.object_id}" # 其他自定义处理逻辑 end
内容的提问来源于stack exchange,提问作者The Lazy Log
相关产品推荐
相关产品推荐

