oracle / truffleruby

A high performance implementation of the Ruby programming language, built on GraalVM.
https://www.graalvm.org/ruby/
Other
3.03k stars 185 forks source link

Superfluous Object:: in module name #3683

Closed fxn closed 1 month ago

fxn commented 1 month ago

Hi! I am replacing TracePoint with Module#const_added in Zeitwerk, and noticed the new test suite does not pass on TruffleRuby (this work is still not released).

The root cause is this:

class Module
  def const_added(cname)
    puts const_get(cname).name
  end
end

module M
end

That prints "Object::M", instead of "M".

I suspect it is related to internal callback logic specifically, because M.name is "M" later.

Version is

% ruby -v
truffleruby 24.1.0, like ruby 3.2.4, Oracle GraalVM JVM [arm64-darwin20]

/cc @byroot

fxn commented 1 month ago

Hey! Just so that you know :), I just published Zeitwerk 2.7 with that change. Due to this issue, Zeitwerk 2.7 does not work with TruffleRuby right now.

eregon commented 1 month ago

Could you point me to something that breaks?

irb(main):001:0> module M;end
=> nil
irb(main):002:0> Object.const_get("Object::M")
=> M

works for example, so while this is still a bug in TruffleRuby, Object::M is a valid constant path to reference M.

eregon commented 1 month ago

I think it would be nice to workaround this in Zeitwerk if possible, so that the latest TruffleRuby release is not broken. If it's just a test failing no big deal but if it means Rails doesn't boot on TruffleRuby 24.1 due to this then it's a big deal.

byroot commented 1 month ago

"Object::M is a valid constant path to reference M." yeah, the problem is Zeitwerk keep the expected name in a Hash and need to look it up.

This can be worked around for sure, but it's a pretty hot loop, so should be done with care (or scoped under if RUBY_ENGINE == "truffleruby".

byroot commented 1 month ago

f it means Rails doesn't boot on TruffleRuby 24.1 due to this then it's a big deal.

People can just require "zeitwerk", "< 2.7" for now. So might not be worth shipping a workaround.

eregon commented 1 month ago

Could you point me to the code doing that? Maybe the key could be the module itself instead of strings?

People can just require "zeitwerk", "< 2.7" for now. So might not be worth shipping a workaround.

I suppose the error won't be clear so it's still a very poor user experience.

I just tried rails new railsapp --minimal, that uses zeitwerk (2.7.0) but both be rake test and bin/rails s seem to work fine.

byroot commented 1 month ago

Could you point me to the code doing that?

https://github.com/fxn/zeitwerk/blob/83277e0ff17728b07d99c1f8720332379b084456/lib/zeitwerk/core_ext/module.rb#L5

Maybe the key could be the module itself instead of strings?

No, the whole point is that this is registered before the module is loaded.

fxn commented 1 month ago

I just tried rails new railsapp --minimal, that uses zeitwerk (2.7.0) but both be rake test and bin/rails s seem to work fine.

Because the error only shows up with namespaces defined in files. Their child constants won't be found.

Maybe the key could be the module itself instead of strings?

There are projects where classes/modules are not hashable, learned that the hard way time ago.

eregon commented 1 month ago

No, the whole point is that this is registered before the module is loaded.

The constant already exists by the time const_added is called.

There are projects where classes/modules are not hashable, learned that the hard way time ago.

How is that possible? All Module instances have #hash via Kernel#hash. And if it's incorrectly overridden then one could use a {}.compare_by_identity Hash

fxn commented 1 month ago

How is that possible? All Module instances have #hash via Kernel#hash. And if it's incorrectly overridden then one could use a {}.compare_by_identity Hash

They had hash overridden to mean something else, and had a different signature (a debatable practice, yes).

In any case, this is a hot code path and the implementation was chosen among several options to be the most performant one. I'd need nested hashes to do this (because the key is a pair (mod, cname) conceptually).

I don't plan to revisit this implementation any time soon, unless I find something even more performant and backwards compatible.

fxn commented 1 month ago

@eregon, can you help me understand this thread?

TruffleRuby has a bug. I report it in advance. The reaction I would expect would be "thanks, we'll ship a fix as soon as possible". But I am feeling instead kind of a push back, and a proposal that consists on investigating in which way TruffleRuby is incompatible and that I release a new version to workaround the fact that TruffleRuby won't ship a new version. Or that I change an implementation that is correct.

Please don't get me wrong, I am asking this with sincerity.

Then, I see this as marked to be released in March 2025 (!).

