问题
I get random crashes (Rails will no longer run), log as follows:
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'
This only started occurring after upgrading to Rails 5 and occurs more often on systems with less main memory. It's hard to debug because it is very random, occurring usually only after the app has been running for about 24 hours.
The overflow happens in actionpack here: https://github.com/rails/rails/blob/404ad9e8acf8ab45ae2314050131a00e57e63b40/actionpack/lib/action_dispatch/routing/mapper.rb#L689
Have tried various ruby versions, currently using ruby 2.5.5p157 with nginx 1.17.3 and Phusion Passenger 6.0.4.
Has anybody seen anything similar? If I could replicate it at will I could possibly debug myself, but being the random nature makes it tricky. Any ideas on how to even approach such a problem?
Update: This seem very similar to this issue (which seems to have not been answered): Stack level too deep (SystemStackError) actionpack
Update 2 I now see that any mounted Engine causes the call to define_generate_prefix, for example a typical config/routes.rb with mounted Engine:
Rails.application.routes.draw do
devise_for :admins
resources :admins
mount MyEngine::Engine, :at => "/", :as => "my_engine"
end
In the mount method there will be a call to define_generate_prefix
which in turn extends app.routes
with an new find_script_name
method. See code here: https://github.com/rails/rails/blob/404ad9e8acf8ab45ae2314050131a00e57e63b40/actionpack/lib/action_dispatch/routing/mapper.rb#L687
The end effect is that one super
method is layered onto the previous over and over with each mount
call. Eventually the system has a stack overflow when find_script_name
is called by url_for
. This seems inevitable
However, I can't be the first one to see this, so I'm sure there is something wrong with my understanding. But what?
回答1:
The TL;DR answer to the problem turned out to be:
Do not call Rails.application.reload_routes!
inside a mounted Engine.
The longer explanation is that calling reload_routes!
when you have a mounted Rails Engine leads to the mount
method being called in actionpack/lib/action_dispatch/routing/mapper.rb
which eventually leads to app.routes
being extended (find_script_name
) over and over, for every time you call reload_routes!
. The at some point you are highly likely to use the url_for
helper and this in turn is going to call super
inside your layers of find_script_name
methods and you will get a stack too deep
error.
This is possibly a Rails 5 bug and seems to be repeated in Rails 6, so I'll see if I should raise an issue on Github.
来源:https://stackoverflow.com/questions/63892568/stack-level-too-deep-rails-5-in-define-generate-prefix