3.7.3 LocalJumpError during asset precompilation
brendonrapp opened this issue · 3 comments
Our Rails 7.0.8 app deploying to Heroku throws LocalJumpError
from the AppSignal gem version 3.7.3 during asset precompilation, coming from lib/hooks/active_job.rb
Reverting to 3.7.2 gets rid of the error.
Have not yet tried to narrow down to a minimum reproducible test case, but since 3.7.3 rolled out just today, figured it was worth it to sound an early warning.
Error trace from Heroku deployment:
remote: -----> Detecting rake tasks
remote: -----> Preparing app for Rails asset pipeline
remote: Running: rake assets:precompile
remote: rake aborted!
remote: LocalJumpError: unexpected return (LocalJumpError)
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/appsignal-3.7.3/lib/appsignal/hooks/active_job.rb:33:in `block in install'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/lazy_load_hooks.rb:95:in `class_eval'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/lazy_load_hooks.rb:95:in `block in execute_hook'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/lazy_load_hooks.rb:85:in `with_execution_control'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/lazy_load_hooks.rb:90:in `execute_hook'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/lazy_load_hooks.rb:76:in `block in run_load_hooks'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/lazy_load_hooks.rb:75:in `each'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/lazy_load_hooks.rb:75:in `run_load_hooks'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activejob-7.0.8/lib/active_job/base.rb:77:in `<class:Base>'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activejob-7.0.8/lib/active_job/base.rb:63:in `<module:ActiveJob>'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activejob-7.0.8/lib/active_job/base.rb:17:in `<main>'
remote: <internal:/tmp/build_5ec81295/vendor/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
remote: <internal:/tmp/build_5ec81295/vendor/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/bootsnap-1.17.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.12/lib/zeitwerk/kernel.rb:38:in `require'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/actionmailer-7.0.8/lib/action_mailer/mail_delivery_job.rb:11:in `<module:ActionMailer>'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/actionmailer-7.0.8/lib/action_mailer/mail_delivery_job.rb:5:in `<main>'
remote: <internal:/tmp/build_5ec81295/vendor/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
remote: <internal:/tmp/build_5ec81295/vendor/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/bootsnap-1.17.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.12/lib/zeitwerk/kernel.rb:38:in `require'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/actionmailer-7.0.8/lib/action_mailer/base.rb:489:in `<class:Base>'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/actionmailer-7.0.8/lib/action_mailer/base.rb:466:in `<module:ActionMailer>'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/actionmailer-7.0.8/lib/action_mailer/base.rb:12:in `<main>'
remote: <internal:/tmp/build_5ec81295/vendor/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
remote: <internal:/tmp/build_5ec81295/vendor/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/bootsnap-1.17.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.12/lib/zeitwerk/kernel.rb:38:in `require'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/inflector/methods.rb:278:in `const_get'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/inflector/methods.rb:278:in `constantize'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/core_ext/string/inflections.rb:74:in `constantize'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/devise-4.9.3/app/mailers/devise/mailer.rb:4:in `<main>'
remote: <internal:/tmp/build_5ec81295/vendor/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
remote: <internal:/tmp/build_5ec81295/vendor/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/bootsnap-1.17.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.12/lib/zeitwerk/kernel.rb:30:in `require'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/inflector/methods.rb:278:in `const_get'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/inflector/methods.rb:278:in `constantize'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/core_ext/string/inflections.rb:74:in `constantize'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/devise-4.9.3/lib/devise.rb:327:in `get'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/devise-4.9.3/lib/devise.rb:350:in `mailer'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/devise_invitable-2.0.9/lib/devise_invitable/rails.rb:12:in `block in <class:Engine>'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/callbacks.rb:445:in `instance_exec'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/callbacks.rb:445:in `block in make_lambda'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/callbacks.rb:199:in `block (2 levels) in halting'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/callbacks.rb:687:in `block (2 levels) in default_terminator'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/callbacks.rb:686:in `catch'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/callbacks.rb:686:in `block in default_terminator'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/callbacks.rb:200:in `block in halting'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/callbacks.rb:595:in `block in invoke_before'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/callbacks.rb:595:in `each'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/callbacks.rb:595:in `invoke_before'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/callbacks.rb:106:in `run_callbacks'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.8/lib/active_support/reloader.rb:88:in `prepare!'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/railties-7.0.8/lib/rails/application/finisher.rb:68:in `block in <module:Finisher>'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/railties-7.0.8/lib/rails/initializable.rb:32:in `instance_exec'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/railties-7.0.8/lib/rails/initializable.rb:32:in `run'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/railties-7.0.8/lib/rails/initializable.rb:61:in `block in run_initializers'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/railties-7.0.8/lib/rails/initializable.rb:60:in `run_initializers'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/railties-7.0.8/lib/rails/application.rb:372:in `initialize!'
remote: /tmp/build_5ec81295/config/environment.rb:5:in `<main>'
remote: <internal:/tmp/build_5ec81295/vendor/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
remote: <internal:/tmp/build_5ec81295/vendor/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/bootsnap-1.17.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.12/lib/zeitwerk/kernel.rb:38:in `require'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/railties-7.0.8/lib/rails/application.rb:348:in `require_environment!'
remote: /tmp/build_5ec81295/vendor/bundle/ruby/3.2.0/gems/railties-7.0.8/lib/rails/application.rb:506:in `block in run_tasks_blocks'
remote: Tasks: TOP => assets:precompile => environment
remote: (See full trace by running task with --trace)
remote: [2024-05-08T22:44:29 (process) #5574][INFO] appsignal: Starting AppSignal 3.7.3 (/tmp/build_5ec81295/bin/rake, Ruby 3.2.2, x86_64-linux)
remote: [2024-05-08T22:44:29 (process) #5574][INFO] appsignal: Starting AppSignal 3.7.3 (/tmp/build_5ec81295/bin/rake, Ruby 3.2.2, x86_64-linux)
remote:
remote: !
remote: ! Precompiling assets failed.
remote: !
remote: ! Push rejected, failed to compile Ruby app.
remote:
remote: ! Push failed
Hi @brendonrapp, thanks for the report! Interesting to see that's not happening in our test suite but it is in your app. I've made a quick fix in #1079.
Thanks for reporting this issue @brendonrapp!
We've just released AppSignal for Ruby 3.7.4, which contains @tombruijn's fix in #1079.
Did some research into why this happened in real apps and not in our test suite. See this test app in this gist for reference.
When the ActiveJob::Base
class (the MyLib
class in the example) is already loaded before the ActiveSupport.on_load(:my_lib) do
callback gets registered, it will immediately run the on_load
hook. The callback block will be run inside the context of the parent method that defines it: the return
bubbles up to the Appsignal::Hooks::ActiveJobHook#install
method and early exit from there.
If the ActiveJob (MyLib) constant isn't defined yet, and it gets loaded later (with require_relative
or Rails's auto load module and/or zeitwerk), the on_load
callback is excuted in another context, namely zeitwerk's Kernel.require
monkeypatch. I think this acts like requiring a file (like require_relative
in the example gist), and that context is not a valid context in which to call return, resulting in that LocalJumpError
.
Previous revisions of that gist also has a zeitwerk version of the example, which is more closely what happens in Rails. It has the same behavior as the require_relative
code base.
The problem is, in our test suite ActiveJob::Base
constant is already loaded. When the return
is called it only exits from the install
method in our gem. But when it's called in a real app, it's going through the require
, because ActiveJob::Base isn't loaded yet, which results in the LocalJumpError
.