Why?

eregon commented 1 month ago

First of all, thank you for reporting the bug, we forgot to say that. Normally @andrykonchin or I would take a look at new reported bugs and at least reply that but we missed this one.

@andrykonchin made a fix today in https://github.com/oracle/truffleruby/pull/3688 and I reviewed, it should be good to go. So at least the fix should be soon on master & dev builds.

https://github.com/oracle/truffleruby/issues/3683#issuecomment-2407011443 worried me because it sounds like you released a new Zeitwerk version without caring about this issue. It's fair enough since you filed this issue and TruffleRuby is not currently in Zeitwerk's CI (due to https://github.com/oracle/truffleruby/issues/2431 which I tried to fix but I got endless complications and CI failures due to the complexity of CRuby autoload semantics and never got to merge it, it's still an open PR, in hindsight it could have been nice to only skip that flaky test but keep running the other tests). And well of course this issue shouldn't block Zeitwerk to be released.

Then, I see this as marked to be released in March 2025 (!).

That is simply the next milestone & next TruffleRuby feature release (same schedule as GraalVM for releases). So it's unfortunately only 1 feature release every 6 months.

From https://www.graalvm.org/release-calendar/#graal-languages it's too late for 24.1.1 (last fix was Oct 1). We could and probably should backport this for 24.1.2 (January 21, 2025), but that's still in a while unfortunately.

I was asking these questions because indeed I was hoping for a quick workaround or fix in Zeitwerk, which could be released much sooner than TruffleRuby. Caching on the Module instead of its name feels intuitively better but of course you make good points that it would need nested hashes or [namespace, child] keys. Also I guess the name key might be needed because it persists over reloading, while the reloaded module could have a different identity.

fxn commented 1 month ago

https://github.com/oracle/truffleruby/issues/3683#issuecomment-2407011443 worried me because it sounds like you released a new Zeitwerk version without caring about this issue.

I cared, and I reported it in advance. But got no feedback. If you guys had been like, "oh, let us work on this one, can you hold releasing a bit?" I would have certainly be glad to do so.

But the ticket was silent and TruffleRuby is the project interested in this. The ticket is not "could you please fix this for Zeitwerk?". The ticket is, "you probably want to know about this (and BTW the next release of Zeitwerk won't fully work without this fixed, but that is up to you guys)".

On the other hand, Zeitwerk 2.7 has been in the oven for some time, and it is a project milestone. So I shipped. And I optimistically thought TruffleRuby would eventually address this one.

And well of course this issue shouldn't block Zeitwerk to be released.

Yes, that.

So it's unfortunately only 1 feature release every 6 months.

Wow, I did not know that.

That makes me think about Rails 8, I planned to make it depend on Zeitwerk 2.7.

eregon commented 1 month ago

I'll try to make a PR to Zeitwerk to see what a workaround looks like (should be pretty trivial, like a start_with?("Object::") check).

fxn commented 1 month ago

Thanks @eregon. I'll also look for spots in which I can leverage comparing by identity, maybe we can save computing a few permanent names.

eregon commented 1 month ago

https://github.com/fxn/zeitwerk/pull/303

fxn commented 1 month ago

I have also seen that

class Module
  def const_added(cname)
    p const_get(cname).name
  end
end

H = Class.new

prints nil in the stable release. Should print "H".

eregon commented 1 month ago

I think that's the same issue (will verify by adding a spec for that case), it's also because of the order in https://github.com/oracle/truffleruby/pull/3688/files#diff-c60ad35a6a0531d8ba253c54bce6ce93009fd357fee591615137609f1929c5ab where it used to be "set constant, call const_added, set full name" where the PR fixes it to "set full name, set constant, call const_added".

EDIT: const_added was implemented in https://github.com/oracle/truffleruby/pull/3099 I think it's worth taking a deeper look at it, I'm not sure calling it from inside the recursive getAdoptedByLexicalParent/updateAnonymousChildrenModules is correct.

fxn commented 1 month ago

"set constant, call const_added, set full name"

Interesting, why isn't the name nil instead of "Object::M" in the original example?

eregon commented 1 month ago

