问题描述
我随机崩溃(Rails将不再运行),记录如下:
I,[2020-09-14T21:50:30.398707 #9732] INFO -- : [e8eb6ebb-46eb-4d0e-93e2-e5d4fe6a8512] Completed 500 Internal Server Error in 10ms (ActiveRecord: 0.8ms)
F,[2020-09-14T21:50:30.406874 #9732] FATAL -- : [e8eb6ebb-46eb-4d0e-93e2-e5d4fe6a8512]
F,[2020-09-14T21:50:30.406988 #9732] FATAL -- : [e8eb6ebb-46eb-4d0e-93e2-e5d4fe6a8512] SystemStackerror (stack level too deep):
F,[2020-09-14T21:50:30.407014 #9732] FATAL -- : [e8eb6ebb-46eb-4d0e-93e2-e5d4fe6a8512]
F,[2020-09-14T21:50:30.407158 #9732] FATAL -- : [e8eb6ebb-46eb-4d0e-93e2-e5d4fe6a8512] actionpack (5.2.4.4) lib/action_dispatch/routing/mapper.rb:689:in `block (2 levels) in define_generate_prefix'
[e8eb6ebb-46eb-4d0e-93e2-e5d4fe6a8512] actionpack (5.2.4.4) lib/action_dispatch/routing/mapper.rb:689:in `block (2 levels) in define_generate_prefix'
<REPEATED AROUND 500 TIMES>
[e8eb6ebb-46eb-4d0e-93e2-e5d4fe6a8512] actionpack (5.2.4.4) lib/action_dispatch/routing/mapper.rb:689:in `block (2 levels) in define_generate_prefix'
这仅在升级到Rails 5之后才开始发生,并且在主内存较少的系统上更经常发生。调试起来非常困难,因为它是非常随机的,通常仅在应用程序运行约24小时后才会发生。
动作包中的溢出发生在这里: https://github.com/rails/rails/blob/404ad9e8acf8ab45ae2314050131a00e57e63b40/actionpack/lib/action_dispatch/routing/mapper.rb#L689
已经尝试了各种红宝石版本,目前使用的红宝石2.5.5p157和Nginx 1.17.3和Phusion Passenger 6.0.4。
有人看见过类似的东西吗?如果我可以随意复制它,则可以调试自己,但是由于随机性使它变得棘手。关于如何解决此类问题的任何想法?
更新: 这似乎与以下问题非常相似(似乎尚未得到答复):Stack level too deep (SystemStackError) actionpack
更新2 我现在看到任何已安装的Engine都会导致调用define_generate_prefix,例如,具有已安装的Engine的典型config / routes.rb:
Rails.application.routes.draw do
devise_for :admins
resources :admins
mount MyEngine::Engine,:at => "/",:as => "my_engine"
end
在mount方法中,将调用define_generate_prefix
,该调用又使用新的app.routes
方法扩展find_script_name
。在此处查看代码:https://github.com/rails/rails/blob/404ad9e8acf8ab45ae2314050131a00e57e63b40/actionpack/lib/action_dispatch/routing/mapper.rb#L687
最终结果是,每次super
调用时,一个mount
方法就会一遍又一遍地叠加到先前的方法上。最终,当find_script_name
调用url_for
时,系统出现堆栈溢出。这似乎是不可避免的
但是,我不能第一个看到这个,所以我确定我的理解有问题。但是呢?
解决方法
该问题的TL; DR答案是:
请勿在已安装的引擎内调用Rails.application.reload_routes!
。
更长的解释是,在安装了Rails Engine的情况下调用reload_routes!
会导致mount
中调用actionpack/lib/action_dispatch/routing/mapper.rb
方法,最终导致app.routes
被扩展( (find_script_name
)一遍又一遍,每次您致电reload_routes!
。在某个时候,您很有可能会使用url_for
帮助程序,这将依次在super
方法层中调用find_script_name
,您将获得一个stack too deep
错误。
这可能是Rails 5的错误,并且似乎在Rails 6中会重复出现,所以我看看是否应该在Github上提出问题。