Because module M immediately gives a "basename" of "M" to that module as soon as the module is created. And then we computed the name (from Module#name inside const_added) before the full name is set as part of the assignment, and that logic normally used mostly for anonymous modules would then do https://github.com/oracle/truffleruby/blob/72fd3638619156f62219207b723ae348d9fc3038/src/main/java/org/truffleruby/core/module/ModuleFields.java#L795 https://github.com/oracle/truffleruby/pull/3688 fixes that case though should it happen before the full name is set.

eregon commented 1 month ago

Fixed in https://github.com/oracle/truffleruby/commit/495a0e5cc6911e01b021fc9aace1137c1492b496

eregon commented 1 month ago

For the record and to document this, this issue causes rails new to fail on TruffleRuby 24.1.0 & 24.1.1 with:

...
         run  bundle install --quiet
         run  bundle lock --add-platform=x86_64-linux
Writing lockfile to /home/eregon/tmp/blog/Gemfile.lock
         run  bundle binstubs bundler
       rails  importmap:install
bin/rails aborted!
NameError: uninitialized constant ActionCable::Server (NameError)
Did you mean?  TCPServer
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/actioncable-7.2.1.1/lib/action_cable.rb:78:in `const_missing'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/actioncable-7.2.1.1/lib/action_cable.rb:78:in `server'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/actioncable-7.2.1.1/lib/action_cable/engine.rb:67:in `block (3 levels) in <class:Engine>'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/actionpack-7.2.1.1/lib/action_dispatch/routing/route_set.rb:467:in `instance_exec'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/actionpack-7.2.1.1/lib/action_dispatch/routing/route_set.rb:467:in `eval_block'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/actionpack-7.2.1.1/lib/action_dispatch/routing/route_set.rb:484:in `block in clear!'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/actionpack-7.2.1.1/lib/action_dispatch/routing/route_set.rb:484:in `each'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/actionpack-7.2.1.1/lib/action_dispatch/routing/route_set.rb:484:in `clear!'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/application/routes_reloader.rb:45:in `block in clear!'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/application/routes_reloader.rb:43:in `each'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/application/routes_reloader.rb:43:in `clear!'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/application/routes_reloader.rb:23:in `reload!'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/application/routes_reloader.rb:38:in `block in updater'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/activesupport-7.2.1.1/lib/active_support/file_update_checker.rb:85:in `execute'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/application/routes_reloader.rb:13:in `execute'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/application/finisher.rb:162:in `block in <module:Finisher>'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/initializable.rb:32:in `instance_exec'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/initializable.rb:32:in `run'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/initializable.rb:61:in `block in run_initializers'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/initializable.rb:60:in `run_initializers'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/application.rb:435:in `initialize!'
/home/eregon/tmp/blog/config/environment.rb:5:in `<top (required)>'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/bootsnap-1.18.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/zeitwerk-2.7.1/lib/zeitwerk/core_ext/kernel.rb:34:in `require'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/application.rb:411:in `require_environment!'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/application.rb:559:in `block in run_tasks_blocks'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/task.rb:281:in `block in execute'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/task.rb:281:in `each'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/task.rb:281:in `execute'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/task.rb:219:in `block in invoke_with_call_chain'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/task.rb:199:in `invoke_with_call_chain'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/task.rb:243:in `block in invoke_prerequisites'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/task.rb:241:in `each'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/task.rb:241:in `invoke_prerequisites'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/task.rb:218:in `block in invoke_with_call_chain'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/task.rb:199:in `invoke_with_call_chain'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/task.rb:188:in `invoke'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/importmap-rails-2.0.3/lib/tasks/importmap_tasks.rake:6:in `block (2 levels) in <top (required)>'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/task.rb:281:in `block in execute'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/task.rb:281:in `each'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/task.rb:281:in `execute'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/task.rb:219:in `block in invoke_with_call_chain'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/task.rb:199:in `invoke_with_call_chain'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/task.rb:188:in `invoke'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/application.rb:188:in `invoke_task'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/application.rb:138:in `block (2 levels) in top_level'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/application.rb:138:in `each'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/application.rb:138:in `block in top_level'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/application.rb:147:in `run_with_threads'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/application.rb:132:in `top_level'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/commands/rake/rake_command.rb:27:in `block (2 levels) in perform'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/application.rb:214:in `standard_exception_handling'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/commands/rake/rake_command.rb:27:in `block in perform'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/commands/rake/rake_command.rb:44:in `block in with_rake'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/rake-13.2.1/lib/rake/rake_module.rb:59:in `with_application'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/commands/rake/rake_command.rb:41:in `with_rake'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/commands/rake/rake_command.rb:20:in `perform'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/command.rb:156:in `invoke_rake'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/command.rb:73:in `block in invoke'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/command.rb:149:in `with_argv'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/command.rb:69:in `invoke'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/railties-7.2.1.1/lib/rails/commands.rb:18:in `<top (required)>'
/home/eregon/tmp/blog/vendor/bundle/truffleruby/3.2.4.24.1.0.1/gems/bootsnap-1.18.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
Tasks: TOP => app:template => environment
(See full trace by running task with --trace)
       rails  turbo:install stimulus:install
You must either be running with node (package.json) or importmap-rails (config/importmap.rb) to use this gem.
You must either be running with node (package.json) or importmap-rails (config/importmap.rb) to use this gem.

The easiest solution is to use truffleruby-head and truffleruby 24.1.2+ when it is released (21 Jan 2025).

Using a zeitwerk < 2.7 also works as documented here, by modifying the Gemfile after rails new fails, adding gem "zeitwerk", "< 2.7" and then running rails new again and not overwriting the Gemfile.

One can also generate the application on CRuby and then run it on TruffleRuby.

bachos commented 1 month ago

Just for tracking sake, it seems that even with truffleruby 24.2.0 (dev), we are still facing some issues with bin/rails s after a successful rails new

I am getting an Internal Serve Error

NameError (uninitialized constant ActionCable::Server):

actioncable (8.0.0.rc1) lib/action_cable.rb:78:in `const_missing'
actioncable (8.0.0.rc1) lib/action_cable.rb:78:in `server'
actioncable (8.0.0.rc1) lib/action_cable/engine.rb:67:in `block (3 levels) in <class:Engine>'
actionpack (8.0.0.rc1) lib/action_dispatch/routing/route_set.rb:479:in `instance_exec'
actionpack (8.0.0.rc1) lib/action_dispatch/routing/route_set.rb:479:in `eval_block'
actionpack (8.0.0.rc1) lib/action_dispatch/routing/route_set.rb:496:in `block in clear!'
actionpack (8.0.0.rc1) lib/action_dispatch/routing/route_set.rb:496:in `each'
actionpack (8.0.0.rc1) lib/action_dispatch/routing/route_set.rb:496:in `clear!'
railties (8.0.0.rc1) lib/rails/application/routes_reloader.rb:55:in `block in clear!'
railties (8.0.0.rc1) lib/rails/application/routes_reloader.rb:53:in `each'
railties (8.0.0.rc1) lib/rails/application/routes_reloader.rb:53:in `clear!'
railties (8.0.0.rc1) lib/rails/application/routes_reloader.rb:25:in `reload!'
railties (8.0.0.rc1) lib/rails/application/routes_reloader.rb:48:in `block in updater'
activesupport (8.0.0.rc1) lib/active_support/file_update_checker.rb:85:in `execute'
railties (8.0.0.rc1) lib/rails/application/routes_reloader.rb:13:in `execute'
railties (8.0.0.rc1) lib/rails/application/routes_reloader.rb:35:in `execute_unless_loaded'
railties (8.0.0.rc1) lib/rails/application.rb:165:in `reload_routes_unless_loaded'
railties (8.0.0.rc1) lib/rails/engine/lazy_route_set.rb:67:in `call'
rack (3.1.8) lib/rack/tempfile_reaper.rb:20:in `call'
rack (3.1.8) lib/rack/etag.rb:29:in `call'
rack (3.1.8) lib/rack/conditional_get.rb:31:in `call'
rack (3.1.8) lib/rack/head.rb:15:in `call'
actionpack (8.0.0.rc1) lib/action_dispatch/http/permissions_policy.rb:38:in `call'
actionpack (8.0.0.rc1) lib/action_dispatch/http/content_security_policy.rb:35:in `call'
rack-session (2.0.0) lib/rack/session/abstract/id.rb:272:in `context'
rack-session (2.0.0) lib/rack/session/abstract/id.rb:266:in `call'
actionpack (8.0.0.rc1) lib/action_dispatch/middleware/cookies.rb:706:in `call'
activerecord (8.0.0.rc1) lib/active_record/migration.rb:671:in `call'
actionpack (8.0.0.rc1) lib/action_dispatch/middleware/callbacks.rb:31:in `block in call'
activesupport (8.0.0.rc1) lib/active_support/callbacks.rb:100:in `run_callbacks'
actionpack (8.0.0.rc1) lib/action_dispatch/middleware/callbacks.rb:30:in `call'
actionpack (8.0.0.rc1) lib/action_dispatch/middleware/executor.rb:16:in `call'
actionpack (8.0.0.rc1) lib/action_dispatch/middleware/actionable_exceptions.rb:18:in `call'
actionpack (8.0.0.rc1) lib/action_dispatch/middleware/debug_exceptions.rb:31:in `call'
web-console (4.2.1) lib/web_console/middleware.rb:132:in `call_app'
web-console (4.2.1) lib/web_console/middleware.rb:28:in `block in call'
<internal:core> core/throw_catch.rb:36:in `catch'
web-console (4.2.1) lib/web_console/middleware.rb:17:in `call'
actionpack (8.0.0.rc1) lib/action_dispatch/middleware/show_exceptions.rb:32:in `call'
railties (8.0.0.rc1) lib/rails/rack/logger.rb:41:in `call_app'
railties (8.0.0.rc1) lib/rails/rack/logger.rb:29:in `call'
actionpack (8.0.0.rc1) lib/action_dispatch/middleware/remote_ip.rb:96:in `call'
actionpack (8.0.0.rc1) lib/action_dispatch/middleware/request_id.rb:34:in `call'
rack (3.1.8) lib/rack/method_override.rb:28:in `call'
rack (3.1.8) lib/rack/runtime.rb:24:in `call'
actionpack (8.0.0.rc1) lib/action_dispatch/middleware/server_timing.rb:61:in `block in call'
actionpack (8.0.0.rc1) lib/action_dispatch/middleware/server_timing.rb:26:in `collect_events'
actionpack (8.0.0.rc1) lib/action_dispatch/middleware/server_timing.rb:60:in `call'
actionpack (8.0.0.rc1) lib/action_dispatch/middleware/executor.rb:16:in `call'
actionpack (8.0.0.rc1) lib/action_dispatch/middleware/static.rb:27:in `call'
rack (3.1.8) lib/rack/sendfile.rb:114:in `call'
actionpack (8.0.0.rc1) lib/action_dispatch/middleware/host_authorization.rb:143:in `call'
railties (8.0.0.rc1) lib/rails/engine.rb:535:in `call'
puma (6.4.3) lib/puma/configuration.rb:272:in `call'
puma (6.4.3) lib/puma/request.rb:100:in `block in handle_request'
puma (6.4.3) lib/puma/thread_pool.rb:378:in `with_force_shutdown'
puma (6.4.3) lib/puma/request.rb:99:in `handle_request'
puma (6.4.3) lib/puma/server.rb:464:in `process_client'
puma (6.4.3) lib/puma/server.rb:245:in `block in run'
puma (6.4.3) lib/puma/thread_pool.rb:155:in `block in spawn_thread'`
=> Booting Puma
=> Rails 8.0.0.rc1 application starting in development
=> Run `bin/rails server --help` for more startup options
Puma starting in single mode...
* Puma version: 6.4.3 (truffleruby 24.2.0-dev-5aa58980 - ruby 3.2.4) ("The Eagle of Durango")

The workaround gem "zeitwerk", "< 2.7" is still working

andrykonchin commented 1 month ago

Cannot reproduce the issue mentioned above with Rails 8.0.0.rc1 and rails s on a just generated application (checked Rails 7.2 as well).

Rails 8.0.0.rc1:

$ rails s
=> Booting Puma
=> Rails 8.0.0.rc1 application starting in development
=> Run `bin/rails server --help` for more startup options
Puma starting in single mode...
* Puma version: 6.4.3 (truffleruby 24.2.0-dev-44ded821 - ruby 3.2.4) ("The Eagle of Durango")
*  Min threads: 3
*  Max threads: 3
*  Environment: development
*          PID: 44411
* Listening on http://127.0.0.1:3000
* Listening on http://[::1]:3000
Use Ctrl-C to stop
^C- Gracefully stopping, waiting for requests to finish
=== puma shutdown: 2024-10-22 21:16:10 +0300 ===
- Goodbye!
Exiting

$ gem list | grep zei
zeitwerk (2.7.1)

Rails 7.2.1.1:

rails s
=> Booting Puma
=> Rails 7.2.1.1 application starting in development
=> Run `bin/rails server --help` for more startup options
Puma starting in single mode...
* Puma version: 6.4.3 (truffleruby 24.2.0-dev-44ded821 - ruby 3.2.4) ("The Eagle of Durango")
*  Min threads: 3
*  Max threads: 3
*  Environment: development
*          PID: 43165
* Listening on http://127.0.0.1:3000
* Listening on http://[::1]:3000
Use Ctrl-C to stop
^C- Gracefully stopping, waiting for requests to finish
=== puma shutdown: 2024-10-22 21:08:57 +0300 ===
- Goodbye!
Exiting

$ gem list | grep zei
zeitwerk (2.7.1)
bachos commented 1 month ago

Did you click http://127.0.0.1:3000?

The exception is thrown when you click to the above URL.

fxn commented 1 month ago

Seems related.

The test suite of Zeitwerk passes with truffleruby-head, could it be something that has drifted?

I have also added a workflow to run the test suite against TruffleRuby HEAD daily. I have a similar one for CRuby HEAD.

fxn commented 1 month ago

If you want a faster way to reproduce, this should suffice:

% ruby -raction_cable -e ActionCable::Server

should trigger the error. The key point is that ActionCable is an explicit namespace. If const_added is not doing its thing, child constants do not get autoloaded.

eregon commented 1 month ago

@bachos

  • Puma version: 6.4.3 (truffleruby 24.2.0-dev-5aa58980 - ruby 3.2.4) ("The Eagle of Durango")

That's 5aa58980 it's before the fix 495a0e5cc6911e01b021fc9aace1137c1492b496 so you need a newer version of truffleruby-dev than what you are using.

andrykonchin commented 1 month ago

Did you click http://127.0.0.1:3000/?

The exception is thrown when you click to the above URL.

Right, thank you for clarification.

If you want a faster way to reproduce, this should suffice:

% ruby -raction_cable -e ActionCable::Server

Thank you!

I've checked again (on https://github.com/oracle/truffleruby/commit/44ded821ff72de16675f320f599e1e97ef0b1786) and don't reproduce the issue:

$ bin/rails s
=> Booting Puma
=> Rails 8.0.0.rc1 application starting in development
=> Run `bin/rails server --help` for more startup options
Puma starting in single mode...
* Puma version: 6.4.3 (truffleruby 24.2.0-dev-44ded821 - ruby 3.2.4) ("The Eagle of Durango")
*  Min threads: 3
*  Max threads: 3
*  Environment: development
*          PID: 28074
* Listening on http://127.0.0.1:3000
* Listening on http://[::1]:3000
Use Ctrl-C to stop
Started GET "/" for 127.0.0.1 at 2024-10-23 12:44:19 +0300
   (2.4ms)  CREATE TABLE "schema_migrations" ("version" varchar NOT NULL PRIMARY KEY) /*application='KyivHawk'*/
   (2.0ms)  CREATE TABLE "ar_internal_metadata" ("key" varchar NOT NULL PRIMARY KEY, "value" varchar, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL) /*application='KyivHawk'*/
  ActiveRecord::SchemaMigration Load (2.0ms)  SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC /*application='KyivHawk'*/
Processing by Rails::WelcomeController#index as HTML
  Rendering /Users/andrykonchin/projects/truffleruby-ws/truffleruby/mxbuild/truffleruby-jvm/lib/gems/gems/railties-8.0.0.rc1/lib/rails/templates/rails/welcome/index.html.erb
  Rendered /Users/andrykonchin/projects/truffleruby-ws/truffleruby/mxbuild/truffleruby-jvm/lib/gems/gems/railties-8.0.0.rc1/lib/rails/templates/rails/welcome/index.html.erb (Duration: 12.3ms | GC: 0.0ms)
Completed 200 OK in 825ms (Views: 31.6ms | ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 12.0ms)

^C- Gracefully stopping, waiting for requests to finish
=== puma shutdown: 2024-10-23 12:44:27 +0300 ===
- Goodbye!
Exiting
$ ruby -vraction_cable -e ActionCable::Server
truffleruby 24.2.0-dev-44ded821, like ruby 3.2.4, Interpreted JVM [x86_64-darwin23]
-e:1: warning: possibly useless use of :: in void context
$ gem list | grep zeit
zeitwerk (2.7.1)

@bachos Is the issue reproducible in your environment on the TruffleRuby master?

bachos commented 1 month ago

I got 5aa58980 from rbenv ruby-build plugin (rbenv install truffleruby+graalvm-dev that is), would you mind updating that version to the latest ?

bachos commented 1 month ago

Looks like truffleruby-jvm-24.2.0-ea.18-linux-amd64.tar.gz was made available but it is based 0e05bfe. 😿

eregon commented 1 month ago

Could you try rbenv install truffleruby-dev? That's recent enough.

truffleruby+graalvm-dev is updated weekly (from https://github.com/graalvm/graal-languages-ea-builds/releases)

bachos commented 1 month ago

Could you try rbenv install truffleruby-dev?

It is working, thanks a lot.